簡體   English   中英

C#中具有方差的通用方法?

[英]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>並請求一些派生類型( TBTC ...)來填充它。 是的,下面的示例也適用(在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM