考虑这个微不足道的功能:
public static bool IsPositive(IComparable<int> value)
{
return value.CompareTo(0) > 0;
}
现在,如果我将int
传递给此方法,则会将其装箱。因此,将上述方法定义如下更好吗?
public static bool IsPositive<T>(T value) where T : IComparable<int>
{
return value.CompareTo(0) > 0;
}
以这种方式使用泛型约束,我可以实现与上面代码完全相同的功能,并且还有额外的好处,即不需要装箱(因为对IsPositive<int>
的调用接受{{1}类型的参数}})。
上面的示例代码显然毫无意义。但我更广泛的问题是:不会总是以后一种方式定义方法(使用通用约束而不是具有某种接口类型的参数),以避免潜在的拳击的价值类型?
我怀疑答案可能是“是的,但它需要更多的输入,并且在很多情况下遇到值类型的可能性很小,例如当方法接受某些int
时。”但是我想知道这些方法之间是否存在更大的差异,这些方法目前正在逃避我。
答案 0 :(得分:8)
一个问题是通用约束实际上不是签名的一部分。如果你有......
static T Method<T>(T value) where T : ICompareable<int>
......和......
static T Method<T>(T value) where T : IEnumerable<int>
......编译器无法知道哪个是哪个。
并调用Eric Lippert ......
答案 1 :(得分:7)
关于该方法的调用是否在传递参数后引发装箱的问题的评论中存在一些混淆。
当对类型为带有约束的类型参数的表达式调用虚方法时,C#编译器会发出constrained.callvirt
指令。人们希望,这是正确的;拳击只在绝对必要时才会发生。
有关约束虚拟调用的精确装箱语义的详细信息,请阅读文档:
http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.constrained.aspx
答案 2 :(得分:0)
另一个问题是泛型约束是在参数化类型的泛型类型参数上,例如
static bool AreAllTheSame<T>(IEnumerable<T> something)
where T : IEquatable<T>
除非你引入第二个类型参数,否则不可能总是以这种方式转换泛型类型参数:
static bool AreAllTheSame<S, T>(S something)
where S : IEnumerable<T>
where T : IEquatable<T>
这看起来不对。