我什么时候应该或不应该使用泛型类型约束?
我有一个基类:
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());
我希望它们都调用它们的 DoSomething() 方法。 我可以期望只迭代列表并调用它们的 DoSomething() 方法,所以假设我有一个名为 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());
}
尽管语法不同,但这两种方法实际上都在做同样的事情。
它们只是做同一件事的不同方式吗? 我了解泛型和类型约束,但不明白为什么在这种情况下我会使用一种方法而不是另一种方法。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是因为到目前为止,C# 还不支持协方差。
参考:http://blogs.msdn.com /rmbyers/archive/2005/02/16/375079.aspx
如果您有以下方法:
就好像您使用泛型类型约束一样,它会的。
有关协变和逆变的详细信息],请查看 Eric Lippert 的系列帖子。
其他值得一读的帖子:
This is because as of yet, C# does not support Covariance.
Reference: http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx
If you have the following method :
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 :
假设您有一个列表:
现在尝试:
使用通用版本,它将被允许。 对于非通用的,则不会。 这就是本质的区别。
Stuff1
列表不是StuffBase
列表。 但在一般情况下,您不需要它完全是StuffBase
的列表,因此它更灵活。您可以通过首先将
Stuff1
列表复制到StuffBase
列表中来解决此问题,以使其与非通用版本兼容。 但假设您有一个方法:如果没有泛型,您可以接受
StuffBase
列表,但随后您必须返回StuffBase
列表。 如果调用者知道这些项确实属于派生类型,则必须使用强制转换。 因此,泛型允许您保留参数的实际类型,并通过方法将其引导到返回类型。Suppose you had a list:
Now try:
With the generic version, it will be allowed. With the non-generic, it won't. That's the essential difference. A list of
Stuff1
is not a list ofStuffBase
. But in the generic case, you don't require it to be exactly a list ofStuffBase
, so it's more flexible.You could work around that by first copying your list of
Stuff1
into a list ofStuffBase
, to make it compatible with the non-generic version. But then suppose you had a method:Without generics, you could accept a list of
StuffBase
, but you would then have to return a list ofStuffBase
. The caller would have to use casts if they knew that the items were really of a derived type. So generics allow you to preserve the actual type of an argument and channel it through the method to the return type.在您提供的示例中,没有区别,但请尝试以下操作:
第一个调用运行良好,但第二个调用由于通用协方差而无法编译
In the example you provided there is no difference but try the following:
The first call works well but the second one does not compile because of generic covariance