避免在泛型类型参数上使用==和!=运算符,但它可以与null进行比较吗?

时间:2013-09-25 20:55:56

标签: c#

根据它所说的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#文档试图告诉我要避免的问题吗?

5 个答案:

答案 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),您有完全不同的语法。指南是你应该避免第一个,但第二个是好的。