C# 列表多态性

C# 列表多态性,c#,generics,polymorphism,C#,Generics,Polymorphism,我有一个对象的继承结构,有点像下面的: public class A { } public class B : A { } public class C : B { } private void Method(List<A> foos) { foreach (var foo in foos) Bar(foo); } private void Method(List<B> foos) { foreach (var foo in foos) Bar(foo); } priv

我有一个对象的继承结构,有点像下面的:

public class A { }
public class B : A { }
public class C : B { }
private void Method(List<A> foos) { foreach (var foo in foos) Bar(foo); }
private void Method(List<B> foos) { foreach (var foo in foos) Bar(foo); }
private void Method(List<C> foos) { foreach (var foo in foos) Bar(foo); }

// An A, B or C object can be passed to this method thanks to polymorphism
private void Bar(A ayy) { /* Method Implementation */ }
理想情况下,我希望能够将
a
B
C
列表传递给以下单个方法:

private void Method(List<A> foos) { /* Method Implementation */ }

B toBee = new B();
B notToBee = new B();
List<B> hive = new List<B> { toBee, notToBee };

// Call Method() with a inherited type.  This throws a COMPILER ERROR 
// because although B is an A, a List<B> is NOT a List<A>.
Method(hive);
private void方法(List foos){/*方法实现*/}
B toBee=新的B();
B notToBee=新的B();
列表配置单元=新列表{toBee,notToBee};
//使用继承的类型调用方法()。这会引发编译器错误
//因为虽然B是A,但列表不是列表。
方法(蜂箱法);
我想想出一种方法来获得同样的功能,尽可能少的代码重复

我能想到的最好办法是创建包装器方法,它接受各种类型的列表,然后循环通过传递的列表来调用相同的方法;最后,利用多态性对我有利:

private void Method(List<A> foos) { foreach (var foo in foos) Bar(foo); }
private void Method(List<B> foos) { foreach (var foo in foos) Bar(foo); }
private void Method(List<C> foos) { foreach (var foo in foos) Bar(foo); }

// An A, B or C object can be passed to this method thanks to polymorphism
private void Bar(A ayy) { /* Method Implementation */ }
private void方法(List foos){foreach(var foo in foos)Bar(foo);}
私有void方法(List foos){foreach(var foo in foos)Bar(foo);}
私有void方法(List foos){foreach(var foo in foos)Bar(foo);}
//由于多态性,可以将A、B或C对象传递给此方法
私有void Bar(A ayy){/*方法实现*/}
正如您所看到的,我已经复制并粘贴了三次该方法,只更改了列表的泛型中包含的类型。我已经开始相信,任何时候你开始复制和粘贴代码,有一个更好的方法来做到这一点。。。但我似乎想不出一个

我如何才能在没有不必要的复制和粘贴的情况下完成这样的壮举?

创建一个:

然后您确定
foos
的每个元素都可以用作
A
的实例:

private void Method<T>(List<T> foos) 
    where T : A
{
    foreach (var foo in foos)
    {
        var fooA = foo as A;

        // fooA != null always (if foo wasn't null already)

        Bar(fooA);
    }
}
private void方法(列出foos)
T:A在哪里
{
foreach(foos中的var foo)
{
var fooA=foo作为一个变量;
//fooA!=始终为null(如果foo尚未为null)
酒吧(fooA);;
}
}
正如他在回答中指出的那样,这甚至更好 如果不需要修改集合,请使用
IEnumerable
。它是协变的,因此您不会遇到您描述的问题。

您需要

如果你能写以下内容:

public class A { }
public class B : A { }
public class C : B { }
private void Method(List<A> foos) { foreach (var foo in foos) Bar(foo); }
private void Method(List<B> foos) { foreach (var foo in foos) Bar(foo); }
private void Method(List<C> foos) { foreach (var foo in foos) Bar(foo); }

// An A, B or C object can be passed to this method thanks to polymorphism
private void Bar(A ayy) { /* Method Implementation */ }
List
是一种机制,它将
T
引用(或值类型的值)存储在数组中的连续内存中。您不需要这里的特定属性

相比之下,
IEnumerable
是一种合同。它只是说您可以枚举一个序列,这就是本例中所需的全部内容

您还可以使用其他协变接口类型,如
IReadOnlyCollection
(如果您需要提前知道项目计数或必须多次枚举)或
IReadOnlyList
(如果您需要项目索引)

请记住,大多数时候最好尽可能将接口类型作为参数,因为它允许您在需要时切换底层实现


但是如果你真的要修改列表,那么协方差是不够的。在这种情况下,使用的是的解决方案,但是,嘿,您仍然可以使用
IList
而不是
列表
:-)

这是一个更好的解决方案@BartoszKP这取决于实现中的内容,如果列表需要修改,那么您的解决方案会更好:-)感谢您提供的信息丰富的回答。不幸的是,在.NET4.0之前,C#似乎不支持通用接口中的协方差,我一直在使用3.5。
private void Method(IEnumerable<A> foos)
{
    foreach (var foo in foos)
        Whatever(foo);
}