[英]Generic method with variance in C#?
考慮以下類(繼承樹):
public class A {}
public class B: A {}
而這種方法:
public IList<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
編譯器不滿意。 錯誤是Cannot convert expression type IList<B> to return type IList<A>
。 我該如何解決? 換句話說如何指定MyMethod
將返回IList<T>
的T
其中T
可以是任何東西,從繼承A
或實例的A
自己?
您要的內容是不可能的,因為IList<T>
不支持方差-您不能在期望IList<A>
任何地方使用IList<B>
。 您必須解釋所需的更多詳細信息才能提出解決方案。
可能的解決方案是:
public IList<A> MyMethod(){
IList<A> result = new List<A>();
//add some items to result
return result;
}
要么
public IEnumerable<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
即使B從A繼承,也不能將IList <B>轉換為IList <A>。否則,用戶可能會嘗試將不是B的A實例添加到列表中。
public void Example(){
IList<B> listB = new List<B>();
IList<A> listA = listB;
listA.Add(new A()); // Can't insert A into a list of B
}
您可以返回IEnumerable <A>而不是IList <A>嗎? 與IList <A>不同,IEnumerable <A>是協變的。
如何指定MyMethod將返回T的IList,其中T可以是從A繼承的任何東西或A本身的實例?
您可以聲明它返回IList<A>
。 為什么? 假設B
繼承自A
可以傳遞B
每個項目,其中所需的類型是A
通過繼承,Liskov替換原理或方法差異將其稱為多態,名稱無關緊要。 重要的是以下各項有效(在LinqPad上測試):
public class A {}
public class B: A {}
public IList<A> MyMethod()
{
var result = new List<A>();
//add some items to result
result.Add(new B());
return result;
}
實際上,您可以說您將返回IList<TA>
並請求一些派生類型( TB
, TC
...)來填充它。 是的,下面的示例也適用(在LinqPad上測試):
void Main()
{
MyMethod<A, B, C>();
}
public class A {}
public class B: A {}
public class C: A {}
public IList<TA> MyMethod<TA, TB, TC>()
where TB : TA, new()
where TC : TA, new()
where TA : class
{
var result = new List<TA>();
//add some items to result
result.Add(new B() as TA);
result.Add(new C() as TA);
return result;
}
或者,如果您想保留特定的基本類型(例如,您想返回一個IList<A>
但實際上它包含派生自A
的類的項,則可以這樣做:
void Main()
{
MyMethod<B, C>();
}
public class A {}
public class B: A {}
public class C: A {}
public IList<A> MyMethod<T1, T2>()
where T1 : A, new()
where T2 : A, new()
{
var result = new List<A>();
//add some items to result
result.Add(new T1() as A);
result.Add(new T2() as A);
return result;
}
好的,如果您真的想說它返回IList<T>
where T : A
。 然后說!
void Main()
{
MyMethod<B>();
}
public class A {}
public class B: A {}
//public class C: A {} //Even if I don't add that class
public IList<T> MyMethod<T>()
where T : A, new()
{
var result = new List<T>();
//add some items to result
result.Add(new T());
return result;
}
是的,不能返回類型T
項和類型A
的項的混合,因為它說它返回IList<T>
並且不是每個類型A
的項也都是類型T
的項。
查看您的代碼:
public IList<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
當您說要返回IList<A>
時,您正在嘗試返回IList<B>
。 讓我們假設那行得通...那么方法調用者會發生什么呢? 讓我們來看看:
public class A {}
public class B: A {}
public class C: A {}
void Main()
{
//Hmmm... I need a IList<T>, let's call MyMethod!
IList<A> list = MyMethod();
//Cool, I got an IList<A>, now let's add some items...
var item = new C();
//Well, item is of type C...
// and C inherits from A, so I must be able to add it...
list.Add(item); //BOOM!
//It was actually an IList<B>!
// and C doesn't dervive from B, so you can't add it.
}
DFTBA!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.