我正在尝试处理具有未知类型的数据集。为此,我要根据显示类格式的头文件创建运行时类。头文件的格式如下:
valueOneName valueTwoName valueThreeName etc...
数据的格式化方法相同,但使用值而不是变量名。我试图做的是基于头文件创建一个运行时类,然后使用来自不同文件的数据创建该类的实例。以下是相关代码。
static readonly char[] delimeters = new char[] { '\t' };
public static object CreateObject(Type type, params object[] args)
{
return Activator.CreateInstance(type, args);
}
public static Type CompileType(string typeName, string typeData)
{
string[] splitTypeData = typeData.Split(delimeters);
TypeBuilder tb = GetTypeBuilder(typeName);
CreateConstructor(tb, splitTypeData);
foreach (string s in splitTypeData)
CreateProperty(tb, s, typeof(string));
Type objectType = tb.CreateType();
return objectType;
}
private static void CreateConstructor(TypeBuilder tb, string[] splitTypeData)
{
GenericTypeParameterBuilder[] types = tb.DefineGenericParameters(splitTypeData);
Type[] t = new Type[types.Length];
for (int i = 0; i < t.Length; i++)
{
t[i] = types[i];//.GetGenericArguments()[0];//.GetGenericTypeDefinition();
}
ConstructorBuilder constructor = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard, t);
ConstructorInfo conObj = typeof(object).GetConstructor(t);
ILGenerator il = constructor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, conObj);
il.Emit(OpCodes.Ret);
}
private static TypeBuilder GetTypeBuilder(string typeName, Type parentType = null)
{
var typeSignature = typeName;// "DynamicType";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout);
if(parentType != null)
tb.SetParent(parentType);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.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 =
tb.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);
}
我这样调用代码:
Type t = CompileType("typeName", "typeHeaderString");
object obj = CreateObject(t, parameterList);//parameterList is an array of strings
我在CreateConstructor函数的倒数第二行中收到ArgumentNullException。创建运行时构造函数时我做错了什么?我会用这种错误的方式吗?
编辑:现在,我将为每种数据类型手动创建类,尽管在接收数据时比以前创建类要好得多。