2009-08-04 2 views
39

Если у вас есть интерфейс IFoo и класс Bar : IFoo, поэтому вы можете сделать следующее:C Список # <Interface>: почему вы не можете сделать `Список <IFoo> Foo = новый список <Bar>();`

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

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

List<IFoo> foo = new List<Bar>(); 
+0

Точный дубликат http://stackoverflow.com/questions/833447/why-is-this-cast-not-possible –

+1

Зачем вам нужно объявлять его IFoo it mus т содержат только бары? –

+1

@samuelcarrijo, поскольку он условно может быть инициализирован списком некоторых других IFoo. – Jimmy

ответ

95

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

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>, который не может разместить Zed.

+13

+1 для «это должно (как в пиве должно быть бесплатно) работать» и заставлять меня улыбаться :) –

+0

Извините, но этот ответ неверен (возможно, популярный для пива, но не правильный). Проверьте свой код, он не сработает на вашем комментарии «// Делает смысл до сих пор», потому что Список - это совсем другой тип списка , перейдите по этой ссылке для получения более подробной информации http://stackoverflow.com/questions/833447/why-is -this-cast-not-possible/833475 # 833475 –

+10

Binary Worrier, Adam сказал, что это не сработает и объясняет почему! вы читаете сообщение перед комментированием ... – Marcom

4

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

1

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

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

0

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

0

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

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

30

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

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

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

Для получения дополнительной информации о ковариации и контравариантности в C# у Эрика Липперта есть nice blog series.

1

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

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

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

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

9

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

using System.Linq; 

--- 

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

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

Я верю.OfType () часть избыточна. Я смог уйти без него. – ScubaSteve

1

Я использовал некоторые LINQ, чтобы сделать преобразование проще

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

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

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

Смежные вопросы