Общая функция в списке производного класса

StackOverflow https://stackoverflow.com/questions/1635662

  •  06-07-2019
  •  | 
  •  

Вопрос

Я чувствую, что мой вопрос довольно тупой, или можно сформулировать по-другому: я слишком потерян в своем коде, чтобы увидеть обходной путь. Оставайтесь слишком долго над проблемой, и ваше зрение сужается и сужается & Gt; & Lt ;. Плюс я не достаточно хорош с наследованием, полиморфизмом и т. Д.

Вот идея: у меня есть несколько списков производных классов, и я хотел бы вызывать универсальные функции в этих списках (доступ и изменение членов базового класса). Я чувствую, что что-то связано с наследованием, но мне пока не удается заставить его работать так, как я хочу.

Вот очень простой пример того, что я собираюсь сделать:

class Baseclass
{
    public int ID;
    public string Name;
}
class DerivedClass1 : Baseclass
{
}

private void FuncOnBase(List<Baseclass> _collection)
{
    // ...

    foreach (Baseclass obj in _collection)
    {
        ++obj.ID;
    }

    // ...
}
private void FuncTest()
{
    List<DerivedClass1> collection1 = new List<DerivedClass1>();
    collection1.Add(new DerivedClass1() { ID = 1 });
    collection1.Add(new DerivedClass1() { ID = 2 });
    collection1.Add(new DerivedClass1() { ID = 3 });

    FuncOnBase(collection1);   //  ==> forbidden, cannot convert the derived class list to the base class list
}
Это было полезно?

Решение

Должен любить дисперсию. List<DerivedClass1> не a List<Baseclass> - иначе FuncOnBase может попытаться добавить Baseclass в список, и компилятор не обнаружит его.

Одна хитрость заключается в использовании универсального метода:

private void FuncOnBase<T>(List<T> _collection) where T : Baseclass
{
    // ...

    foreach (T obj in _collection)
    {
        obj.ID++;
    }

    // ...
}

В приведенном выше примере - обратите внимание, что мы можем добавить T в список; особенно полезно, если мы добавляем ограничение T : new() или передаем (например) a params T[].

Также обратите внимание, что IEnumerable<T> становится ковариантным в C # 4.0 / .NET 4.0, поэтому, если вы передадите просто IEnumerable<Baseclass> (а не список), это сработает " как есть "

private void FuncOnBase(IEnumerable<Baseclass> _collection)
{
   ///...
}

Другие советы

Если вы делаете только foreach, объявите FuncOnBase(IEnumerable<Baseclass> collection), который можно вызвать из FuncTest следующим образом:

FuncOnBase(collection1.Cast<Baseclass>());

Когда вы объявляете метод с параметром List<T>, но используете только его функции IEnumerable<T>, вы добавляете ограничения API, которые ничего не значат в вашем коде.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top