根据它所说的Constraints on Type Parameters (C# Programming Guide)文档,我引用:
当应用where T:class约束时,避免使用==和!= 类型参数上的运算符,因为这些运算符将进行测试 仅参考标识,而不是价值平等。甚至是这种情况 如果这些运算符在一个用作的类型中重载 论点。以下代码说明了这一点;输出是 false,即使String类重载了==运算符。
使用以下示例:
public static void OpTest<T>(T s, T t) where T : class
{
System.Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "target";
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}
然而,ReSharper(我刚刚开始使用演示/试用版本来查看它是否对我来说是否有价值)提供了一个提示/提示来对参数执行空值检查,如下所示:
public Node(T type, Index2D index2D, int f, Node<T> parent)
{
if (type == null) throw new ArgumentNullException("type");
if (index2D == null) throw new ArgumentNullException("index2D");
if (parent == null) throw new ArgumentNullException("parent");
}
(T受where T : class, new()
约束)
我可以安全地关注ReSharper而不会遇到C#文档试图告诉我要避免的问题吗?
答案 0 :(得分:7)
是的,没关系。文档说不要比较两个参数,因为你正在进行参考比较。 ReSharper建议的代码只是确保你传递的引用不是null,这样做是安全的。
在我看来,C#docs建议您不这样做的主要原因是,例如,如果您使用两个字符串==
和T1
传递T2
它会做一个参考比较。在执行stringA == stringB
的任何其他时间,它将与字符串类中的重载进行值比较。它实际上只是警告不要进行这些类型的比较,因为通常使用的运算符重载(如果在本地范围内声明的两种类型上使用该运算符)不是。
答案 1 :(得分:7)
是。
只有==
运算符的一个非常奇怪的实现会使x == null
表示ReferenceEquals(x, null)
以外的其他内容。如果您正在使用具有如此奇怪的相等实现的类,那么当使用泛型类型参数检查null时,您遇到的问题要大于它的不一致。
答案 2 :(得分:4)
文档告诉您,==
将使用引用比较,无论T
的实际类型是什么,即使它已使==
运算符超载。在许多情况下,这不是用户期望的。
对于resharper代码,它将变量与null进行比较,您将想要作为参考比较,而不是值比较,因此文档警告您这是正确的行为。
然而,你可以通过写这样的东西使它变得更加明确,只是为了更清楚:
if(object.ReferenceEquals(type, null))//...
答案 3 :(得分:2)
是的,通常可以假设null
是一个特殊情况,可以对其==
或!=
进行处理。至少部分原因在于recommendation for overriding Equals
表示x.Equals(null)
应为false
。
如果你没有T : class
约束,那就是一个不同的故事,因为你会看到struct
和可空struct
的一些可能意外的行为(您可能希望default(T)
而不是null
。
如果你想明确表示肯定,你知道你正在比较对null
的引用,你可以随时使用object.ReferenceEquals(x, null)
(我只需要==
/ !=
,但是)。
答案 4 :(得分:1)
我会说这没关系。
null
有点特别,所以你没有在两个引用变量之间进行实际比较,你只是确保引用变量不是空引用。
将此与例如SQL进行比较。对于比较(a = b
)和空检查(a is null
),您有完全不同的语法。指南是你应该避免第一个,但第二个是好的。