C # compiler error? Why is this implicit user transformation not compiling?

Given the following structure:

public struct Foo<T> { public Foo(T obj) { } public static implicit operator Foo<T>(T input) { return new Foo<T>(input); } } 

This code compiles:

 private Foo<ICloneable> MakeFoo() { string c = "hello"; return c; // Success: string is ICloneable, ICloneable implicitly converted to Foo<ICloneable> } 

But this code does not compile - why?

 private Foo<ICloneable> MakeFoo() { ICloneable c = "hello"; return c; // Error: ICloneable can't be converted to Foo<ICloneable>. WTH? } 
+32
compiler-construction c #
Jul 30 '09 at 19:29
source share
2 answers

Implicit user conversions do not seem to work when one of the types is an interface. From C # specs:




6.4.1 Allowed custom conversions

C # allows only specific user conversions to be declared. In particular, it is not possible to override an existing implicit or explicit conversion. For a given type of source S and target type T, if S or T are NULL types, let S0 and T0 belong to their base types, otherwise S0 and T0 are equal to S and T, respectively. A class or structure is allowed to declare a conversion from source type S to destination type T only if all of the following values ​​are true:

  • S0 and T0 are different types.
  • Either S0 or T0 is the type of class or structure in which the operator is declared.
  • Neither S0 nor T0 are type interfaces .
  • Excluding custom conversions, the transform does not exist from S to T or from T to S.



In your first method, both types are not interface types, so custom implicit conversion works.

The specifications are not very clear, but it seems to me that if one of the types is associated with an interface type, the compiler does not even try to find any custom implicit conversions.

+30
Jul 30 '09 at 19:49
source share

(Following the comments of the accepted answer.)

Yes, this is a very, very confusing part of the specification. The whole bit about the "spanning types" in particular is deeply corrupt. I’ve been trying for several years to find the time to completely rewrite this entire section into something more consistent, but there has never been a high enough priority.

In fact, we have a contradiction; we say that there are no user implicit conversions involving interfaces, but it is clear that this is not true in this case; there is a custom implicit conversion from IC to Foo<IC> , demonstrated by the fact that the string goes to Foo<IC> through this conversion.

What we really need to emphasize better is the line you quoted:

In particular, it is not possible to override an existing implicit or explicit conversion.

What motivates it all; the desire to not let you ever think that you are executing a type test that preserves the view when you are actually calling the user method. Consider, for example, this variation:

 interface IBar {} interface IFoo : IBar {} class Foo<T> : IFoo { public static explicit operator Foo<T>(T input) { whatever } } class Blah : Foo<IBar> {} ... IBar bar = new Blah(); Foo<IBar> foo = (Foo<IBar>)bar; 

Now, does this cause an explicit user-defined transformation or not? The object is indeed derived from Foo, so you hope this does not happen; it should be a simple type test and reference job, not a call to a helper method. Casting the value of an interface is always considered a type test, since it is almost always possible that an object really has this type and really implements this interface. We do not want to deny you the opportunity to make a cheap transformation that preserves the view.

+24
Jul 30 '09 at 21:40
source share



All Articles