当使用的值可以隐式转换为这些结构时,为什么我不能使用采用两个结构的重载 ==?
Why can't I use the overloaded == that takes two structs when the values used are implicitly convertable to these structs?
我注意到在应用 operator==
时,用户定义的隐式转换为 int
和用户定义的隐式转换为任意结构 MyStruct
的行为之间存在差异。
如果我有:
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;
}
然后编译以下代码:
{
var a = new IntA(3);
var b = new IntB(4);
bool equal = (a == b); // ok! converted to int and used int operator==
// ...
}
这使用我的用户定义 implicit operator int
用于 IntA
和 IntB
转换为 int
,然后调用 operator==(int, int)
.
但是,如果我有:
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;
}
那么下面的代码不编译:
{
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==?
// ...
}
我希望它和前面的例子一样,并使用我的用户定义 implicit operator MyStruct
转换为 MyStruct
,然后调用 operator==(MyStruct, MyStruct)
.
它不会那样做。为什么不?从编译器的角度来看,这两种情况有何不同?
答案在语言规范中。重点是我的。
C# Language Specification 7.3.4
An operation of the form x op y, where op is an overloadable binary
operator, x is an expression of type X, and y is an expression of type
Y, is processed as follows:
- The set of candidate user-defined operators provided by X and Y for the operation operator op(x, y) is determined. The set consists of
the union of the candidate operators provided by X and the candidate
operators provided by Y, each determined using the rules of §7.3.5.
If X and Y are the same type, or if X and Y are derived from a common
base type, then shared candidate operators only occur in the combined
set once.
- If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators
for the operation. The predefined implementations of a given
operator are specified in the description of the operator (§7.8
through §7.12). For predefined enum and delegate operators, the
only operators considered are those defined by an enum or delegate
type that is the binding-time type of one of the operands.
- The overload resolution rules of §7.5.3 are applied to the 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 resolution process. If overload resolution fails to select a
single best operator, a binding-time error occurs.
因此,如果没有初始匹配,它会将所有内部定义的 ==
运算符视为候选。由于 int
有一个,但 MyStruct
没有,您会看到不同的行为。
我注意到在应用 operator==
时,用户定义的隐式转换为 int
和用户定义的隐式转换为任意结构 MyStruct
的行为之间存在差异。
如果我有:
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;
}
然后编译以下代码:
{
var a = new IntA(3);
var b = new IntB(4);
bool equal = (a == b); // ok! converted to int and used int operator==
// ...
}
这使用我的用户定义 implicit operator int
用于 IntA
和 IntB
转换为 int
,然后调用 operator==(int, int)
.
但是,如果我有:
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;
}
那么下面的代码不编译:
{
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==?
// ...
}
我希望它和前面的例子一样,并使用我的用户定义 implicit operator MyStruct
转换为 MyStruct
,然后调用 operator==(MyStruct, MyStruct)
.
它不会那样做。为什么不?从编译器的角度来看,这两种情况有何不同?
答案在语言规范中。重点是我的。
C# Language Specification 7.3.4
An operation of the form x op y, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:
- The set of candidate user-defined operators provided by X and Y for the operation operator op(x, y) is determined. The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of §7.3.5. If X and Y are the same type, or if X and Y are derived from a common base type, then shared candidate operators only occur in the combined set once.
- If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators
for the operation. The predefined implementations of a given operator are specified in the description of the operator (§7.8 through §7.12). For predefined enum and delegate operators, the only operators considered are those defined by an enum or delegate type that is the binding-time type of one of the operands.- The overload resolution rules of §7.5.3 are applied to the 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 resolution process. If overload resolution fails to select a single best operator, a binding-time error occurs.
因此,如果没有初始匹配,它会将所有内部定义的 ==
运算符视为候选。由于 int
有一个,但 MyStruct
没有,您会看到不同的行为。