2009-08-01 92 views
2

我有两个IList<ICat>,我试图创建一个方法,需要一个IList<ICat>并做一些工作。我在尝试将IList<PussyCat>IList<OtherCat>传递给它时遇到了问题,PussyCatOtherCat都实现了ICatIList <IWhatever>作为方法参数

我已经试过:

List<PussyCat> cats = ... 
DoWork((IList<ICat>)cats); 

,只是

DoWork(cats); 

但无论编译。有任何想法吗?

+0

请显示您的Dowork()方法的签名... – 2009-08-01 06:30:28

回答

7

C#泛型是不变的。这意味着List<string>不是List<object>

C#4.0引入了safe covariance/contravariance但仍然无法通过List<string>作为List<object>。原因是:

List<string> x = new List<string>(); 
List<object> o = x; // assume this statement is valid 
o.Add(5); // Adding an integer to a list of strings. Unsafe. Will throw. 

另一方面,数组是协变的。您可以将string[]传递给期望object[]的方法。

+0

谢谢。我已经阅读过关于共同和反对方差的内容,但我认为需要更详细的阅读。我发现我需要越来越多的C#4.0。 – Echilon 2009-08-01 06:37:33

+3

请注意,如果`DoWork`只是`foreach`集合并且不改变任何内容,则可以声明该参数为`IEnumerable `,并用`DoWork(cats.Cast ())`调用它。 – 2009-08-01 06:40:09

0

直到C#4.0到达其对CO和反方的支持,你也许可以用这样的闪避:

public void DoWork(IEnumerable<ICat> cats) 
{ 
    //do something 
} 
List<PussyCat> pussyCats = new List<PussyCat>; 
List<OtherCat> otherCats = new List<OtherCat>; 
DoWork(pussyCats.OfType<ICat>); 
DoWork(otherCats.OfType<ICat>); 
+1

正如我所说的,对于这种特定的情况,没有什么会改变C#4.0,'OfType`返回`IEnumerable`而不是`IList`。 – 2009-08-01 06:48:42

5

有两个备选方案:

  1. 让你的方法像这样:

    public void DoWork<T> (IList<T> cats_) where T : ICat 
    { 
        //Do work; 
    } 
    
  2. 另一种可能性是有一个像

    public void DoWork(IList<ICat> cats_) 
    { 
        //Do work; 
    } 
    

    ,并调用它以下列方式:

    { 
        //....Assuming: IList<PussyCat> iListOfPussyCats 
        List<PussyCat> pussyCats = new List<PussyCats>(iListOfPussyCats); 
        DoWork(pussyCats.ConvertAll<ICat>(c => c as ICat); 
    } 
    
1

如果方法不真正需要直接索引(IList<T>),并且不需要添加/删除项目(ICollection<T>) ,然后通过一个IEnumerable<T>Cast<T>()扩展方法允许将[插入ICat衍生类型]的任何IList作为IEnumerable<ICat>传递。