4

我正在使用 Visual Studion 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

它应该是这样的吗?

4

6 回答 6

6

这是 Windows 窗体吗?

因为在 WinForms 中,System.Drawing.Color.Equals()没有需要Color. 相反,它只有一个 fromObject。在 WPF 中,System.Windows.Media.Color.Equals()包含一个采用Color.

default作为参数传递给Color.Equals(Object)时,传递的是default(Object)因为编译器Object根据其签名推断为类型。从文档

文字产生与推断类型default相同的值。default(T)T

显然,default(Color)不等价于default(Object),因为Color它是一个值类型并且Object是一个引用类型(默认为 null)。

ValueTuple.Equals(),另一方面,需要另一个ValueTuple,因此编译器可以轻松推断defaultas的类型default(ValueTuple)

编辑:

从 .NET Core 2.0 开始,System.Drawing.Color.Equals()确实有一个需要Color. 编译器可以毫不费力地将默认类型推断为 default(Color); 因此,它现在将返回 true。

于 2018-01-16T17:33:31.087 回答
5

@fharreau 是正确的:System.Drawing.Color没有实现Equals(Color)方法,因此$"{t.Equals(default)}"绑定到唯一可用的方法:Equals(Object)。因此,default解析为default(Object)or null

如果您System.Windows.Media.Color从 WPF 中使用,它确实实现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与另一个元组进行比较的方法,这就是您看到预期结果的原因。

于 2018-01-16T17:34:02.790 回答
5

在第一个代码块中,.Equals()方法来自基object类,这意味着将是and notdefault的默认值。这就是它返回 false 的原因。objectColor

然而,元组.Equals()方法已被覆盖以采用相关类型,该函数的内部比较各个组件。从docs来看,一个 ValueTuple 被认为是相等的,如果:

  • 它的组件与当前实例的组件类型相同。
  • 它的组件与当前实例的组件相同。相等性由每个组件的默认相等比较器确定。
于 2018-01-16T17:35:04.977 回答
4

不,这和预期的一样。

default为参数或变量的类型或分配给它的东西提供默认值。

那么让我们看看这个:

Color c = Color.White;
bool b = c.Equals(x);

x预计是什么类型?由于该Color类型没有声明采用的Equals方法Color,因此唯一可用的方法是:

public class Object
{
    public virtual bool Equals(object obj)
    ...

所以default这里将有望满足object, not的需要Color,因此您的代码实际上是这样的:

bool b = c.Equals(default(object));

这与此相同:

bool b = c.Equals(null);

但是等等,为什么这是真的?

bool b = c.Equals(default(Color));

? 那是因为Color 覆盖Equalsfrom 的方法object或者基方法知道如何比较值类型,它仍然object作为参数,因此你的其他语句:

bool b = c.Equals(default(Color));

实际上提供了 aColor和 not null,这就是两者不同的原因。

于 2018-01-16T17:34:22.493 回答
3

此结果与文档匹配,但第二个(元组)片段的文档并未说明您的预期。

Color.Equals ()方法接受 type 的参数Object。因此,您将默认颜色与默认对象进行比较。那些不一样,因此false结果。

ValueType.Equals()具有接受Object和的参数的重载ValueTuple。这里的文档很有趣……带有 ValueTuple 参数的版本总是返回 true。如果参数是 ValueTuple,则 Object 版本返回 true,否则返回 false。换句话说,根据 Equals 方法,所有的 ValueTuple 彼此相等,但不等于任何不是 ValueTuple 的东西。

这里唯一的另一个技巧是default在这种情况下如何解释关键字。我们可以在这里清楚地看到,您得到的是一个默认的 ValueTuple,而不是一个默认的 Object。我不知道编译器究竟为什么如何能够从上下文中确定这一点的最新信息,但是一旦你为参数设置了该值,就很容易看出为什么true在这种情况下会得到结果。显然,重载决议将选择该方法的 ValueTuple,它(再次)总是返回 true。

于 2018-01-16T17:34:53.657 回答
0

System.Drawing.Color结构不实现IEquatable,而ValueTuple实现。

所以在第一种情况下编译器选择Object.Equals

于 2018-01-16T17:39:19.493 回答