用户定义的重载运算符参数

时间:2015-12-08 16:56:39

标签: c#

我的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'类型的操作数和' 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());
        }
    }
}

3 个答案:

答案 0 :(得分:4)

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

来自C#5规范的第7.3.4节:

  

x op y形式的操作,其中op是一个可重载的二元运算符,xX类型的表达式,y是一个类型Y的表达式按如下方式处理:

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

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

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

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

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

然后这是有效的:

A a = new A();        
Console.WriteLine(a * a);

答案 1 :(得分:1)

Console.WriteLine(2 * var)不包含您希望将var转换为Term类型的任何提示。编译器会看到int和multiplication运算符以及“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(); }
}

不知道会发生什么。

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

答案 2 :(得分:0)

如果你想让你的例子起作用,你必须将将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