-2

I have have the following classes A and B:

public class A 
{
}
    
public class B  
{
    public static implicit operator A(B value)
    {
        return new A();
    } 
}

As expected, the following code compiles and runs fine (no exceptions):

A a = new B();

Same for:

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

However, if I create a method that does similar cast at runtime (by emitting IL) it fails :

DynamicMethod method = new DynamicMethod("", typeof(A), new [] { typeof(B) });
ILGenerator gen = method.GetILGenerator();

gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Castclass, typeof(A)); //actual cast
gen.Emit(OpCodes.Ret);    
Func<B, A> fn = (Func<B, A>)method.CreateDelegate(typeof(Func<B, A>));

A instance = fn(new B());

This is supposed to be the equivalent of (but it's not):

Func<B, A> fn = x => (A)x;

Here is what I got :

InvalidCastException: Unable to cast object of type 'B' to type 'A'.

It looks like implicit cast is something purely resolved at compile time (some kind of synthetic sugar) and the regular cast (that looks through types hierarchy and checks it cast can be made) is not aware of it. Can somebody confirm it ?

Is there a workaround ? I ask this because I use a library (not written by me) that maps some types using generated code (IL). I expected implicit casts to work (be called automatically by the library) but it does not.

Charlieface
  • 52,284
  • 6
  • 19
  • 43
tigrou
  • 4,236
  • 5
  • 33
  • 59
  • What does the IL for the code that works look like? – Flydog57 Mar 16 '23 at 15:26
  • 6
    The answer to any question of the form "What IL do I need to emit to be equivalent to [compliable C# code]" is "compile that code and see what IL is generated. – Servy Mar 16 '23 at 15:28
  • 1
    [Representation and Identity](https://ericlippert.com/2009/03/03/representation-and-identity/), on casting: "The attentive reader will have noticed that these are opposites. A neat trick, to have an operator which means two contradictory things, don’t you think?" – Damien_The_Unbeliever Mar 16 '23 at 15:31
  • 1
    To your edit, "This is the equivalent of:" that's just factually not true. We know you know this, because you ran the code and it behaves differently than the C# code below it does. So it's not equivalent. Again, to see IL that *is* equivalent, compile the code. – Servy Mar 16 '23 at 15:48
  • @Servy : I added this because someone asked "What does the IL for the code that works look like?". So it's not the equivalent of IL code posted above, but rather what it is supposed to do. – tigrou Mar 16 '23 at 15:54

1 Answers1

1

You need the following

gen.Emit(OpCodes.Call, typeof(B).GetMethod("op_Implicit"));

Implicit casts are operators, which are compiled as special static methods.

Charlieface
  • 52,284
  • 6
  • 19
  • 43