13

考虑这个微不足道的函数:

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>接受 type 的参数int)。

上面的示例代码显然毫无意义。但我更广泛的问题是:以后一种方式定义方法(使用通用约束而不是具有某种接口类型的参数)以避免潜在的值类型装箱不是总是有意义的吗?

我怀疑答案很可能是“是的,但它需要更多的输入,并且在许多情况下遇到值类型的可能性很小,例如当方法接受 some 时IEnumerable<T>”。但我想知道这些方法之间是否存在更大的差异,而这些方法目前正在逃避我。

4

3 回答 3

8

一个问题是通用约束实际上并不是签名的一部分。如果你有 ...

static T Method<T>(T value) where T : ICompareable<int>

... 和 ...

static T Method<T>(T value) where T : IEnumerable<int>

...编译器无法知道哪个是哪个。

并调用 Eric Lippert...

于 2010-08-19T20:09:20.283 回答
7

关于在参数传递对该方法的调用是否会导致装箱的问题的评论存在一些混淆。

当您在其类型是带有约束的类型参数的表达式上调用虚拟方法时,C# 编译器会发出一条constrained.callvirt指令。正如人们所希望的那样,这是正确的。拳击只有在绝对必要时才会发生。

有关受限虚拟调用的精确装箱语义的详细信息,请阅读文档:

http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.constrained.aspx

于 2010-08-20T19:56:12.333 回答
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>

那看起来不太对劲。

于 2010-08-19T20:31:19.647 回答