目的:从接口动态创建对象并从IDataReader设置值
现在,我可以从接口动态创建对象类型/实例,但是当我从IDataReader设置值时,会出现错误:
“指定的演员表无效”
我用Google搜索了它,但没有太多帮助。我知道错误与发出代码有关,但是我不知道如何修改它。
有关界面中动态创建类型的代码
private PropertyBuilder BuildProperty(TypeBuilder tb, PropertyInfo property)
{
var fieldName = $"_{property.Name}";
var propertyBuilder = tb.DefineProperty(property.Name, PropertyAttributes.None, property.PropertyType, Type.EmptyTypes);
var fb = tb.DefineField(fieldName, property.PropertyType, FieldAttributes.Private);
var getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
var getterBuilder = BuildGetter(tb, property, fb, getSetAttributes);
var setterBuilder = BuildSetter(tb, property, fb, getSetAttributes);
propertyBuilder.SetGetMethod(getterBuilder);
propertyBuilder.SetSetMethod(setterBuilder);
return propertyBuilder;
}
private MethodBuilder BuildGetter(TypeBuilder tb, PropertyInfo property, FieldBuilder fb, MethodAttributes attributes)
{
var getterBuilder = tb.DefineMethod($"get_{property.Name}", attributes, property.PropertyType, Type.EmptyTypes);
var ilGenerator = getterBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, fb);
ilGenerator.Emit(OpCodes.Ret);
return getterBuilder;
}
private MethodBuilder BuildSetter(TypeBuilder tb, PropertyInfo property, FieldBuilder fb, MethodAttributes attributes)
{
var propertyType = property.PropertyType;
var setterBuilder = tb.DefineMethod($"set_{property.Name}", attributes, null, new Type[] { propertyType });
var setIl = setterBuilder.GetILGenerator();
var exitSet = setIl.DefineLabel(); // define label to jump in case condition is false
var opInequality = propertyType.GetMethod("op_Inequality", new Type[] { propertyType, propertyType });
if (opInequality != null)
{
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldfld, fb);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Call, opInequality);
setIl.Emit(OpCodes.Brfalse_S, exitSet);
}
else
{
// Use object inequality
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldfld, fb);
if (propertyType.IsValueType)
{
setIl.Emit(OpCodes.Box, propertyType);
}
setIl.Emit(OpCodes.Ldarg_1);
if (propertyType.IsValueType)
{
setIl.Emit(OpCodes.Box, propertyType);
}
setIl.Emit(OpCodes.Call, EqualsMethod);
setIl.Emit(OpCodes.Brtrue_S, exitSet);
}
setIl.Emit(OpCodes.Ldarg_0); // load string literal
setIl.Emit(OpCodes.Ldarg_1); // value
if (propertyType.IsValueType)
{
setIl.Emit(OpCodes.Box, propertyType);
}
setIl.Emit(OpCodes.Ldstr, property.Name);
var parentType = tb.BaseType;
if (parentType == null)
throw new Exception($"Interface {tb.Name} should be inherited from \"IDbEntity\". ");
var m = parentType.GetMethod("ValueChanged", BindingFlags.Instance | BindingFlags.NonPublic);
setIl.Emit(OpCodes.Call, m);
setIl.Emit(OpCodes.Ldarg_0); // this
setIl.Emit(OpCodes.Ldarg_1); // value
setIl.Emit(OpCodes.Stfld, fb); // save the new value into _name
setIl.MarkLabel(exitSet); // mark the label
setIl.Emit(OpCodes.Ret); // return
return setterBuilder;
}
有关设置值的代码
internal delegate T Load<out T>(IDataRecord dataRecord) where T : IDbEntity;
private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });
private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
private Load<T> CreateDynamicMethod<T>(Type insType) where T : IDbEntity
{
var method = new DynamicMethod("DynamicCreate", insType, new[] { typeof(IDataRecord) }, insType, true);
ILGenerator generator = method.GetILGenerator();
LocalBuilder result = generator.DeclareLocal(insType);
generator.Emit(OpCodes.Newobj, insType.GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Stloc, result);
var props = insType.GetProperties( BindingFlags.DeclaredOnly |BindingFlags.Public | BindingFlags.Instance);
for (var i = 0; i < props.Length; i++)
{
var info = props[i];
Label endIfLabel = generator.DefineLabel();
if (info.GetSetMethod() != null)
{
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Callvirt, isDBNullMethod);
generator.Emit(OpCodes.Brtrue, endIfLabel);
generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Callvirt, getValueMethod);
generator.Emit(OpCodes.Unbox_Any, info.PropertyType);
generator.Emit(OpCodes.Callvirt, info.GetSetMethod());
generator.MarkLabel(endIfLabel);
}
}
generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Ret);
return (Load<T>)method.CreateDelegate(typeof(Load<T>));
}
更新1
屏幕快照
更新2
方法
更新3
解决方案