Общая функция в списке производного класса
Вопрос
Я чувствую, что мой вопрос довольно тупой, или можно сформулировать по-другому: я слишком потерян в своем коде, чтобы увидеть обходной путь. Оставайтесь слишком долго над проблемой, и ваше зрение сужается и сужается & 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, которые ничего не значат в вашем коде.