重载运算符的用户定义隐式转换';s的论点
本文关键字:用户 运算符 定义 重载 转换 | 更新日期: 2023-09-27 18:26:12
以下运算符重载在我的Term
类中定义:
public static Term operator *(int c, Term t) {...}
这个类还定义了从Variable
到Term
:的隐式转换
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());
}
}
}
基本上,运算符重载解析不包括隐式用户定义转换,以便找到可能适用的运算符。
来自C#5规范第7.3.4节:
形式为
x op y
的运算,其中op
是可重载的二进制运算符,x
是类型为X
的表达式,而y
是类型为Y
的表达式,处理如下:
- 确定由
X
和Y
为运算运算符op(x, y)
提供的候选用户定义运算符的集合。该集合由X提供的候选算子和Y
提供的候选操作符的并集组成,每个算子都使用§7.3.5的规则确定。如果X
和Y
是相同的类型,或者如果X
和Y
是从一个公共的基类型派生的,那么共享的候选运算符只在组合集中出现一次
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);
编辑:为了澄清,为了让你的例子发挥作用,编译器必须遍历范围中的所有类型,看看其中是否恰好有从类型"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