【问题标题】:object.ReferenceEquals or == operator?object.ReferenceEquals 或 == 运算符?
【发布时间】:2011-10-30 11:32:17
【问题描述】:

为什么ThrowIfNull 实现为:

    static void ThrowIfNull<T>(this T argument, string name) where T : class
    {
        if (argument == null)
        {
            throw new ArgumentNullException(name);
        }
    }

改写成这样是不是更好:

    static void ThrowIfNull<T>(this T argument, string name) where T : class
    {
        if (object.ReferenceEquals(argument, null))
        {
            throw new ArgumentNullException(name);
        }
    }

优点:它有助于避免混淆 Equals 重载,并可能使代码更清晰。

这样做有什么缺点吗?应该有的。

【问题讨论】:

    标签: c# linq equals throw


    【解决方案1】:

    两者没有区别。您将 overriding Equals (在任一实现中均未调用)与 overloading == (在任一 sn-p 中均不相关)混淆了重载是在编译时执行的,编译器对T的了解不够,无法使用任何特定的重载)。

    只是为了说明我的意思:

    static void ThrowIfFoo<T>(this T argument, string name) where T : class
    {
        if (argument == "foo")
        {
            throw new Exception("You passed in foo!");
        }
    }
    

    测试:

    "foo".ThrowIfFoo(); // Throws
    
    string x = "f";
    x += "oo"; // Ensure it's actually a different reference
    
    x.ThrowIfFoo(); // Doesn't throw
    

    ThrowIfFoo 不知道 T 将是一个字符串 - 因为这取决于 调用 代码 - 并且仅在编译 ThrowIfFoo 时执行重载决议 。因此它使用运算符==(object, object) 而不是==(string, string)

    换句话说,是这样的:

    object foo1 = "foo";
    
    string tmp = "f";
    object foo2 = tmp + "oo";
    
    Console.WriteLine(foo1.Equals(foo2)); // Prints True
    Console.WriteLine(foo1 == foo2); // Prints false
    Console.WriteLine((string) foo1 == (string) foo2); // Prints True
    

    在最后一行中,编译器知道它可以使用 == 的重载,因为两个操作数的 compile-time 类型都是 string

    【讨论】:

    • 啊,是的。这就是 C# 深度泛型章节告诉我的,但我没有听!
    • @Grozz:是的,那家伙的想法和我一样;)
    • @Jon Skeet,但是当您调试代码时,第二次 X.ThrowIfFoo() 实际上将 x 值表示为 foo 而不是某些东西,甚至它上面的 getType 也表示它是一个字符串而不是目的。我在扩展方法中做了这个来检查它的类型和东西。所以我不明白为什么第二次虽然是 "foo"=="foo" 但仍然是假的?
    • @zenwalker:值等于到“foo”,但是涉及到两个不同的字符串,所以引用比较返回false。将编辑答案以显示示例。
    • @Jon Skeet,你们不是在 JIT 时间而不是在执行时间见面吗?
    【解决方案2】:

    == 运算符在编译时解析,而不是在运行时解析,由于 T 是通用的,编译器将使用 object 本身提供的 == 的实现,它会检查引用是否相等。

    这正是object.ReferenceEquals 所做的:调用object 提供的== 实现。

    【讨论】:

      【解决方案3】:

      这主要是化妆品。

      obj == null 将进行引用检查并返回,Equals 如果参数为 null 且未在 T 中覆盖,则也将返回。当一个参数为空时,它需要一个非常古怪/恶意的实现才能返回 true。

      【讨论】:

      • 会超载Equals 这样做吗?
      猜你喜欢
      • 2013-04-29
      • 2014-09-30
      • 2019-05-03
      • 2017-04-13
      • 2013-07-25
      • 2016-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多