带有反射发射的显式运算符

时间:2018-10-04 13:43:56

标签: c#

我有一个类,需要使用反射发射即时生成。我希望能够将此类的实例显式转换为在编译时定义的类型。

我试图重载使用反射发射定义的类型中的显式运算符,以实现此目的,但是在进行转换时会抛出错误:

  

System.InvalidCastException:'无法将类型为'MySourceClass'的对象转换为类型为'ExplictOperatorTest.MyTargetClass'。'

这就是我使用反射发射定义显式运算符的方式:

private static void CreateExplicitOp(TypeBuilder typeBuilder, MethodInfo conversionMethod)
{
    var myType = typeBuilder.AsType();
    var method = typeBuilder.DefineMethod(
        "op_Explicit",
        MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static,
        typeof(MyTargetClass),
        new Type[] { myType });

    var ilGenerator = method.GetILGenerator();
    var emitRecordLocal = ilGenerator.DeclareLocal(typeof(MyTargetClass));
    ilGenerator.Emit(OpCodes.Nop);
    ilGenerator.Emit(OpCodes.Ldarg_0);
    ilGenerator.EmitCall(OpCodes.Callvirt, conversionMethod, new Type[] { });
    ilGenerator.Emit(OpCodes.Stloc_0);
    ilGenerator.Emit(OpCodes.Ldloc_0);
    ilGenerator.Emit(OpCodes.Ret);
}

这就是我想要做的没有错误的事情:

var mySourceTypeType = CreateMyType();
var mySourceTypeInstance = Activator.CreateInstance(mySourceTypeType);
// System.InvalidCastException: 'Unable to cast object of type 'MySourceClass' to type 'ExplictOperatorTest.MyTargetClass'.'
var myTarget = (MyTargetClass)mySourceTypeInstance;

我已经将我在IL中的显式声明与从等效的预定义类型生成的声明进行了比较,它看起来几乎相同,并且如果我直接调用op_Explicit方法,它将起作用。

我的问题是:我想做什么可能?如果是这样,我哪里出问题了?

完整复制: https://dotnetfiddle.net/1AgRuJ

1 个答案:

答案 0 :(得分:3)

问题在于mySourceTypeInstance编译时间类型为object,因为这是Activator.CreateInstance的返回类型。这意味着您处于这样的情况:

object obj = new XElement("foo", "text content");
string text = (string) obj; // Throws InvalidCastException

这不会使用从XElementstring的显式转换,因为转换的可用性是在编译时根据表达式的编译时类型选择的。 / p>

但是,如果您希望将该绑定决策移至执行时间,则可以使用dynamic

dynamic obj = new XElement("foo", "text content");
string text = (string) obj; // Works fine

因此,在您的情况下,对于动态生成/实例化的类型,您将使用:

var mySourceTypeType = CreateMyType();
dynamic mySourceTypeInstance = Activator.CreateInstance(mySourceTypeType);
var myTarget = (MyTargetClass)mySourceTypeInstance;