当所使用的值可以隐式地转换为两个结构体时,为什么不能使用'

本文关键字:结构体 两个 不能 为什么 转换 | 更新日期: 2023-09-27 18:06:18

我注意到在应用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 intIntAIntB转换为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#语言规范7.3.4

x op y形式的操作,其中op是可重载的二进制数操作符,x是类型x的表达式,y是类型x的表达式Y,处理如下:

  • 确定X和Y为操作符op(X, Y)提供的候选用户定义操作符集。这个集合包括由X提供的候选操作符和候选操作符的并集由Y提供的操作符,每个操作符使用§7.3.5的规则确定。如果X和Y是相同的类型,或者如果X和Y是由公共派生的,则共享候选操作符只出现在组合的设置一次。
  • 如果候选用户定义操作符集合不为空,则此集合成为该操作的候选操作符集合。否则,预定义的二进制操作符op实现,包括其提升形式,将成为候选操作符
    的集合。
    操作。的预定义实现操作符在操作符的描述中指定(§7.8)通过§7.12)。对于预定义的枚举和委托操作符只考虑由枚举或委托定义的操作符操作数的绑定时间类型。
  • §7.5.3的重载解析规则应用于候选操作符的集合,以选择相对于的最佳操作符参数列表(x, y),此操作符成为过载解析过程。如果重载解析失败,请选择

所以,如果没有初始匹配,它会考虑所有内部定义的==操作符作为候选。由于int有一个,而MyStruct没有,所以您会看到不同的行为。