2009-07-23 3 views
4

Скажем, у меня есть метод, ожидающий общий набор параметров базового типа, см. Test.MethodA (IEnumerable (BaseClass) listA) ниже. Почему, когда я передаю ему коллекцию производного типа, код не будет создан? Не все ли экземпляры DerivedClass также будут BaseClass?Передача общей коллекции объектов методу, который требует набора базового типа

я мог бы просто создал новый список (BaseClass) и передал, что в Methoda (IEnumerable (BaseClass) lišta). Но я бы подумал, что C# будет достаточно умным, чтобы знать, что коллекция DerivedClass имеет все те же свойства, что и коллекция BaseClass.

Использует метод List.Cast (T)(), как я показал лучший способ решить эту проблему?

abstract class BaseClass 
{ 
    public int SomeField; 
    public abstract string SomeAbstractField 
    { 
     get; 
    } 
} 

class DerivedClass:BaseClass 
{ 
    public override string SomeAbstractField 
    { 
     get { return "foo"; } 
    } 
} 

class TestClass 
{ 

    public void MethodA(IEnumerable<BaseClass> listA) 
    { 

    } 

    public void MethodB() 
    { 
     List<DerivedClass> listB = new List<DerivedClass>(); 

     //Error 16 The best overloaded method match for 
     //TestClass.MethodA(List<BaseClass>)' 
     //has some invalid arguments 
     this.MethodA(listB); 

     //this works 
     this.MethodA(listB.Cast<BaseClass>()); 
    } 
} 
+0

Возможный дубликат [Литье общей коллекции в базовый тип] (http://stackoverflow.com/questions/539287/casting-a-generic-collection-to-base-type) – outis

ответ

10

Cast<>() это лучший способ решить эту проблему на данный момент. Ваша исходная версия будет работать отлично в C# 4.0/.NET 4.0, хотя, где IEnumerable<T> ковариантно в T.

(я только что проверил это не компилируется в .NET 4.0 бета 1)

До .NET 4.0 и C# 4 выходи, дженерики инвариантны - IEnumerable<object> и IEnumerable<string> эффективно несвязанные интерфейсы. Даже в .NET 4.0 вы не сможете сделать это с помощью List<T> в качестве типа параметра - только интерфейсы и делегаты будут вариантами, и даже тогда только тогда, когда параметр типа только используется в соответствующих положениях (выходные позиции для ковариация, входные позиции для контравариантности).

Чтобы узнать больше о дисперсии в C# 4, прочитайте превосходный series of blog posts Eric Lippert.

+0

+1 Да, это типичный случай ожидания .NET 4.0 :) – Zyphrax

+2

@Downvoter: Почему downvote? –

+0

@ Jon Skeet: ты лучший. Я знал ответ, но вы вошли быстрее. @Downvoter: почему downvote? –

1

В общем случае (т. Е. Для коллекций, которые могут быть модифицируемыми), не имеет значения, что «коллекция DerivedClass имеет все те же свойства, что и коллекция BaseClass»: в коллекцию Fruit вы можете вставить Banana, Apple и Pear - в коллекции Orange, вы не можете, значит, это не имеют такие же свойства (под модификацией).

IEnumerable - это другой случай, поскольку он НЕ модифицируется, так как @Jon говорит, что это чрезмерное ограничение было удалено для этого специального случая в 4.0.

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