reflection发射:如何为此构建构造函数

我想动态构建的代码如下:

public class Sample { public Sample() { Items = new ObservableTestCollection(this); } public Sample(IEnumerable source) { Items = new ObservableTestCollection(this, source); } public ObservableTestCollection Items; } 

ObservableTestCollection的来源如下:

 public class ObservableTestCollection : ObservableCollection { public T Parent; public ObservableTestCollection(T parent) { Parent = parent; } public ObservableTestCollection(T parent, IEnumerable source) : base(source) { Parent = parent; } } 

我写的代码是:

 const string assemblyName = "SampleAssembly"; const string fieldName = "Items"; const string typeName = "Sample"; const string assemblyFileName = assemblyName + ".dll"; AppDomain domain = AppDomain.CurrentDomain; AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.RunAndSave); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, assemblyFileName); TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public); Type[] ctorParameters = new Type[] { typeBuilder }; Type typeOfCTS = typeof(ObservableTestCollection); Type genericTypeOTS = typeOfCTS.MakeGenericType(typeBuilder); FieldBuilder fieldBuilder = typeBuilder.DefineField(fieldName, genericTypeOTS, FieldAttributes.Public); //first constructor ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes); ILGenerator generator = ctorBuilder.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); //load this generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); //call object constructor var ci = typeOfCTS.GetConstructors()[0]; generator.Emit(OpCodes.Newobj, ci); generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Items generator.Emit(OpCodes.Ret); //return //second constructor var typeOfIE = typeof(IEnumerable); var genericTypeIE = typeOfIE.MakeGenericType(typeBuilder); ctorParameters = new Type[] {genericTypeIE }; ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorParameters); ctorParameters = new Type[] { typeBuilder, genericTypeIE }; generator = ctorBuilder.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); //load this ci = typeOfCTS.GetConstructors()[1]; generator.Emit(OpCodes.Newobj, ci); generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Items generator.Emit(OpCodes.Ret); //return Type type = typeBuilder.CreateType(); var obj = Activator.CreateInstance(type); assemblyBuilder.Save(assemblyFileName); 

我无法创建Sample的实例。

任何人都可以帮我纠正这个问题吗?

非常感谢您的帮助。

此错误的原因是打开generics类型的构造函数的调用。 您需要使用TypeBuilder作为通用参数获取闭合generics类型的构造函数。 获取此解释的ConstructorInfo有一些问题。

因此,解决方案是使用以下参数调用TypeBuilder.GetConstructor(Type, ConstructorInfo)静态方法(如已提及的@TonyTHONG):

  • Type必须是TypeBuilder上的generics类型,在你的情况下是typeof(ObservableTestCollection<>).MakeGenericType(typeBuilder) ;
  • 您可以从开放generics类型获取的ConstructorInfo ,在您的情况下为typeof(ObservableTestCollection<>)

您可以在下面看到问题的代码示例:

  const string assemblyName = "SampleAssembly"; const string fieldName = "Items"; const string typeName = "Sample"; const string assemblyFileName = assemblyName + ".dll"; var domain = AppDomain.CurrentDomain; var assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.RunAndSave); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, assemblyFileName); var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public); var typeOfCts = typeof(ObservableTestCollection<>); var genericTypeOfCts = typeOfCts.MakeGenericType(typeBuilder); var fieldBuilder = typeBuilder.DefineField(fieldName, genericTypeOfCts, FieldAttributes.Public); //first constructor Sample() var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes); var obsCtor1 = typeOfCts.GetConstructors().First(c => c.GetParameters().Length == 1); obsCtor1 = TypeBuilder.GetConstructor(genericTypeOfCts, obsCtor1); //hack to get close generic type ctor with typeBuilder as generic parameter var generator = ctorBuilder.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); //load this for base type constructor generator.Emit(OpCodes.Call, typeof(object).GetConstructors().Single()); generator.Emit(OpCodes.Ldarg_0); //load this for field setter generator.Emit(OpCodes.Ldarg_0); //load this for ObservableTestCollection constructor generator.Emit(OpCodes.Newobj, obsCtor1); //call ObservableTestCollection constructor, it will put point to new object in stack generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Items generator.Emit(OpCodes.Ret); //return //second constructor Sample(IEnumerable source) var ctorParam = typeof(IEnumerable<>).MakeGenericType(typeBuilder); ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { ctorParam } ); obsCtor1 = typeOfCts.GetConstructors().First(c => c.GetParameters().Length == 2); obsCtor1 = TypeBuilder.GetConstructor(genericTypeOfCts, obsCtor1); //hack to get close generic type ctor with typeBuilder as generic parameter generator = ctorBuilder.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); //load this for base type constructor generator.Emit(OpCodes.Call, typeof(object).GetConstructors().Single()); generator.Emit(OpCodes.Ldarg_0); //load this for field setter generator.Emit(OpCodes.Ldarg_0); //load this for ObservableTestCollection constructor generator.Emit(OpCodes.Ldarg_1); //load IEnumerable for ObservableTestCollection constructor generator.Emit(OpCodes.Newobj, obsCtor1); //call ObservableTestCollection constructor, it will put point to new object in stack generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Items generator.Emit(OpCodes.Ret); //return var type = typeBuilder.CreateType(); var obj1 = Activator.CreateInstance(type); var parameter = Activator.CreateInstance(typeof(List<>).MakeGenericType(type)); var obj2 = Activator.CreateInstance(type, parameter); assemblyBuilder.Save(assemblyFileName); 

另外请记住,我只是通过将ObservableTestCollection放在生成Sample类的代码的不同程序集中来设法运行它。

如果我没弄错的话,你也会动态生成ObservableTestCollection类。 所以它可以在不分离程序集的情况下工作,特别是如果你为它们使用相同的AssemblyBuilder

您的程序无效,因为您尝试创建实例“ObservableTestCollection of Sample”但Sample是一个类型构建器。

如果generics参数是类型构建器而不是“MakeGenericType” ,请使用TypeBuilder.GetConstructor(Type,ConstructorInfo)来获取generics构造函数。