我找到了一篇Microsoft Connect的文章,详细讨论了这个问题:
Unfortunately, this behavior is by design and there is not an easy solution to enable use of with type parameters that may contain value types.
If the types are known to be reference types, the default overload of defined on object tests variables for reference equality, although a type may specify its own custom overload. The compiler determines which overload to use based on the static type of the variable (the determination is not polymorphic). Therefore, if you change your example to constrain the generic type parameter T to a non-sealed reference type (such as Exception), the compiler can determine the specific overload to use and the following code would compile:
public class Test<T> where T : Exception
If the types are known to be value types, performs specific value equality tests based on the exact types used. There is no good "default" comparison here since reference comparisons are not meaningful on value types and the compiler cannot know which specific value comparison to emit. The compiler could emit a call to ValueType.Equals(Object) but this method uses reflection and is quite inefficient compared to the specific value comparisons. Therefore, even if you were to specify a value-type constraint on T, there is nothing reasonable for the compiler to generate here:
public class Test<T> where T : struct
在您介绍的例子中,编译器甚至不知道T是值还是引用类型,同样也没有生成对所有可能类型都有效的东西。引用比较对于值类型无效,某些类型的值比较对于没有重载的引用类型是不可预期的。
以下是你可以做的事情。
我已经验证了这两个方法都适用于引用类型和值类型的泛型比较:
object.Equals(param, default(T))
or
EqualityComparer<T>.Default.Equals(param, default(T))
要与"=="操作符进行比较,您需要使用以下方法之一:
如果T的所有情况都派生自一个已知的基类,则可以使用泛型类型限制让编译器知道。
public void MyMethod<T>(T myArgument) where T : MyBase
然后,编译器识别如何在MyBase上执行操作,不会抛出“Operator '=='不能应用于类型为'T'和'T'的操作数”错误,你现在看到的。
另一种选择是将T限制为实现IComparable的任何类型。
public void MyMethod<T>(T myArgument) where T : IComparable
然后使用IComparable接口定义的CompareTo方法。