由 ObservableCollection 派生的反射发射
Reflection Emit Derived by ObservableCollection
我想创建带有 refelction emit 的动态类型,例如:
public class ObservableTestColleciton<T> : ObservableCollection<T>
{
public T Parent { get; set; }
public ObservableTestColleciton(T parent)
{
Parent = parent;
}
public ObservableTestColleciton(T parent, IEnumerable<T> source):base(source)
{
Parent = parent;
}
}
我无法完成的代码是这样的:
AppDomain myDomain = AppDomain.CurrentDomain;
AssemblyName myAsmName = new AssemblyName("AAB");
AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName,AssemblyBuilderAccess.Save);
ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name,myAsmName.Name + ".dll");
TypeBuilder myType = myModule.DefineType("ObservableTestCollection", TypeAttributes.Class | TypeAttributes.Public);
string[] typeParamNames = { "T" };
GenericTypeParameterBuilder[] typeParams = myType.DefineGenericParameters(typeParamNames);
Type observableOf = typeof(ObservableCollection<>);
Type genOb = observableOf.MakeGenericType(typeParams[0]);
FieldBuilder myField = myType.DefineField("Parent", typeParams[0], FieldAttributes.Public);
ConstructorBuilder constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
var type = myType.CreateType();
var obj = Activator.CreateInstance(type);
myAssembly.Save("AAB.dll");
非常感谢您的帮助!!
您的解决方案存在几个问题:
AssemblyBuilderAccess
应该是 RunAndSave
以允许类型实例在 运行 时间内创建对象。
- 您需要为构造函数指定主体。
- 在构造函数主体中,您应该调用基类型 (
ObservableCollection
) 构造函数。
- 在构造函数主体中,您应该从构造函数参数中设置字段值。
我对两个构造函数的这个问题的解决方案是这样的:
const string typeName = "ObservableTestCollection";
const string fieldName = "Parent";
const string assemblyName = "TestAssembly";
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 baseType = typeof(ObservableCollection<>);
var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public, baseType);
var genericParameters = typeBuilder.DefineGenericParameters("T");
var genericParameter = genericParameters.First();
var fieldBuilder = typeBuilder.DefineField(fieldName, genericParameter, FieldAttributes.Public);
//First constructor ObservableTestColleciton(T parent)
var ctorParameters = new Type[] { genericParameter };
var baseCtor = baseType.GetConstructor(Type.EmptyTypes);
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorParameters);
var generator = ctorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Call, baseCtor); //call base constructor
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Ldarg_1); // load argument value
generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Parent field
generator.Emit(OpCodes.Ret); //return
//Second constructor ObservableTestColleciton(T parent, IEnumerable<T> source):base(source)
var baseCtorParam = typeof(IEnumerable<>).MakeGenericType(genericParameter);
ctorParameters = new [] { genericParameter, baseCtorParam };
baseCtor = baseType.GetConstructors()
.First(c => c.GetParameters().FirstOrDefault()?.ParameterType?.GetGenericTypeDefinition() == typeof(IEnumerable<>));
ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorParameters);
generator = ctorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Ldarg_2); // load second argument value
generator.Emit(OpCodes.Call, baseCtor); //call base constructor
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Ldarg_1); // load first argument value
generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Parent field
generator.Emit(OpCodes.Ret); //return
var genericType = typeBuilder.CreateType();
var type = genericType.MakeGenericType(typeof(string));
var fieldInfo = type.GetField(fieldName);
var obj1 = Activator.CreateInstance(type, "Parent1");
Console.WriteLine("Ctor1 field value :" + fieldInfo.GetValue(obj1)); //check that field value was set
var obj2 = Activator.CreateInstance(type, "Parent2", new List<string>());
Console.WriteLine("Ctor1 field value :" + fieldInfo.GetValue(obj2));
assemblyBuilder.Save(assemblyFileName);
我想创建带有 refelction emit 的动态类型,例如:
public class ObservableTestColleciton<T> : ObservableCollection<T>
{
public T Parent { get; set; }
public ObservableTestColleciton(T parent)
{
Parent = parent;
}
public ObservableTestColleciton(T parent, IEnumerable<T> source):base(source)
{
Parent = parent;
}
}
我无法完成的代码是这样的:
AppDomain myDomain = AppDomain.CurrentDomain;
AssemblyName myAsmName = new AssemblyName("AAB");
AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName,AssemblyBuilderAccess.Save);
ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name,myAsmName.Name + ".dll");
TypeBuilder myType = myModule.DefineType("ObservableTestCollection", TypeAttributes.Class | TypeAttributes.Public);
string[] typeParamNames = { "T" };
GenericTypeParameterBuilder[] typeParams = myType.DefineGenericParameters(typeParamNames);
Type observableOf = typeof(ObservableCollection<>);
Type genOb = observableOf.MakeGenericType(typeParams[0]);
FieldBuilder myField = myType.DefineField("Parent", typeParams[0], FieldAttributes.Public);
ConstructorBuilder constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
var type = myType.CreateType();
var obj = Activator.CreateInstance(type);
myAssembly.Save("AAB.dll");
非常感谢您的帮助!!
您的解决方案存在几个问题:
AssemblyBuilderAccess
应该是RunAndSave
以允许类型实例在 运行 时间内创建对象。- 您需要为构造函数指定主体。
- 在构造函数主体中,您应该调用基类型 (
ObservableCollection
) 构造函数。 - 在构造函数主体中,您应该从构造函数参数中设置字段值。
我对两个构造函数的这个问题的解决方案是这样的:
const string typeName = "ObservableTestCollection";
const string fieldName = "Parent";
const string assemblyName = "TestAssembly";
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 baseType = typeof(ObservableCollection<>);
var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public, baseType);
var genericParameters = typeBuilder.DefineGenericParameters("T");
var genericParameter = genericParameters.First();
var fieldBuilder = typeBuilder.DefineField(fieldName, genericParameter, FieldAttributes.Public);
//First constructor ObservableTestColleciton(T parent)
var ctorParameters = new Type[] { genericParameter };
var baseCtor = baseType.GetConstructor(Type.EmptyTypes);
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorParameters);
var generator = ctorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Call, baseCtor); //call base constructor
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Ldarg_1); // load argument value
generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Parent field
generator.Emit(OpCodes.Ret); //return
//Second constructor ObservableTestColleciton(T parent, IEnumerable<T> source):base(source)
var baseCtorParam = typeof(IEnumerable<>).MakeGenericType(genericParameter);
ctorParameters = new [] { genericParameter, baseCtorParam };
baseCtor = baseType.GetConstructors()
.First(c => c.GetParameters().FirstOrDefault()?.ParameterType?.GetGenericTypeDefinition() == typeof(IEnumerable<>));
ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorParameters);
generator = ctorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Ldarg_2); // load second argument value
generator.Emit(OpCodes.Call, baseCtor); //call base constructor
generator.Emit(OpCodes.Ldarg_0); // load this
generator.Emit(OpCodes.Ldarg_1); // load first argument value
generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Parent field
generator.Emit(OpCodes.Ret); //return
var genericType = typeBuilder.CreateType();
var type = genericType.MakeGenericType(typeof(string));
var fieldInfo = type.GetField(fieldName);
var obj1 = Activator.CreateInstance(type, "Parent1");
Console.WriteLine("Ctor1 field value :" + fieldInfo.GetValue(obj1)); //check that field value was set
var obj2 = Activator.CreateInstance(type, "Parent2", new List<string>());
Console.WriteLine("Ctor1 field value :" + fieldInfo.GetValue(obj2));
assemblyBuilder.Save(assemblyFileName);