2009-08-14 67 views
1

可能重复的一些问题:
Upcasting and generic lists与发送列表<T>为IEnumerable <T>的方法

好吧,我想送一个List<CardHolder>IEnumerable<ICardHolder>其中CardHolder : ICardHolder。然而,编译器错误:

错误4参数 '1':无法从 'System.Collections.Generic.List' 到 'System.Collections.Generic.IEnumerable' 转换

这似乎很奇怪对我来说,考虑一个List<T> : IEnumerable<T>。出了什么问题?

public interface ICardHolder 
{ 
    List<Card> Cards { get; set; } 
} 

public class CardHolder : ICardHolder 
{ 
    private List<Card> cards = new List<Card>(); 
    public List<Card> Cards 
    { 
     get { return cards; } 
     set { cards = value; } 
    } 

    // ........ 
} 

public class Deck : ICardHolder 
{ 
    // ......... 

    public void Deal(IEnumerable<ICardHolder> cardHolders) 
    { 
     // ........ 
    } 

    // ......... 
} 

public class Game 
{ 
    Deck deck = new Deck(); 
    List<CardHolder> players = new List<CardHolder>(); 

    // ......... 

    deck.Deal(players); // Problem is here! 

    // ......... 
} 

回答

7

问题是List<T>不是IEnumerable<T1>即使T : T1亚型。

C#中的泛型(C#4.0之前)是“不变的”(即没有这种子类型关系)。在.Net 4中,IEnumerable<T>将其类型参数标注为“协变”。这意味着如果T : T1List<T>将是IEnumerable<T1>的子类型。

有关此功能的更多详细信息,请参阅MSDN上的this page

编辑 - 您可以通过使Deal方法的通用解决这个在您的情况:

public void Deal<T>(IEnumerable<T> cardHolders) where T : ICardHolder 
{ 
    // ........ 
} 
+0

没有,所以我需要将我的列表转换为列表能够将它作为IEnumerable 发送?哦,是否有可能在VS2008上获得某种C#4.0的预览? – 2009-08-14 21:41:01

+1

这里有一篇关于泛型中的co/contravariance的优秀InfoQ文章:http://www.infoq.com/news/2008/08/GenericVariance – 2009-08-14 21:41:39

+0

+50泛型方法(如果可以的话)。谢谢! – 2009-08-14 21:50:35

0

添加到Ben的答案,则应更换行:

List<CardHolder> players = new List<CardHolder>(); 

有:

List<ICardHolder> players = new List<ICardHolder>(); 

你是不管怎么说接口更好...... :)

+0

不幸的是,这不适用于我有的其他代码,因为它需要访问ICardHolder没有(也不能)拥有的CardHolder的某些特定属性。不过谢谢。 – 2009-08-14 21:43:05

+0

对于CardHolder特定属性,您始终可以投射到CardHolder ... – 2009-08-14 21:48:25

1

A List<CardHolder>IEnumerable<CardHolder>,但IEnumerable<CardHolder>不是IEnumerable<ICardHolder>。这两个接口是无关的(除了它们的结构)。

C#4.0引入了协变和逆变,可以解决这样的问题

同时,在C#3.0中,你可以这样做:

deck.Deal(players.Cast<ICardHolder>()); 

应该没有显著的性能影响,因为收藏品是只枚举了一次,并upcast ICardHolder是MSIL

相关问题