Подтвердить что ты не робот

Список С# <Интерфейs>: почему вы не можете выполнить `List <IFoo> foo = new List <Bar>();`

Если у вас есть интерфейс IFoo и класс Bar : IFoo, почему вы можете сделать следующее:

List<IFoo> foo = new List<IFoo>();  
foo.Add(new Bar());

Но вы не можете сделать:

List<IFoo> foo = new List<Bar>();
4b9b3361

Ответ 1

На случайном взгляде кажется, что это должно (как в пиве быть свободным) работать. Тем не менее, быстрый анализ здравомыслия показывает нам, почему он не может. Имейте в виду, что следующий код не будет компилировать. Он намеревался показать, почему это не разрешено, хотя оно выглядит в порядке до точки.

public interface IFoo { }
public class Bar : IFoo { }
public class Zed : IFoo { }

//.....

List<IFoo> myList = new List<Bar>(); // makes sense so far

myList.Add(new Bar()); // OK, since Bar implements IFoo
myList.Add(new Zed()); // aaah! Now we see why.

//.....

myList - это List<IFoo>, то есть он может принимать любой экземпляр IFoo. Однако это противоречит тому, что он был создан как List<Bar>. Поскольку наличие List<IFoo> означает, что я мог бы добавить новый экземпляр Zed, мы не можем этого допускать, так как базовый список на самом деле List<Bar>, который не может разместить a Zed.

Ответ 2

Причина в том, что С# не поддерживает совместную и контравариантность для дженериков в версиях С# 3.0 или более ранних версий. Это выполняется в С# 4.0, поэтому вы сможете сделать следующее:

IEnumerable<IFoo> foo = new List<Bar>();

Обратите внимание, что в С# 4.0 вы можете использовать для IEnumerable <IFoo> , но вы не сможете использовать List <IFoo> . Причина связана с безопасностью типа, если вы можете использовать List <Bar> для списка <IFoo> вы могли бы добавить в список других разработчиков IFoo, не нарушая безопасность.

Для получения дополнительной информации о ковариации и контравариантности в С# у Эрика Липперта есть хорошая серия блога.

Ответ 3

Если вам нужно преобразовать список в список базового класса или интерфейса, вы можете сделать это:

using System.Linq;

---

List<Bar> bar = new List<Bar>();
bar.add(new Bar());

List<IFoo> foo = bar.OfType<IFoo>().ToList<IFoo>();

Ответ 4

Это связано с созданием списка, вы указали, что T является IFoo, поэтому вы не можете создавать его как панель, поскольку они разные, хотя Bar поддерживает IFoo.

Ответ 5

Список - это тип в этом случае, и это не список вопросов наследования <IFoo> действительно отличается от List <Bar> . List не знает anythign или наследует характеристики IFoo или Bar.

Надеюсь, что это поможет.

Ответ 6

Поскольку список IFoo может содержать и некоторый Bar, но список IFoo - это не то же самое, что список Bar s.

Обратите внимание, что вместо использования С# я использовал английский выше. Хочу подчеркнуть, что это не глубокая проблема; вы просто путаетесь с деталями синтаксиса. Чтобы понять ответ, вам нужно увидеть вне синтаксиса и подумать о том, что он на самом деле означает.

Список IFoo может содержать Bar, потому что a Bar является IFoo. Здесь мы говорим об элементах списка. Список по-прежнему является списком IFoo s. Мы не изменили это.

Теперь список, который вы назвали foo, по-прежнему является списком IFoo (более педантично, foo объявлен как List<IFoo>). Это не может быть ничего. В частности, он не может быть внесен в список Bar (List<Bar>). Список Bar - это совершенно другой объект, чем список IFoo s.

Ответ 7

Я использовал некоторый linq, чтобы упростить преобразование

List<Bar> bar = new List<Bar>();
bar.add(new Bar());

List<IFoo> foo = bar.Select(x => (IFoo)x).ToList();

Это немного меньше, чем другие ответы, но хорошо работает

Ответ 8

List<Bar> не наследуется от List<IFoo>

Ответ 9

Если у вас есть список типов List<IFoo>, вы можете вызвать list.add(new Baz());, предполагая Baz реализует IFoo. Однако вы не можете сделать это с помощью List<Bar>, поэтому вы не можете использовать List<Bar> везде, где вы можете использовать List<IFoo>.

Однако, поскольку Bar реализует IFoo, вы можете использовать панель везде, где вы используете IFoo, поэтому передача строки для добавления работает, когда она ожидает, и IFoo.