何时应该或不应该我能使用一般类型的限制吗?
-
10-07-2019 - |
题
我已经有了一个基类:
public abstract class StuffBase
{
public abstract void DoSomething();
}
和两个源类
public class Stuff1 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 1 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 1 reporting for duty!");
}
}
public class Stuff2 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 2 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 2 reporting for duty!");
}
}
好吧,现在就说我已经有了一个列表中的项目:
var items = new List<StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());
我想他们都叫他们或重写现有的()方法。我能期望的只是迭代表和呼叫他们的或重写现有的()方法,因此,让我们说,我已经有了一个方法做到这一所谓的AllDoSomething()只是迭代表与会的工作:
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
什么是实际区别以下的方法?
public static void AllDoSomething<T>(List<T> items) where T: StuffBase
{
items.ForEach(i => i.DoSomething());
}
这两种方法显示在实际方面,虽然在语法上的不同,将做同样的事情。
他们只是不同的方式做同样的事情吗?我的理解泛型和类型的制约但不能看到我为什么会使用一种方法比其他在这个实例。
解决方案
这是因为作为尚未,C#不支持 差.
更正式,在C#v2。0如果是一个T 亚型的U,然后T[]是一个子类型的 U[],但克不是一个子类型的G (G任何通用型)。在 类理论的术语中,我们描述 这种行为说,C#阵列 类型的"协变"和一般 类型是"不变".
参考: http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx
如果你有以下方法:
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
var items = new List<Stuff2>();
x.AllDoSomething(items); //Does not compile
在那里如果你使用通用类型的约束,它会的。
有关的详细信息的协变和逆变],检查了 埃里克利珀特的系列的员额.
其他文章值得一读:
- http://www.pabich.eu/blog/archive/2008/02/12/c-generics---parameter-variance-its-constraints-and-how-it.aspx
- http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx
- http://msdn.microsoft.com/en-us/library/ms228359(VS。80).aspx
- http://www.csharp411.com/convert-between-generic-ienumerablet/
- http://research.microsoft.com/apps/pubs/default.aspx?id=64042
- 为什么不能列表<parent> =列表<child>?
其他提示
假设你有一个清单:
List<Stuff1> l = // get from somewhere
现在尝试:
AllDoSomething(l);
使用通用版本,将允许。使用非泛型,它不会。这是本质区别。 Stuff1
列表不是StuffBase
列表。但在通用情况下,您并不要求它完全是<=>的列表,因此它更灵活。
您可以首先将<=>列表复制到<=>列表中,以使其与非泛型版本兼容。但是假设你有一个方法:
List<T> TransformList<T>(List<T> input) where T : StuffBase
{
List<T> output = new List<T>();
foreach (T item in input)
{
// examine item and decide whether to discard it,
// make new items, whatever
}
return output;
}
如果没有泛型,您可以接受<=>列表,但是您必须返回<=>列表。如果调用者知道这些项目实际上是派生类型,则必须使用强制转换。因此,泛型允许您保留参数的实际类型,并通过该方法将其引导到返回类型。
在您提供的示例中没有区别,但请尝试以下操作:
List<Stuff1> items = new List<Stuff1>();
items.Add(new Stuff1());
AllDoSomething(items);
AllDoSomething<StuffBase>(items);
第一个调用运行良好,但第二个调用由于通用协方差而无法编译