来自运行时类型的泛型 class
Generics class from a runtime type
我有一个在运行时 (RClass) 中构建的 class,还有一个通用 class B,我如何创建一种 DataLoader 并使用它的方法。
public interface IDataLoader<GType>
{
//some code
GType SampleMethod();
}
public class DataLoader <GType>: IDataLoader<GType>
{
GType SampleMethod(){
//some code
}
}
//class "RClass" created in runtime
MyClassBuilder MCB=new MyClassBuilder("RClass");
var myclass = MCB.CreateObject(new string[3] { "id", "name", "link" }, new Type[3] { typeof(int), typeof(string), typeof(string) });
Type myclassType = myclass.GetType();
var dta = typeof(DataLoader<>).MakeGenericType(myclassType);
// ?????
var gs = (???)Activator.CreateInstance(dta);
gs.SampleMethod();
为了在运行时构建一个 class 我使用这篇论文 http://www.codeproject.com/Articles/13337/Introduction-to-Creating-Dynamic-Types-with-Reflec
MyClassBuilder 的完整详细信息是
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using Faroid;
namespace Faroid
{
namespace Runtime
{
public class ORMapperFactory
{
string asmName;
AssemblyName assemblyName;
AssemblyBuilder asmBuilder;
ModuleBuilder modBuilder;
public ORMapperFactory(string ClassName)
{
asmName = ClassName;
}
void GenerateAssemblyAndModule()
{
if (asmBuilder == null)
{
assemblyName = new AssemblyName();
assemblyName.Name = asmName;
AppDomain thisDomain = Thread.GetDomain();
asmBuilder = thisDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
modBuilder = asmBuilder.DefineDynamicModule(asmBuilder.GetName().Name, false);
}
}
TypeBuilder CreateType(ModuleBuilder moduleBuilder, string typeName)
{
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
typeof(object),
new Type[] {typeof(IORMapper)});
return typeBuilder;
}
public IORMapper CreateObject(string[] PropertyNames,Type[]Types, bool returnAdapter)
{
if(PropertyNames.Length!=Types.Length)
{
Console.WriteLine("The number of property names should match their corresopnding types number");
}
TypeBuilder DynamicClass = CreateClass ();
CreateConstructor (DynamicClass);
for (int ind = 0; ind < PropertyNames.Count (); ind++) {
CreateProperty (DynamicClass, PropertyNames [ind], Types [ind]);
//cache adapter instance
// adapters.Add(dt.TableName, dra);
}
Type type = DynamicClass.CreateType();
//Create an instance of the DataRowAdapter
var dra = (IORMapper)Activator.CreateInstance(type, true);
//cache adapter instance
//adapters.Add(dt.TableName, dra);
//if just initializing adapter, dont return instance
return !returnAdapter ? null : dra;
}
TypeBuilder CreateClass()
{
GenerateAssemblyAndModule ();
TypeBuilder typeBuilder = CreateType (modBuilder, assemblyName.FullName);
return typeBuilder;
}
void CreateConstructor(TypeBuilder typeBuilder)
{
ConstructorBuilder constructor = typeBuilder.DefineConstructor(
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName,
CallingConventions.Standard,
new Type[0]);
//Define the reflection ConstructorInfor for System.Object
ConstructorInfo conObj = typeof(object).GetConstructor(new Type[0]);
//call constructor of base object
ILGenerator il = constructor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, conObj);
il.Emit(OpCodes.Ret);
}
// static void CreateConstructor(TypeBuilder typeBuilder)
// {
// typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
// }
void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =typeBuilder.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
}
}
简单地说,你不能:-)
有多种可能的解决方案:
非通用接口:
public interface IDataLoader
{
//some code
object SampleMethod();
}
例如IEnumerable
/IEnumerable<T>
dynamic
dynamic gs = Activator.CreateInstance(dta);
您将对象传递给 class,它将使用反射 "explore" 它(例如 DataGrid
通常)
你把所有你想做的事情都包含在一个泛型方法中:
public void Work<GType>(IDataLoader<GType> dataLoader)
{
// Here you can work with the IDataLoader<GType>
}
然后通过反射调用Work<GType>()
我有一个在运行时 (RClass) 中构建的 class,还有一个通用 class B,我如何创建一种 DataLoader 并使用它的方法。
public interface IDataLoader<GType>
{
//some code
GType SampleMethod();
}
public class DataLoader <GType>: IDataLoader<GType>
{
GType SampleMethod(){
//some code
}
}
//class "RClass" created in runtime
MyClassBuilder MCB=new MyClassBuilder("RClass");
var myclass = MCB.CreateObject(new string[3] { "id", "name", "link" }, new Type[3] { typeof(int), typeof(string), typeof(string) });
Type myclassType = myclass.GetType();
var dta = typeof(DataLoader<>).MakeGenericType(myclassType);
// ?????
var gs = (???)Activator.CreateInstance(dta);
gs.SampleMethod();
为了在运行时构建一个 class 我使用这篇论文 http://www.codeproject.com/Articles/13337/Introduction-to-Creating-Dynamic-Types-with-Reflec
MyClassBuilder 的完整详细信息是
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using Faroid;
namespace Faroid
{
namespace Runtime
{
public class ORMapperFactory
{
string asmName;
AssemblyName assemblyName;
AssemblyBuilder asmBuilder;
ModuleBuilder modBuilder;
public ORMapperFactory(string ClassName)
{
asmName = ClassName;
}
void GenerateAssemblyAndModule()
{
if (asmBuilder == null)
{
assemblyName = new AssemblyName();
assemblyName.Name = asmName;
AppDomain thisDomain = Thread.GetDomain();
asmBuilder = thisDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
modBuilder = asmBuilder.DefineDynamicModule(asmBuilder.GetName().Name, false);
}
}
TypeBuilder CreateType(ModuleBuilder moduleBuilder, string typeName)
{
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
typeof(object),
new Type[] {typeof(IORMapper)});
return typeBuilder;
}
public IORMapper CreateObject(string[] PropertyNames,Type[]Types, bool returnAdapter)
{
if(PropertyNames.Length!=Types.Length)
{
Console.WriteLine("The number of property names should match their corresopnding types number");
}
TypeBuilder DynamicClass = CreateClass ();
CreateConstructor (DynamicClass);
for (int ind = 0; ind < PropertyNames.Count (); ind++) {
CreateProperty (DynamicClass, PropertyNames [ind], Types [ind]);
//cache adapter instance
// adapters.Add(dt.TableName, dra);
}
Type type = DynamicClass.CreateType();
//Create an instance of the DataRowAdapter
var dra = (IORMapper)Activator.CreateInstance(type, true);
//cache adapter instance
//adapters.Add(dt.TableName, dra);
//if just initializing adapter, dont return instance
return !returnAdapter ? null : dra;
}
TypeBuilder CreateClass()
{
GenerateAssemblyAndModule ();
TypeBuilder typeBuilder = CreateType (modBuilder, assemblyName.FullName);
return typeBuilder;
}
void CreateConstructor(TypeBuilder typeBuilder)
{
ConstructorBuilder constructor = typeBuilder.DefineConstructor(
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName,
CallingConventions.Standard,
new Type[0]);
//Define the reflection ConstructorInfor for System.Object
ConstructorInfo conObj = typeof(object).GetConstructor(new Type[0]);
//call constructor of base object
ILGenerator il = constructor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, conObj);
il.Emit(OpCodes.Ret);
}
// static void CreateConstructor(TypeBuilder typeBuilder)
// {
// typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
// }
void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =typeBuilder.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
}
}
简单地说,你不能:-)
有多种可能的解决方案:
非通用接口:
public interface IDataLoader { //some code object SampleMethod(); }
例如
IEnumerable
/IEnumerable<T>
dynamic
dynamic gs = Activator.CreateInstance(dta);
您将对象传递给 class,它将使用反射 "explore" 它(例如
DataGrid
通常)你把所有你想做的事情都包含在一个泛型方法中:
public void Work<GType>(IDataLoader<GType> dataLoader) { // Here you can work with the IDataLoader<GType> }
然后通过反射调用
Work<GType>()