重载运算符的用户定义隐式转换';s的论点

本文关键字:用户 运算符 定义 重载 转换 | 更新日期: 2023-09-27 18:26:12

以下运算符重载在我的Term类中定义:

public static Term operator *(int c, Term t) {...}

这个类还定义了从VariableTerm:的隐式转换

public static implicit operator Term(Variable var) {...}

我想了解为什么以下内容没有编译:

static void Main(string[] args)
{
    Variable var = ...; // the details don't matter
    Console.WriteLine(2 * var); // var isn't implicitly converted to Term...
    Console.ReadKey();
}

编译器说:

运算符"*"不能应用于类型为"int"answers"OOSnake.Variable"的操作数

为什么没有找到我的operator *过载?

编辑:根据评论中的建议,这里有一个完整的小例子,它会重新产生错误:

namespace Temp
{
    class A { 
    }
    class B
    {
        public static implicit operator B(A a) { return new B(); }
        public static B operator *(int c, B b) { return new B(); }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(2 * new A());
        }
    }
}

重载运算符的用户定义隐式转换';s的论点

基本上,运算符重载解析不包括隐式用户定义转换,以便找到可能适用的运算符。

来自C#5规范第7.3.4节:

形式为x op y的运算,其中op是可重载的二进制运算符,x是类型为X的表达式,而y是类型为Y的表达式,处理如下:

  • 确定由XY为运算运算符op(x, y)提供的候选用户定义运算符的集合。该集合由X提供的候选算子和Y提供的候选操作符的并集组成,每个算子都使用§7.3.5的规则确定。如果XY是相同的类型,或者如果XY是从一个公共的基类型派生的,那么共享的候选运算符只在组合集中出现一次

7.3.5在搜索一组运算符时没有包含隐式用户定义转换。

请注意,如果在Variable类中声明了到Term的隐式转换,这也不会起作用——尽管指定和实现这一点更合理,因为编译器可以查看从操作数类型到其他类型的转换集,并将其用于重载解析。

然而,这只是一个寻找运营商的问题。编译器很乐意在考虑重载是否适用时执行隐式转换。例如,在您的情况下,如果您添加:

class A
{
    public static B operator *(A a, B b) { return new B(); }
}

那么这是有效的:

A a = new A();        
Console.WriteLine(a * a);
Console.WriteLine(2*var)不包含任何要将var转换为Term类型的提示。编译器看到int和乘法运算符以及"variable"类型的变量。

编辑:为了澄清,为了让你的例子发挥作用,编译器必须遍历范围中的所有类型,看看其中是否恰好有从类型"A"的隐式转换。

如果碰巧也有一个C类:

class C
{
    public static implicit operator C(A a) { return new A(); }
    public static B operator *(int i, C c) { return new C(); }
}

不知道会发生什么。

这就是编译器不这样做的原因:)

如果你想让你的例子发挥作用,你必须把把A转换为B的隐式操作符移到A类,如下所示:

namespace Temp
{
    class A
    {
        public static implicit operator B(A a) { return new B(); }
    }
    class B
    {
        public static B operator *(int c, B b) { return new B(); }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(2 * ((B)new A()));
        }
    }
}

但你不能使用这个2 * new A(),因为(Jon Skeet回答):

基本上,运算符重载解析不包括隐式用户定义转换,以便找到可能适用的运算符。

https://stackoverflow.com/a/34161798/815590