当“相同”时不会出现编译错误。用户定义的转换存在两次
在 C# 中,为什么当“相同”的用户定义转换存在两次时没有编译错误? (一次在源类中,一次在目标类中?)
例如,如果我尝试编译以下代码,则不会出现编译错误:
namespace TestConversionOverloading
{
public class A
{
public int value = 1;
public static explicit operator B(A a)
{
B b = new B();
b.value = a.value + 6;
return b;
}
}
public class B
{
public int value = 2;
public static explicit operator B(A a)
{
B newB = new B();
newB.value = a.value;
return newB;
}
}
public class program
{
public static void Main() {}
}
}
但是,如果我尝试将 A 显式转换为 B,我会这样做 出现编译错误。假设我将以下内容添加到 Main() 并尝试编译:
A a = new A();
B b = ((B)a);
我将得到以下内容:
用户定义的转化不明确 'TestConversionOverloading.A.显式运算符 TestConversionOverloading.B(TestConversionOverloading.A)'
和 'TestConversionOverloading.B.explicit 操作员 TestConversionOverloading.B(TestConversionOverloading.A)'
从“TestConversionOverloading.A”转换为“TestConversionOverloading.B”时
那么为什么不直接从定义中给出错误呢?有没有办法使用这两种转换?
In C#, why are there no compilation errors when the "same" user-defined conversion exists twice? (once in the source class and once in the target class?)
For example, if I try to compile the following code I get no compilation errors:
namespace TestConversionOverloading
{
public class A
{
public int value = 1;
public static explicit operator B(A a)
{
B b = new B();
b.value = a.value + 6;
return b;
}
}
public class B
{
public int value = 2;
public static explicit operator B(A a)
{
B newB = new B();
newB.value = a.value;
return newB;
}
}
public class program
{
public static void Main() {}
}
}
However, if I try to explicitly convert A to B, I do get a compilation error. Say I add the following to Main() and try to compile:
A a = new A();
B b = ((B)a);
I'll get the following:
Ambiguous user defined conversions
'TestConversionOverloading.A.explicit operator TestConversionOverloading.B(TestConversionOverloading.A)'
and
'TestConversionOverloading.B.explicit
operator
TestConversionOverloading.B(TestConversionOverloading.A)'
when converting from 'TestConversionOverloading.A' to 'TestConversionOverloading.B'
So why not give an error straight from definition? Could there be a way to use either conversion?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不会推测为什么语言允许这样做是有意义的,但如果您控制这两个类,那么明显的解决方案是摆脱其中一个运算符。
如果你不能,这里有一种使用反射来消除歧义的方法。
首先,创建一个绑定到预期运算符的委托:
然后将该委托用作:
I wouldn't speculate on why it makes sense for the language to allow this, but if you are in control of both classes, the obvious solution is to get rid of one of the operators.
If you can't, here's a way to disambiguate using reflection.
First, create a delegate that binds to the intended operator:
And then use the delegate as:
根据规范,这是预期的行为。
大量压缩原始文本,在这种情况下会发生以下情况:编译器将在两个类定义中找到所有可以将 A 转换为 B 的运算符。这将招募
A 运算符 B(A a)
和B 运算符 B(A a)
。然后,那么为什么不直接从定义中给出错误呢?因为这两个定义都可以,但正是它们的使用导致了问题的出现。
有没有办法使用这两种转换?我没有看到一个简单的方法来做到这一点。我正在考虑绕过编译器,手动发出 IL。这样我认为您可以指示程序使用一个运算符或另一个运算符。但不确定这是否完全可行。像 Reflector 这样的工具可以提供帮助。
虽然使用基于运算符的转换有一些优点,但其中一个类将丢失一个运算符,或者您可以更改为基于构造函数的转换或更简单的语法
ToA(A a)
和FromA(A a)
。或者也许埃里克·利珀特(Eric Lippert)可以用一些语言智慧来启发我们!According to the spec, this is the expected behavior.
Heavily compressing the original text, here's what happens in this case: the compiler will find all operators that could convert A to B in both class definitions. This would enlist
A operator B(A a)
andB operator B(A a)
. Then,So why not give an error straight from definition? Because both definitions are OK, but it's their use that makes the problem arise.
Could there be a way to use either conversion? I don't see an easy way to do this. I'm thinking of bypassing the compiler, emitting IL by hand. That way I think you can instruct the program to use one operator or the other. Not sure if this is entirely feasible, though. A tool like Reflector could help.
While there's some beauty using operator-based conversions, either one of the classes will lose one operator, or you could change to constructor-based conversions or a more straightforward syntax of
ToA(A a)
andFromA(A a)
. Or maybe Eric Lippert could enlighten us with some language cleverness!看看每个“public static 隐式运算符 B(A a)”代码行生成的 IL 代码:
所以这是第一个问题的答案:隐式/显式转换运算符是语法糖。在 MSIL 中,它们看起来像常用方法(而且确实如此)。当两个不同的类具有具有相同签名的方法时,不存在任何犯罪行为,因为它不违反任何规定。尽管在这种情况下无法编译转换运算符调用。
正如前面提到的,您可以使用反射来获取任一方法的 MethodInfo。
Look at the IL code generated per "public static implicit operator B(A a)" code line:
So here is the answer on the first question: Implicit/explicit convertion operators are syntactic sugar. In MSIL they are look like usual methods (and they are). There is nothing criminal when two different classes have methods with identical signature as it does not violate anything. Though conversion operator call cannot be compiled in this case.
And as it was mentioned you can use reflection to get MethodInfo of either method.
请记住,冲突的转换之一可能是通用的,并且对于通用参数的其他组合可能有用。
您甚至可以在同一个类中定义冲突的转换:
如果编译器抱怨这一点,您将失去
C
转换为string
和int
。Remember that one of the conflicting conversions could be generic, and could be useful for other combinations of generic parameters.
You can even have conflicting conversions defined in the SAME class:
If the compiler complained about this, you'd lose the ability for
C<string>
to convert to bothstring
andint
.