6

为什么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的重载,并且可能使代码更清晰。

有什么缺点吗?应该有一些。

4

3 回答 3

12

两者没有区别。您将覆盖 Equals(在任何一个实现中都没有调用)与重载 ==(这在任何一个片段中都不相关,因为重载是在编译时执行的,并且编译器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

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

于 2011-08-19T09:34:11.967 回答
5

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

这也正是这样object.ReferenceEquals做的:调用==object.

于 2011-08-19T09:32:56.927 回答
1

这是一个主要是化妆品。

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

于 2011-08-19T09:32:04.320 回答