我试图生成一个将属性从一个通用对象复制到另一个通用对象的方法,如果属性类型不同,我希望它使用TypeConverter来转换属性值。
最后我想扩大规模,以便我可以将IDataRecords直接自动映射到对象。但是现在我遇到了在属性类型不同时将属性从一个对象复制到另一个对象的问题。如果所有属性类型相同,则生成的方法可以正常工作。
我不明白为什么它无法生成,因为我在C#中编写了一个示例方法,然后查看了IL,而IL I生成应该是相同的。
以下是简化版,完整代码可在https://gist.github.com/DerekZiemba/468b84d7b5a5a289470859e261f17217
找到public static void CopyExample(StreetAddress target, DBLocation src) {
target.Locality = src.Locality;
target.Latitude = (float)TypeConversion.Float32Converter.ConvertFrom(src.Latitude);
}
这是由CopyExample生成的IL:
.method public hidebysig static void
CopyExample(
class ExampleILGeneratorShallowCopy.StreetAddress target,
class ExampleILGeneratorShallowCopy.DBLocation src
) cil managed
{
.maxstack 8
// [36 4 - 36 35]
IL_0000: ldarg.0 // target
IL_0001: ldarg.1 // src
IL_0002: callvirt instance string ExampleILGeneratorShallowCopy.DBLocation::get_Locality()
IL_0007: callvirt instance void ExampleILGeneratorShallowCopy.StreetAddress::set_Locality(string)
// [37 4 - 37 87]
IL_000c: ldarg.0 // target
IL_000d: ldsfld class [System.ComponentModel.TypeConverter]System.ComponentModel.SingleConverter ExampleILGeneratorShallowCopy.TypeConversion::Float32Converter
IL_0012: ldarg.1 // src
IL_0013: callvirt instance float64 ExampleILGeneratorShallowCopy.DBLocation::get_Latitude()
IL_0018: box [System.Runtime]System.Double
IL_001d: callvirt instance object [System.ComponentModel.TypeConverter]System.ComponentModel.TypeConverter::ConvertFrom(object)
IL_0022: unbox.any [System.Runtime]System.Single
IL_0027: callvirt instance void ExampleILGeneratorShallowCopy.StreetAddress::set_Latitude(float32)
// [38 3 - 38 4]
IL_002c: ret
} // end of method ExampleILGeneratorShallowCopy::CopyExample
这里的ILGenerator方法应该产生与上面例子相同的输出:
public delegate void CopyIntoDelegate<T, S>(T location, S src);
public static CopyIntoDelegate<StreetAddress, DBLocation> GenerateExactExample() {
Type targetType = typeof(StreetAddress);
Type srcType = typeof(DBLocation);
PropertyInfo targetLocality = targetType.GetProperty("Locality");
PropertyInfo srcLocality = srcType.GetProperty("Locality");
PropertyInfo targetLatitude = targetType.GetProperty("Latitude");
PropertyInfo srcLatitude = srcType.GetProperty("Latitude");
DynamicMethod dynmethod = new DynamicMethod("ExactExample", typeof(void), new Type[2]{ targetType, srcType }, true);
ILGenerator gen = dynmethod.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Callvirt, srcLocality.GetMethod);
gen.Emit(OpCodes.Callvirt, targetLocality.SetMethod);
TypeConverter converter = TypeConversion.Float32Converter;
FieldInfo converterField = typeof(TypeConversion).GetField(nameof(TypeConversion.Float32Converter));
MethodInfo convertFrom = converter.GetType().GetMethod(nameof(TypeConverter.ConvertFrom), new [] { typeof(object) });
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldsfld, converterField);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Callvirt, srcLatitude.GetMethod);
gen.Emit(OpCodes.Box, srcLatitude.PropertyType);
gen.Emit(OpCodes.Callvirt, convertFrom);
gen.Emit(OpCodes.Unbox_Any);
gen.Emit(OpCodes.Callvirt, targetLatitude.SetMethod);
gen.Emit(OpCodes.Ret);
Delegate del = dynmethod.CreateDelegate(typeof(CopyIntoDelegate<StreetAddress, DBLocation>));
return (CopyIntoDelegate<StreetAddress, DBLocation>)del;
}