Compilation error when the same conversion exists twice

In C #, why are there no compilation errors when the โ€œsameโ€ user transform 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 get a compilation error. Let's say I add the following to Main () and try to compile:

 A a = new A(); B b = ((B)a); 

I will get the following:

Ambiguous conversions defined by the user 'TestConversionOverloading.A.explicit operator TestConversionOverloading.B (TestConversionOverloading.A)'
and the 'TestConversionOverloading.B.explicit statement TestConversionOverloading.B (TestConversionOverloading.A)'
when converting from 'TestConversionOverloading.A' to 'TestConversionOverloading.B'

So why not give an error directly from the definition? Could there be a way to use the transform?

+4
source share
4 answers

I would not ponder why it makes sense for this language, but if you control both classes, the obvious solution is to get rid of one of the operators.

If you canโ€™t, here is a way to disambiguate using reflection.

First create a delegate that communicates with the intended statement:

 // Picks the conversion operator declared in class A. var method = typeof(A).GetMethod("op_Explicit", new[] { typeof(A) }); var converter = (Func<A, B>)Delegate.CreateDelegate(typeof(Func<A, B>), method); 

And then use the delegate as:

 A a = ... B b = converter(a); 
+3
source

According to the specification , this is the expected behavior.

The heavy compression of the source is what happens in this case: the compiler will find all the operators that could convert A to B into both class definitions . This will require A operator B(A a) and B operator B(A a) . Then,

If such an operator does not exist or more than one such operator exists, then the conversion is ambiguous and a compile-time error occurs.

So why not give an error directly from the definition? Because both definitions are in order, but this is their use, which is why the problem arises.

Could there be a way to use conversion? I do not see an easy way to do this. I am thinking of going around the compiler by emitting IL manually. Thus, I think you can instruct the program to use one operator or another. Not sure if this is entirely possible. A tool like Reflector can help.

While there is some beauty using operator-based conversions, either one of the classes will lose one operator, or you can change ToA(A a) and FromA(A a) syntax to conversions based on a constructor. Or maybe Eric Lippert could enlighten us with some language cleverness!

+2
source

Look at the IL code generated by the "open static implicit statement B (A a)" line of code:

 .method public hidebysig specialname static class TestConversionOverloading.B op_Explicit(class TestConversionOverloading.A a) cil managed 

So, here is the answer to the first question: Implicit / explicit conversion operators are syntactic sugar. In MSIL, they look like regular methods (and they are). There is nothing criminal if two different classes have methods with the same signature, because they do not violate anything. Although the conversion operator call cannot be compiled in this case. And, as already mentioned, you can use reflection to get MethodInfo of any of the methods.

+1
source

Remember that one of the conflicting conversions may be common and may be useful for other combinations of common parameters.

You can even have conflicting conversions defined in the SAME class:

 class C<T> { implicit operator int() { return 0; } implicit operator T() { return default(T); } } C<int> c; int i = c; 

If the compiler complains about this, you will lose the ability of C<string> convert to both string and int .

0
source

Source: https://habr.com/ru/post/1340887/


All Articles