'c# 7.2 default expression and Equals (bug?)
I'm using Visual Studion 2017 version 15.5.2, and C# version 7.2. To the point:
Color c = default; // or: c = default(Color); no difference
Debug.Print($"{c.Equals(default(Color))}"); // true
Debug.Print($"{c.Equals(default)}"); // false WHY?!
But if I use ValueTuple:
(string s, int i) t = default;
Debug.Print($"{t.Equals(default((string, int)))}"); // true
Debug.Print($"{t.Equals(default)}"); // true
Is it supposed to be like this?
Solution 1:[1]
@fharreau is correct: System.Drawing.Color does not implement an Equals(Color) method, so $"{t.Equals(default)}" binds to the only method available: Equals(Object). Thus, default resolves to default(Object) or null.
If you use System.Windows.Media.Color from WPF, which does implement Equals(Color), then you'll see the expected results:
System.Windows.Media.Color c = default;
Console.WriteLine($"{c.Equals(default(System.Windows.Media.Color))}"); // true
Console.WriteLine($"{c.Equals(default)}"); // true
ValueTuple also provides an Equals to compare against another tuple, which is why you saw the expected result.
Solution 2:[2]
In the first code block, the .Equals() method comes from the base object class, meaning the default will be the default value for object and not Color. This is why it returns false.
The tuple .Equals() method however has been overriden to take the relevant type, the internals of that function compare the individual components. From the docs, a ValueTuple is considered equal if:
- 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.
Solution 3:[3]
No, this is as expected.
default provides the default value for the type of parameter or variable or whatnot it is assigned to.
So let's look at this:
Color c = Color.White;
bool b = c.Equals(x);
What type is x expected to be? since the Color type does not declare a Equals method that takes Color, the only method available is this:
public class Object
{
public virtual bool Equals(object obj)
...
So the default here will be expected to fulfill the need of object, not Color, hence your code is actually this:
bool b = c.Equals(default(object));
which is the same as this:
bool b = c.Equals(null);
But hang on, why then is this true?
bool b = c.Equals(default(Color));
? That is because Color overrides the Equals method from object, or the base method knows how to compare value types, that still takes object as parameter, and thus your other statement:
bool b = c.Equals(default(Color));
actually provides a Color, and not null, and that's why the two are different.
Solution 4:[4]
This result matches the documentation, but the documentation for the second (Tuple) snippet doesn't say what you might expect.
The Color.Equals() method accepts an argument of type Object. So you're comparing the default color to the default Object. Those are not the same, hence the false result.
ValueType.Equals() has overloads to accept arguments for both Object and ValueTuple. The documentation here is interesting... the version with the ValueTuple argument always returns true. The Object version returns true if the argument is a ValueTuple, or false otherwise. In other words, according to the Equals method, all ValueTuples are equal to each other, but not equal to anything that isn't a ValueTuple.
The only other trick here is how the default keyword is interpreted in this context. We can clearly see here that you're getting a default ValueTuple, rather than a default Object. I'm not up to date on exactly why or how the compiler is able to determine this from the context, but once you have that value for the argument it's easy to see why you get the true result in this case. Clearly overload resolution would then choose the ValueTuple of the method, which (again) always returns true.
Solution 5:[5]
System.Drawing.Color structure does not implement IEquatable whereas ValueTuple does.
So in first case compiler selects Object.Equals
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Mike Strobel |
| Solution 2 | DavidG |
| Solution 3 | Lasse V. Karlsen |
| Solution 4 | |
| Solution 5 | Pavel Voronin |
