Список кастов из класса Derived в список базового classа
У меня есть два classа: базовый class (Animal) и class, полученный из него (Cat). Базовый class содержит один виртуальный метод Play, который принимает List как входной параметр. Что-то вроде этого
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication9 { class Animal { public virtual void Play(List animal) { } } class Cat : Animal { public override void Play(List animal) { } } class Program { static void Main(string[] args) { Cat cat = new Cat(); cat.Play(new List()); } } }
Когда я скомпилирую вышеуказанную программу, я получаю следующую ошибку
Ошибка 2 Аргумент 1: невозможно преобразовать из 'System.Collections.Generic.List' в 'System.Collections.Generic.List'
Нужно ли это сделать?
- Почему этот общий код компилируется в java 8?
- Collections.emptyList () возвращает List ?
- java generics ковариация
- Псевдо-дженерики в C
- Можно ли решить «Генерируемый массив T создан для параметра varargs», предупреждающий о компиляторе?
- Generics: List совпадает с List ?
- C # использовать System.Type как общий параметр
- Список OrderBy Алфавитный порядок
- Почему C # запрещает общие типы атрибутов?
- C # - Несколько общих типов в одном списке
- Generics и casting - не могут передавать унаследованный class в базовый class
- Использование ключевого слова «params» для общих параметров в C #
- Что такое SuppressWarnings («unchecked») в Java?
Причина, по которой вы не можете сделать это, состоит в том, что список доступен для записи. Предположим, что это было законно, и посмотрите, что пойдет не так:
List cats = new List (); List animals = cats; // Trouble brewing... animals.Add(new Dog()); // hey, we just added a dog to a list of cats... cats[0].Speak(); // Woof!
Ну собака мои кошки, это нехорошо.
Функция, которую вы хотите, называется «общей ковариацией», и она поддерживается в C # 4 для интерфейсов, которые, как известно, безопасны. IEnumerable
не имеет возможности записать последовательность, поэтому он безопасен.
class Animal { public virtual void Play(IEnumerable animals) { } } class Cat : Animal { public override void Play(IEnumerable animals) { } } class Program { static void Main() { Cat cat = new Cat(); cat.Play(new List()); } }
Это будет работать в C # 4, потому что List
конвертируется в IEnumerable
, который можно конвертировать в IEnumerable
. Невозможно, чтобы Play мог использовать IEnumerable
чтобы добавить собаку к тому, что на самом деле является списком кошек.
Вы могли бы сделать несколько вещей. Одним из примеров является листинг элементов списка для Animal
Использование вашего кода:
cat.Play(new List().Cast().ToList());
Другой – сделать Animal
generic, поэтому cat.Play(new List
должно сработать.
class Animal { public virtual void Play(List animals) { } } class Cat : Animal { public override void Play(List cats) { } } class Program { static void Main(string[] args) { Cat cat = new Cat(); cat.Play(new List ()); } }
Другим способом является не создание Animal
generic, а метод Play
и ограничение этого на T : Animal
class Animal { public virtual void Play(List animals) where T : Animal { } } class Cat : Animal { public override void Play (List animals) { } }
Наконец, если вы находитесь на C # 4 и вам нужно только перечислить список и не изменять его, проверьте ответ Эрика Липперта на IEnumerable
.
Вы ищете общую ковариацию коллекции. Очевидно, что эта функция не поддерживается версией C #, которую вы используете.
Вы можете обойти это, используя метод расширения Cast
. Имейте в виду, однако, что это создаст копию исходного списка вместо передачи оригинала как другой тип:
cat.Play((new List()).Cast().ToList());
используйте метод расширения Cast ()
так:
class Program { static void Main(string[] args) { Cat cat = new Cat(); cat.Play(new List().Cast()); } }
Причиной этого является b / c .net 3.5 не поддерживает ковариацию, но 4.0 делает 🙂
Все упоминают метод литья уже. Если вы не можете обновить до 4.0, способ скрыть приведение
class Cat : Animal { public override void Play(List animal) { Play((List)animal); } public virtual void Play(List animal) { } }
Это тот же трюк IEnumable
и IEnumarable
для GetEnumerator