在C#中通过TypeBuilder创建类型时出现TypeLoadException

时间:2016-01-12 12:26:53

标签: c# reflection

我在使用CreateType方法引发的欠读异常时遇到问题。 最后是例外和第二个问题。

代码如下:

定义(有效 - 我希望):

AssemblyName name = new AssemblyName("MyOwnNewAssembly"); 
AssemblyBuilder builder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = builder.DefineDynamicModule("Emission", "Emission.dll"); 
TypeBuilder typeBuilder = moduleBuilder.DefineType("User", TypeAttributes.Public);
typeBuilder.SetParent(typeof(object)); 
var field = typeBuilder.DefineField("name", typeof(string), FieldAttributes.Private);

构造函数创建(工作):

var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Any, new Type[] { typeof(String) });
var baseConstructor = typeof(object).GetConstructor(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance, null, new Type[0], null);var genertaor = constructor.GetILGenerator();
genertaor.Emit(OpCodes.Ldarg_0);         
genertaor.Emit(OpCodes.Call, baseConstructor);  
genertaor.Emit(OpCodes.Nop);
genertaor.Emit(OpCodes.Nop);
genertaor.Emit(OpCodes.Ldarg_0);  
genertaor.Emit(OpCodes.Ldarg_1);  
genertaor.Emit(OpCodes.Stfld, field);  
genertaor.Emit(OpCodes.Ret);

现在这里的代码不起作用 - 覆盖ToString:

var method = typeof(object).GetMethod("ToString");
var toStringBuilder = typeBuilder.DefineMethod("ToString", MethodAttributes.Public, typeof(string), Type.EmptyTypes);
typeBuilder.DefineMethodOverride(toStringBuilder, method);
var generator2 = toStringBuilder.GetILGenerator();
generator2.Emit(OpCodes.Nop);
generator2.Emit(OpCodes.Ldarg_0); 
generator2.Emit(OpCodes.Ldfld, field);
generator2.Emit(OpCodes.Stloc_0);
generator2.Emit(OpCodes.Ldloc_0);
generator2.Emit(OpCodes.Ret,field);

并创建类型(作品):

typeBuilder.CreateType();
builder.Save("Emission.dll");

以下是我要创建的代码:

public class User{
   private string _name;
   public User(string name){
      _name = name;
   }
   public override string ToString(){
      return _name;
   }
}

在ToString上面反编译后看起来像:

.method public hidebysig virtual 
instance string ToString () cil managed 
{
.maxstack 1
.locals init (
[0] string
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld string AssemblyBuilding.User::_name
IL_0007: stloc.0
IL_0008: br.s IL_000a

IL_000a: ldloc.0
IL_000b: ret
} // end of method User::ToString

我的其他问题

的原因
    IL_0007: stloc.0
    IL_0008: br.s IL_000a

    IL_000a: ldloc.0

看起来不像这样(为什么会有跳跃):

IL_0007: stloc.0
IL_000a: ldloc.0

例外是:

  

发生了'System.TypeLoadException'类型的未处理异常   mscorlib.dll中

     

附加信息:正文签名和方法实现中的声明不匹配。输入:'用户'。汇编:'MyOwnNewAssembly,   Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null'。

更新 我用字符串返回函数更正了上面的代码。现在它几乎可以工作,但我得到另一个异常,表明ToString不是虚拟的。

  

发生了'System.TypeLoadException'类型的未处理异常   mscorlib.dll中

     

附加信息:来自程序集MyOwnNewAssembly的'User'类型的方法'ToString',   版本= 0.0.0.0,Culture = neutral,PublicKeyToken = null'必须是虚拟的才能在接口或超类型中实现该方法。

然后我将方法名称从“ToString”更改为“Object.ToString”,但出现了相同的异常。

更新2 我想是什么问题。方法构建器应该有更多的MethodAttributes,如下所示:

            var toStringBuilder = typeBuilder.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(string), Type.EmptyTypes);

感谢您的回答。

1 个答案:

答案 0 :(得分:2)

typeBuilder.DefineMethod()来电中的第三个参数应该是typeof(string)而不是null,因为ToString()会返回一个字符串。

分支很可能是由编译器为调试版本引入的。