c# 7.2 默认表达式和等于(错误?)
c# 7.2 default expression and Equals (bug?)
我使用的是 Visual Studio 2017 版本 15.5.2 和 C# 版本 7.2。重点:
Color c = default; // or: c = default(Color); no difference
Debug.Print($"{c.Equals(default(Color))}"); // true
Debug.Print($"{c.Equals(default)}"); // false WHY?!
但是如果我使用 ValueTuple:
(string s, int i) t = default;
Debug.Print($"{t.Equals(default((string, int)))}"); // true
Debug.Print($"{t.Equals(default)}"); // true
应该是这样的吗?
这是Windows表格吗?
因为在 WinForms 中,System.Drawing.Color.Equals()
没有采用 Color
的重载。相反,它只有 the one from Object
. In WPF, System.Windows.Media.Color.Equals()
contains an overload that takes a Color
.
当 default
作为参数传递给 Color.Equals(Object)
时,传递的是 default(Object)
,因为编译器推断 Object
是基于其签名的类型。来自 docs:
The default
literal produces the same value as the equivalent default(T)
where T
is the inferred type.
显然,default(Color)
不等同于 default(Object)
,因为 Color
是值类型而 Object
是引用类型(默认为 null)。
ValueTuple.Equals()
,另一方面,takes another ValueTuple
,因此编译器可以毫不费力地将 default
的类型推断为 default(ValueTuple)
.
编辑:
从 .NET Core 2.0 开始,System.Drawing.Color.Equals()
确实有一个需要 Color
的重载。编译器可以毫不费力地将默认类型推断为 default(Color);因此,它现在 return 为真。
@fharreau 是正确的:System.Drawing.Color
没有实现 Equals(Color)
方法,因此 $"{t.Equals(default)}"
绑定到唯一可用的方法:Equals(Object)
。因此,default
解析为 default(Object)
或 null
.
如果您使用 WPF 中的 System.Windows.Media.Color
, 实现了 Equals(Color)
,那么您将看到预期的结果:
System.Windows.Media.Color c = default;
Console.WriteLine($"{c.Equals(default(System.Windows.Media.Color))}"); // true
Console.WriteLine($"{c.Equals(default)}"); // true
ValueTuple
还提供了一个 Equals
来与另一个元组进行比较,这就是您看到预期结果的原因。
不,这符合预期。
default
为参数或变量的类型或分配给它的诸如此类的东西提供默认值。
让我们看看这个:
Color c = Color.White;
bool b = c.Equals(x);
x
应该是什么类型?由于 Color
类型没有声明采用 Color
的 Equals
方法,唯一可用的方法是:
public class Object
{
public virtual bool Equals(object obj)
...
所以这里的 default
应该满足 object
的需要,而不是 Color
,因此你的代码实际上是这样的:
bool b = c.Equals(default(object));
与此相同:
bool b = c.Equals(null);
但等等,为什么这是真的?
bool b = c.Equals(default(Color));
?这是因为 Color
覆盖了 来自 object
、 或 的 Equals
方法,基本方法知道如何比较值类型,它仍然以 object
作为参数,因此您的其他语句:
bool b = c.Equals(default(Color));
实际上提供了一个Color
,而不是null
,这就是两者不同的原因。
此结果与文档相符,但第二个(元组)片段的文档并未说明您可能期望的内容。
Color.Equals() 方法接受类型为 Object
的参数。因此,您正在将默认颜色与默认对象进行比较。那些不一样,因此 false
结果。
ValueType.Equals() 有重载来接受 Object
和 ValueTuple
的参数。这里的文档很有趣... 带有 ValueTuple 参数的版本总是 returns true。对象版本 returns 如果参数是 ValueTuple,则为 true,否则为 false。换句话说,根据 Equals 方法,所有 ValueTuple 彼此相等,但不等于任何不是 ValueTuple 的值。
这里唯一的其他技巧是如何在此上下文中解释 default
关键字。我们可以在这里清楚地看到您正在获取默认的 ValueTuple,而不是默认的对象。我不是最新的 why 或 how 编译器能够从上下文中确定这一点,但是一旦你有了这个值很容易看出为什么在这种情况下会得到 true
结果。显然,重载解析会选择方法的 ValueTuple,它(再次)总是 returns true。
在第一个代码块中,.Equals()
方法来自基础 object
class,这意味着 default
将是 [=11= 的默认值] 而不是 Color
。这就是它 returns 错误的原因。
然而,元组 .Equals()
方法已被覆盖以采用相关类型,该函数的内部比较各个组件。从 docs 开始,如果满足以下条件,则认为 ValueTuple 相等:
- Its components are of the same types as those of the current instance.
- Its components are equal to those of the current instance. Equality is determined by the default equality comparer for each component.
System.Drawing.Color
结构不实现 IEquatable
而 ValueTuple
实现。
所以在第一种情况下编译器选择 Object.Equals
我使用的是 Visual Studio 2017 版本 15.5.2 和 C# 版本 7.2。重点:
Color c = default; // or: c = default(Color); no difference
Debug.Print($"{c.Equals(default(Color))}"); // true
Debug.Print($"{c.Equals(default)}"); // false WHY?!
但是如果我使用 ValueTuple:
(string s, int i) t = default;
Debug.Print($"{t.Equals(default((string, int)))}"); // true
Debug.Print($"{t.Equals(default)}"); // true
应该是这样的吗?
这是Windows表格吗?
因为在 WinForms 中,System.Drawing.Color.Equals()
没有采用 Color
的重载。相反,它只有 the one from Object
. In WPF, System.Windows.Media.Color.Equals()
contains an overload that takes a Color
.
当 default
作为参数传递给 Color.Equals(Object)
时,传递的是 default(Object)
,因为编译器推断 Object
是基于其签名的类型。来自 docs:
The
default
literal produces the same value as the equivalentdefault(T)
whereT
is the inferred type.
显然,default(Color)
不等同于 default(Object)
,因为 Color
是值类型而 Object
是引用类型(默认为 null)。
ValueTuple.Equals()
,另一方面,takes another ValueTuple
,因此编译器可以毫不费力地将 default
的类型推断为 default(ValueTuple)
.
编辑:
从 .NET Core 2.0 开始,System.Drawing.Color.Equals()
确实有一个需要 Color
的重载。编译器可以毫不费力地将默认类型推断为 default(Color);因此,它现在 return 为真。
@fharreau 是正确的:System.Drawing.Color
没有实现 Equals(Color)
方法,因此 $"{t.Equals(default)}"
绑定到唯一可用的方法:Equals(Object)
。因此,default
解析为 default(Object)
或 null
.
如果您使用 WPF 中的 System.Windows.Media.Color
, 实现了 Equals(Color)
,那么您将看到预期的结果:
System.Windows.Media.Color c = default;
Console.WriteLine($"{c.Equals(default(System.Windows.Media.Color))}"); // true
Console.WriteLine($"{c.Equals(default)}"); // true
ValueTuple
还提供了一个 Equals
来与另一个元组进行比较,这就是您看到预期结果的原因。
不,这符合预期。
default
为参数或变量的类型或分配给它的诸如此类的东西提供默认值。
让我们看看这个:
Color c = Color.White;
bool b = c.Equals(x);
x
应该是什么类型?由于 Color
类型没有声明采用 Color
的 Equals
方法,唯一可用的方法是:
public class Object
{
public virtual bool Equals(object obj)
...
所以这里的 default
应该满足 object
的需要,而不是 Color
,因此你的代码实际上是这样的:
bool b = c.Equals(default(object));
与此相同:
bool b = c.Equals(null);
但等等,为什么这是真的?
bool b = c.Equals(default(Color));
?这是因为 Color
覆盖了 来自 object
、 或 的 Equals
方法,基本方法知道如何比较值类型,它仍然以 object
作为参数,因此您的其他语句:
bool b = c.Equals(default(Color));
实际上提供了一个Color
,而不是null
,这就是两者不同的原因。
此结果与文档相符,但第二个(元组)片段的文档并未说明您可能期望的内容。
Color.Equals() 方法接受类型为 Object
的参数。因此,您正在将默认颜色与默认对象进行比较。那些不一样,因此 false
结果。
ValueType.Equals() 有重载来接受 Object
和 ValueTuple
的参数。这里的文档很有趣... 带有 ValueTuple 参数的版本总是 returns true。对象版本 returns 如果参数是 ValueTuple,则为 true,否则为 false。换句话说,根据 Equals 方法,所有 ValueTuple 彼此相等,但不等于任何不是 ValueTuple 的值。
这里唯一的其他技巧是如何在此上下文中解释 default
关键字。我们可以在这里清楚地看到您正在获取默认的 ValueTuple,而不是默认的对象。我不是最新的 why 或 how 编译器能够从上下文中确定这一点,但是一旦你有了这个值很容易看出为什么在这种情况下会得到 true
结果。显然,重载解析会选择方法的 ValueTuple,它(再次)总是 returns true。
在第一个代码块中,.Equals()
方法来自基础 object
class,这意味着 default
将是 [=11= 的默认值] 而不是 Color
。这就是它 returns 错误的原因。
然而,元组 .Equals()
方法已被覆盖以采用相关类型,该函数的内部比较各个组件。从 docs 开始,如果满足以下条件,则认为 ValueTuple 相等:
- Its components are of the same types as those of the current instance.
- Its components are equal to those of the current instance. Equality is determined by the default equality comparer for each component.
System.Drawing.Color
结构不实现 IEquatable
而 ValueTuple
实现。
所以在第一种情况下编译器选择 Object.Equals