I need to create a type at runtime using the TypeBuilder. This type should implement a specific interface so that it is possible to treat instances of this dynamic type uniformly at the compile time.
The interface should return an array of objects filled with values of specific fields in that type.
Interface that is supposed to be implemented is defined as follows:
public interface ISelectable
{
object[] GetPrimaryKeysValues();
}
This is the code I use to generate a method for the interface:
public static Type BuildTypeFromTable(Table tableToBuildTypeFrom)
{
AssemblyBuilder customTypesAssembly =
AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("CustomTypesAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder _moduleBuilder = customTypesAssembly.DefineDynamicModule("CustomTypesModule");
TypeBuilder customTypeBuilder = _moduleBuilder.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Public | TypeAttributes.Class);
List<FieldBuilder> primaryKeyFields = new List<FieldBuilder>();
//create a property for each column in the table
for (int i = 0; i < tableToBuildTypeFrom.Columns.Count; i++)
{
string propertyName = tableToBuildTypeFrom.Columns[i].Name;
//get a type of a property to create from a first row of the table
Type propertyType = tableToBuildTypeFrom.GetTypeOfColumnAtIndex(i);
//each property has to have a field to store its value in
FieldBuilder backingField = customTypeBuilder.DefineField(propertyName + "_field", propertyType, FieldAttributes.Private);
//body of a property getter
MethodBuilder getMethod = customTypeBuilder.DefineMethod(propertyName + "_get", MethodAttributes.Public | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIlGenerator = getMethod.GetILGenerator();
getIlGenerator.Emit(OpCodes.Ldarg_0);
getIlGenerator.Emit(OpCodes.Ldfld, backingField);
getIlGenerator.Emit(OpCodes.Ret);
///body of a property setter
MethodBuilder setMethod = customTypeBuilder.DefineMethod(propertyName + "_set", MethodAttributes.Public | MethodAttributes.HideBySig, null, new Type[] { propertyType });
ILGenerator setIlGenerator = setMethod.GetILGenerator();
setIlGenerator.Emit(OpCodes.Ldarg_0);
setIlGenerator.Emit(OpCodes.Ldarg_1);
setIlGenerator.Emit(OpCodes.Stfld, backingField);
setIlGenerator.Emit(OpCodes.Ret);
PropertyBuilder customProperty = customTypeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, Type.EmptyTypes);
customProperty.SetGetMethod(getMethod);
customProperty.SetSetMethod(setMethod);
//save all primary key columns to avoid iterating over columns all over again
if (tableToBuildTypeFrom.Columns[i].IsPrimaryKey)
{
primaryKeyFields.Add(backingField);
}
}
customTypeBuilder.AddInterfaceImplementation(typeof(ISelectable));
MethodBuilder getPrimaryKeysMethod = customTypeBuilder.DefineMethod("GetPrimaryKeysValues", MethodAttributes.Public | MethodAttributes.Virtual, typeof(object[]), null);
ILGenerator getPrimaryKeysMethodIlGenerator = getPrimaryKeysMethod.GetILGenerator();
getPrimaryKeysMethodIlGenerator.DeclareLocal(typeof(object[]));
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldc_I4, primaryKeyFields.Count);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Newarr, typeof(object));
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Stloc_0);
for (int i = 0; i < primaryKeyFields.Count; i++)
{
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldloc_0);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldc_I4, i);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldarg_0);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldfld, primaryKeyFields[i]);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Stelem_Ref);
}
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldloc_0);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ret);
MethodInfo s = typeof(ISelectable).GetMethod("GetPrimaryKeysValues");
customTypeBuilder.DefineMethodOverride(getPrimaryKeysMethod, s);
return customTypeBuilder.CreateType();
}
The way the method is supposed to be generated is taken from MSDN.
Now, the problem is that each time I try to call GetPrimaryKeysValues method, the VerificationException with a message 'Operation could destabilize the runtime.' is thrown. I have no idea what is causing it. Could someone help?
Thank you!