何时应该或不应该使用泛型约束? [英] When should or shouldn't I be using generic type constraints?
问题描述
我有一个基类:
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 东西2做了一件很酷的事!);
public Stuff1()
{
Console.WriteLine(New stuff 2 reporting for duty!);
好的,现在说我有一份清单items:
var items = new List< StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());
我希望他们都调用他们的DoSomething()方法。我可以期望迭代列表并调用它们的DoSomething()方法,所以我们可以说我有一个方法可以完成名为AllDoSomething()的方法,它只是迭代列表并完成任务:
public static void AllDoSomething(List< StuffBase> items)
{
items.ForEach(i => i.DoSomething() );
}
以下方法的实际区别是什么?
public static void AllDoSomething< T>(List< T> items)其中T:StuffBase
{
items.ForEach(i => i.DoSomething());
$ / code>
这两种方法虽然在语法上有所不同,同样的事情。
他们做同样的事情只是不同的方式吗?我了解泛型和类型约束,但不明白为什么我会在这种情况下使用其他方法。
是因为至今为止,C#不支持协变。
更正式地说,在C#v2.0中,如果T是U的
子类型,那么T []是
U [],但G不是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); //不会编译
如果您使用泛型类型约束,它会。
有关协方差和反变量的更多信息,请查看 Eric Lippert的一系列贴子。
阅读:
- 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
- h ttp://msdn.microsoft.com/en-us/library/ms228359(VS.80).aspx
- $
- http://research.microsoft.com/apps/pubs /default.aspx?id=64042
- 为什么不能列出< parent> =列表< child> ;?
I've got a base class:
public abstract class StuffBase
{
public abstract void DoSomething();
}
And two derived classes
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!");
}
}
Okay, now say I've got a list of items:
var items = new List<StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());
and I want them all to call their DoSomething() method. I could expect to just iterate the list and call their DoSomething() method, so let's say I've got a method to do that called AllDoSomething() that just iterates over the list and does the job:
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
What is the practical difference of the following method?
public static void AllDoSomething<T>(List<T> items) where T: StuffBase
{
items.ForEach(i => i.DoSomething());
}
Both methods appear in real terms, although being syntactically different, to be doing the same thing.
Are they just different ways of doing the same thing? I understand generics and type constraints but can't see why I would use one way over the other in this instance.
This is because as of yet, C# does not support Covariance.
More formally, in C# v2.0 if T is a subtype of U, then T[] is a subtype of U[], but G is not a subtype of G (where G is any generic type). In type-theory terminology, we describe this behavior by saying that C# array types are "covariant" and generic types are "invariant".
Reference: http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx
If you have the following method :
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
var items = new List<Stuff2>();
x.AllDoSomething(items); //Does not compile
Where as if you use the generic type constraint, it will.
For more information about Covariance and Contravariance], check out Eric Lippert's series of posts.
Other posts worth reading :
- 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
- Why can't List<parent> = List<child>?
这篇关于何时应该或不应该使用泛型约束?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!