为什么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
重载,并可能使代码更清晰。
对此有何不妥?应该有一些。
答案 0 :(得分: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
将是一个字符串 - 因为这取决于调用代码 - 并且重载解析仅在{em>时执行{编译{1}} 。因此,它使用的是运算符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
。
答案 1 :(得分:5)
==
运算符在编译时解析,而不是运行时,并且由于T
是通用的,编译器将使用==
本身提供的object
的实现,检查参考相等性。
这正是object.ReferenceEquals
所做的:调用==
提供的object
实现。
答案 2 :(得分:1)
这主要是化妆品。
obj == null
将执行引用检查并返回,如果参数为null且未在Equals
中覆盖,T
将会{{1}}。当一个参数为空时,它需要一个非常不稳定/恶意的实现来返回true。