动态生成方法(如IL发射)中能否触发隐式转换运算符?
问题描述
定义如下C#类:
public class A { } public class B { public static implicit operator A(B value) { return new A(); } }
编译时,以下两种转换代码均可正常执行:
// 隐式转换写法 A a = new B();
// 显式转换写法 B b = new B(); A a = (A)b;
但通过DynamicMethod动态生成IL代码执行转换时,抛出InvalidCastException:
DynamicMethod method = new DynamicMethod("", typeof(A), new [] { typeof(B) }); ILGenerator gen = method.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Castclass, typeof(A)); // 使用了强制类型转换的IL指令 gen.Emit(OpCodes.Ret); Func<B, A> fn = (Func<B, A>)method.CreateDelegate(typeof(Func<B, A>)); A instance = fn(new B());
报错信息:
InvalidCastException: Unable to cast object of type 'B' to type 'A'.
疑问
隐式转换是否仅为编译时语法糖,运行时常规转换无法识别?求确认及解决方法,因使用的第三方IL生成库未自动处理该转换。
回答
确认:自定义隐式/显式转换属于编译时语法糖
C#中的自定义隐式、显式转换运算符,本质就是编译期的语法糖。编译器遇到A a = new B()或者(A)b这类写法时,会自动将代码替换为对public static implicit operator A(B value)这个静态方法的调用,而非生成类型强制转换的IL指令。
你在动态IL中使用的OpCodes.Castclass是运行时原生类型强制转换指令,它只会检查对象实际类型与目标类型的继承/接口实现关系,完全不会识别自定义转换运算符——二者属于完全不同的机制。
解决方法:在IL中直接调用自定义转换运算符的静态方法
要实现正确转换,需要在IL里生成调用B类的implicit operator A(B)静态方法的指令,替换掉Castclass指令。修改后的代码如下:
DynamicMethod method = new DynamicMethod("", typeof(A), new [] { typeof(B) }); ILGenerator gen = method.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); // 调用B类的隐式转换静态方法,替代Castclass指令 gen.Emit(OpCodes.Call, typeof(B).GetMethod("op_Implicit", new[] { typeof(B) })); gen.Emit(OpCodes.Ret); Func<B, A> fn = (Func<B, A>)method.CreateDelegate(typeof(Func<B, A>)); A instance = fn(new B());
补充说明
- 如果是自定义显式转换运算符(
public static explicit operator A(B value)),对应的静态方法名为op_Explicit,调用时替换为该方法名即可。 - 若不确定转换类型,可通过反射遍历目标类型的静态方法,筛选出返回类型为目标类型、参数为源类型的
op_Implicit或op_Explicit方法。
内容的提问来源于stack exchange,提问作者tigrou
相关产品推荐
相关产品推荐

