Why can't I use overloaded ==, which takes two structures when used values ​​are implicitly converted to these structures?

I noticed a difference between the behavior of a custom implicit conversion to int and a user-defined implicit conversion to an arbitrary MyStruct structure when using operator== .

If I have:

 public struct IntA { public IntA(int value) { m_value = value; } public static implicit operator int(IntA a) { return a.m_value; } private int m_value; } public struct IntB { public IntB(int value) { m_value = value; } public static implicit operator int(IntB b) { return b.m_value; } private int m_value; } 

Then the following code compiles:

 { var a = new IntA(3); var b = new IntB(4); bool equal = (a == b); // ok! converted to int and used int operator== // ... } 

This uses my custom implicit operator int for IntA and IntB to convert to int , and then calls operator==(int, int) .

However, if I have:

 public struct MyStruct { public MyStruct(int value) { m_value = value; } public static bool operator==(MyStruct lhs, MyStruct rhs) { return lhs.m_value == rhs.m_value; } public static bool operator!=(MyStruct lhs, MyStruct rhs) { return lhs.m_value != rhs.m_value; } private int m_value; } public struct MyStructA { public MyStructA(int value) { m_value = new MyStruct(value); } public static implicit operator MyStruct(MyStructA a) { return a.m_value; } private MyStruct m_value; } public struct MyStructB { public MyStructB(int value) { m_value = new MyStruct(value); } public static implicit operator MyStruct(MyStructB b) { return b.m_value; } private MyStruct m_value; } 

Then the following code does not compile:

 { var a = new MyStructA(3); var b = new MyStructB(4); bool equal = (a == b); // compile error: Operator `==' cannot be applied to operands of type `MyStructA' and `MyStructB' // why can't it convert to MyStruct and use that operator==? // ... } 

I expected it to do the same as in the previous example, and use my custom implicit operator MyStruct to convert to MyStruct , and then call operator==(MyStruct, MyStruct) .

This is not true. Why not? What is the difference between the two cases from a compiler point of view?

+4
source share
1 answer

The answer is in the language specification. The emphasis is mine.

C # 7.3.4 language specification

An operation of the form x op y, where op is an overloaded binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:

  • A set of user defined user defined operators is provided, provided by X and Y for the op (x, y) operator. The set consists of a combination of candidate operators provided by X and candidate operators provided by Y, each determined using the rules of clause 7.3.5. If X and Y are the same type or X and Y are derived from a common base type, then common candidate operators are found only in a combined set once.
  • If the set of user-defined user-defined operators is not empty, this becomes the set of candidate operators for the operation. Otherwise, the predefined binary operational operations, including their withdrawn forms, become a set of candidate operators
    for operation . Predefined implementations of this operator are specified in the operator description (§7.8 through § 7.12). For the predefined enumeration operators and delegates, only the operators considered are those defined by the enumeration or delegate type, which is the type of binding time of one of the operands.
  • The rules for overload resolution in §7.5.3 apply to a set of candidate operators to select the best operator with respect to the argument list (x, y), and this operator becomes the result of the overload. If overload resolution does not allow you to select one best operator, a binding time error occurs.

So, if there is no initial match, all internally defined == operators are considered as candidates. And since there is one for int , but not MyStruct , you see a different behavior.

+2
source

All Articles