Возможно ли сделать список объектов, полученных из базового базового класса, на список & lt; интерфейс базового класса & gt; [Дубликат]

объединение других ответов в простейшую форму ... аннотация с простым списком значений ...

  @Foos ({"one", "two"}) private String  AWK;  // ... public @interface Foos {String [] value ();  }  
22
задан santosh singh 15 September 2010 в 19:51
поделиться

5 ответов

Причина, по которой вы не можете сделать это, состоит в том, что список доступен для записи. Предположим, что это было законным, и посмотрите, что пойдет не так:

  List & lt; Cat & gt;  cats = new List & lt; Cat & gt; ();  Список & л; Животное & GT;  животные = кошки;  // Проблемы пивоварения ... animals.Add (новая собака ());  // эй, мы просто добавили собаку в список кошек ... кошек [0] .Speak ();  // Уоф!   

Хорошо, собака, мои кошки, это нехорошо.

Функция, которую вы хотите, называется «общей ковариацией», и она поддерживается в C # 4 для интерфейсов, которые, как известно, являются безопасными. IEnumerable & lt; T & gt; не имеет никакого способа записи в последовательность, поэтому он безопасен.

  класс Animal {public virtual void Play (IEnumerable & lt; Animal & gt; животные  ) {}} class Cat: Animal {public override void Play (IEnumerable & lt; Animal & gt; животные) {}} class Program {static void Main () {Cat cat = new Cat ();  cat.Play (новый список & lt; Cat & gt; ());  }}  

Это будет работать в C # 4, потому что List & lt; Cat & gt; конвертируется в IEnumerable & lt; Cat & gt; , который можно конвертировать в IEnumerable & л; & животные триазоли . Нельзя использовать Play IEnumerable & lt; Animal & gt; , чтобы добавить собаку к тому, что на самом деле является списком кошек.

45
ответ дан Eric Lippert 16 August 2018 в 02:46
поделиться
  • 1
    Мне не хватает того, как игра, являющаяся членом Animal, добавляет к объяснению. То есть, воспроизведение выполняется с использованием IEnumerable & lt; Animal & gt ;. IMO было бы более ясным, если бы это был Play (), и пример был помещен в void Main () с использованием назначения. – Dykam 17 September 2010 в 18:07
  • 2
    @Dykam: Это не так. Я пытался следовать структуре кода, изложенной в оригинальном плакате. – Eric Lippert 17 September 2010 в 19:08
  • 3
    Ах я вижу. По какой-то причине я не связывал два фрагмента. – Dykam 18 September 2010 в 16:41
  • 4
    плюс один для сохранения моих кошек в безопасности – Sayka 4 March 2017 в 16:27

Вы могли бы сделать несколько вещей. Один из примеров - это элементы в списке Animal

Используя ваш код:

  cat.Play (  новый список & lt; Cat & gt; (). Cast & lt; Animal & gt; (). ToList ());   

Другим является создание Animal generic, поэтому cat.Play (новый List & lt; Cat & gt; ()); будет работать. [ ! d13]

  класс Animal & lt; T & gt;  {public virtual void Play (List & lt; T & gt; животные) {}} класс Cat: Animal & lt; Cat & gt;  {public override void Play (List & lt; Cat & gt; cats) {}} class Program {static void Main (string [] args) {Cat cat = new Cat ();  cat.Play (новый список & lt; Cat & gt; ());  }}  

Другим способом является не создание Animal generic, а метод Play и ограничение этого на T: Animal

  класс Animal {public virtual void Play & lt; T & gt; (List & lt; T & gt; животные), где T: Animal {}} класс Cat: Animal {public override void Play & lt; T & gt;  (List & lt; T & gt; животные) {}}  

Наконец, если вы находитесь на C # 4 и вам нужно только перечислить список и не изменять его, проверьте ответ Эрика Липперта на IEnumerable & л; Животное & GT;!.! [D9] [D15]

13
ответ дан Anthony Pegram 16 August 2018 в 02:46
поделиться
  • 1
    +1 за общий трюк – Scott Chamberlain 15 September 2010 в 20:00
  • 2
    Также +1 для указания, что вы, вероятно, должны использовать IEnumerable для типа параметра, а не List – Joel Coehoorn 15 September 2010 в 20:05
  • 3
    Я не понимаю, что последний бит; почему класс Cat имеет метод с параметром типа Cat? Разве это не слишком запутанно, иметь два типа с одним и тем же именем внутри одной и той же декларации? – Eric Lippert 15 September 2010 в 22:38
  • 4
    Что ж, это о нем. Я становлюсь водопроводчиком. – Anthony Pegram 16 September 2010 в 01:05
  • 5
    Водопроводчики зарабатывают хорошие деньги, а аутсорсинг сантехники для зарубежных компаний невозможно. Мне гораздо удобнее работать с электричеством, чем вода. Если я когда-нибудь заболею этой работой по сантехнике, возможно, я это сделаю. – Eric Lippert 16 September 2010 в 07:07

использовать метод расширения Cast ()

so:

  class Program {static void Main (string [] args) {Cat cat = new Cat ();  cat.Play (новый список & lt; Cat & gt; (). Cast & lt; Animal & gt; ());  }}  

Причиной этого является b / c .net 3.5 не поддерживает ковариацию, но 4.0 делает:)

3
ответ дан Jose 16 August 2018 в 02:46
поделиться
  • 1
    Причина не в том. cat.Play (новый список & lt; Cat & gt; ()); также не будет работать в 4 с существующим кодом. – Anthony Pegram 15 September 2010 в 20:05

Вы ищете общую ковариацию коллекции. Очевидно, что эта функция не поддерживается версией C #, которую вы используете.

Вы можете обойти это, используя метод расширения Cast & lt; gt; () , Имейте в виду, что это создаст копию исходного списка вместо передачи оригинала как другой тип:

  cat.Play ((новый список & lt; Cat & gt; ()).  ; Животное & GT; () ToList ()).   
10
ответ дан Justin Niessner 16 August 2018 в 02:46
поделиться
  • 1
    Он не поддерживается списком вообще, поскольку он является универсальным. – Dykam 15 September 2010 в 20:02
  • 2
    @Dykam - Можете ли вы подробно рассказать? Комментарий не имеет большого смысла, как есть. – Justin Niessner 15 September 2010 в 20:13
  • 3
    Ну, так как List принимает входные данные, а также возвращает выход, co- и contravariance не представляется возможным. Если вы сможете сделать List & lt; Animal & gt; list = new List & lt; Dog & gt; (); Следующее приведет к сбою приложения: list.Add (новый Elephant ()); . – Dykam 15 September 2010 в 21:54

Все упоминают метод литья уже. Если вы не можете обновить до 4.0, способ скрыть листинг

  class Cat: Animal {public override void Play (List & lt; Animal & gt; animal) {Play ((List & lt; Cat & gt;) animal  );  } public virtual void Play (List & lt; Cat & gt; animal) {}}  

Это тот же трюк IEnumable и IEnumarable & lt; T & gt; играть за GetEnumerator

2
ответ дан Scott Chamberlain 16 August 2018 в 02:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: