//A:已有的类 public class Creator<T> { public static Creator<T> Create() { return new Creator<T>(); } } //B:用Emit创建的类 public class Express { public Creator<Express> Cache { get { return Creator<Express>.Create(); } } }
A是代码中已有的类型,B是希望用Emit动态创建的类型,构建get_Cache方法时会出错,下面是创建的方法:
public static void Create() { AssemblyName name = new AssemblyName("Com.DiQiSoft.Demo"); AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave); ModuleBuilder module = assembly.DefineDynamicModule(name.Name, name.Name + ".dll"); TypeBuilder typeOfExpress = module.DefineType("Express", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit); typeOfExpress.SetParent(typeof(object)); var creator = typeof(Creator<>); var typeOfCreator = creator.MakeGenericType(typeOfExpress); var getMethod = typeOfExpress.DefineMethod("get_New", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, typeOfCreator, Type.EmptyTypes); var property = typeOfExpress.DefineProperty("New", PropertyAttributes.HasDefault, typeOfCreator, Type.EmptyTypes); var generator = getMethod.GetILGenerator(); var createMethod = typeOfCreator.GetMethod("Create"); var local = generator.DeclareLocal(typeOfCreator); generator.Emit(OpCodes.Nop); generator.Emit(OpCodes.Call, createMethod); generator.Emit(OpCodes.Stloc_0); var lb = generator.DefineLabel(); generator.Emit(OpCodes.Br_S, lb); generator.MarkLabel(lb); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ret); property.SetGetMethod(getMethod); typeOfExpress.CreateType(); assembly.Save(name.Name + ".dll"); }
上面的代码在运行到:
var createMethod = typeOfCreator.GetMethod("Create");
这一行时会提示错误:不支持所指定的方法。
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Text; namespace Demo { class Program { static void Main(string[] args) { Create(); } public static void Create() { AssemblyName name = new AssemblyName("Com.DiQiSoft.Demo"); AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave); ModuleBuilder module = assembly.DefineDynamicModule(name.Name, name.Name + ".dll"); TypeBuilder typeOfExpress = module.DefineType("Express", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit); typeOfExpress.SetParent(typeof(object)); var creator = typeof(Creator<>); var typeOfCreator = creator.MakeGenericType(typeOfExpress); var getMethod = typeOfExpress.DefineMethod("get_New", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, typeOfCreator, Type.EmptyTypes); var property = typeOfExpress.DefineProperty("New", PropertyAttributes.HasDefault, typeOfCreator, Type.EmptyTypes); var generator = getMethod.GetILGenerator(); var createMethod = typeOfCreator.GetMethod("Create"); var local = generator.DeclareLocal(typeOfCreator); generator.Emit(OpCodes.Nop); generator.Emit(OpCodes.Call, createMethod); generator.Emit(OpCodes.Stloc_0); var lb = generator.DefineLabel(); generator.Emit(OpCodes.Br_S, lb); generator.MarkLabel(lb); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ret); property.SetGetMethod(getMethod); typeOfExpress.CreateType(); assembly.Save(name.Name + ".dll"); } } public class Creator<T> { public static Creator<T> Create() { return new Creator<T>(); } } }
上面是完整的测试代码,新建一个控制台程序复制进去就可以运行了。
So hard for remember,需要翻文档...
折腾了一个晚上没找到方法,静候佳音,谢谢
@DiQiSoft.Com:
var createMethod = TypeBuilder.GetMethod(typeOfCreator, creator.GetMethod("Create"));
生成的代码为:
public class Express { public Creator<Express> New { get { return Creator<Express>.Create(); } } }
@幻天芒: 搞定,万分感谢
@DiQiSoft.Com: 共同进步,我也是在StackOverflow上找到的方案,然后测试成功了。
以前用过、都忘记了。帮顶
谢谢
查看一下typeOfCreator都有哪些方法。
帮顶!
typeOfCreator的类型没记错的话好像是TypeBuilderInstantiation
帮顶!
谢谢