private static PropertyMapper GenerateIndexerDelegate(Type indexerType, Type targetType, bool ignoreMappings) { var method = new DynamicMethod("Map_" + indexerType.FullName + "_" + targetType.FullName, null, new[] { typeof(object), typeof(object) }, typeof(Mapper).Module); var il = method.GetILGenerator(); var targetProperties = Reflector.GetPropertyMap(targetType); var entityMap = MappingFactory.GetEntityMap(targetType); var getItem = indexerType.GetMethod("get_Item", new[] { typeof(string) }); var matches = targetProperties.Where(t => t.Value.IsSelectable && t.Key.PropertyType.IsPublic && t.Key.CanWrite && (t.Value.IsSimpleList || t.Value.IsSimpleType || t.Value.IsBinary)); foreach (var match in matches) { var typeConverter = MappingFactory.GetTypeConverter(getItem.ReturnType, match.Key, entityMap); if (match.Value.IsSimpleList && typeConverter == null) { continue; } il.Emit(OpCodes.Ldarg_1); if (typeConverter.Item1 != null) { // New the converter il.Emit(OpCodes.Newobj, typeConverter.Item1.GetConstructor(Type.EmptyTypes)); } il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, MappingFactory.GetPropertyOrColumnName(match.Key, ignoreMappings, entityMap, true)); il.Emit(OpCodes.Callvirt, getItem); if (typeConverter.Item1 == null) { il.EmitCastToReference(match.Key.PropertyType); } else { // Call the convert method il.Emit(OpCodes.Callvirt, typeConverter.Item2.GetMethod("ConvertForward")); } il.EmitCall(OpCodes.Callvirt, match.Key.GetSetMethod(), null); } il.Emit(OpCodes.Ret); var mapper = (PropertyMapper)method.CreateDelegate(typeof(PropertyMapper)); return(mapper); }
private static void DefineIndexerProperty(PropertyInfo property, TypeBuilder typeBuilder, FieldInfo field, Type objectType, bool ignoreMappings, IEntityMap entityMap) { // create the new property. var propertyBuilder = typeBuilder.DefineProperty(property.Name, PropertyAttributes.HasDefault, property.PropertyType, null); // The property "set" and property "get" methods require a special set of attributes. //var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; const MethodAttributes getSetAttr = MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName; var columnName = MappingFactory.GetPropertyOrColumnName(property, ignoreMappings, entityMap, true); // create the getter if we can read. if (property.CanRead) { var getItemMethod = objectType.GetMethod("get_Item", new[] { typeof(string) }); var typeConverter = MappingFactory.GetTypeConverter(getItemMethod.ReturnType, property, entityMap); // create the get method for the property. var getMethodName = "get_" + property.Name; var getMethod = typeBuilder.DefineMethod(getMethodName, getSetAttr, property.PropertyType, Type.EmptyTypes); // get the IL generator to generate the required IL. ILGenerator il = getMethod.GetILGenerator(); if (typeConverter.Item1 != null) { // New the converter il.Emit(OpCodes.Newobj, typeConverter.Item1.GetConstructor(Type.EmptyTypes)); } // load the first argument (the instance itself) and the field. il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Ldstr, columnName); il.Emit(OpCodes.Callvirt, getItemMethod); if (typeConverter.Item1 == null) { il.EmitCastToReference(property.PropertyType); } else { // Call the convert method il.Emit(OpCodes.Callvirt, typeConverter.Item2.GetMethod("ConvertForward")); } il.Emit(OpCodes.Ret); // set the method. propertyBuilder.SetGetMethod(getMethod); typeBuilder.DefineMethodOverride(getMethod, property.ReflectedType.GetMethod(getMethodName)); } // create the setter if we can read. if (property.CanWrite) { var setItemMethod = objectType.GetMethod("set_Item", new[] { typeof(string), typeof(object) }); var typeConverter = MappingFactory.GetTypeConverter(setItemMethod.GetParameters()[1].ParameterType, property, entityMap); // create the set method of the property. var setMethodName = "set_" + property.Name; var setMethod = typeBuilder.DefineMethod(setMethodName, getSetAttr, null, new[] { property.PropertyType }); // get the IL generator to generate some IL. ILGenerator il = setMethod.GetILGenerator(); // load the first argument (instance itself) and the field. il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Ldstr, columnName); if (typeConverter.Item1 != null) { // New the converter il.Emit(OpCodes.Newobj, typeConverter.Item1.GetConstructor(Type.EmptyTypes)); } // load the second argument (holding the value). il.Emit(OpCodes.Ldarg_1); if (typeConverter.Item1 != null) { // Call the convert method il.Emit(OpCodes.Callvirt, typeConverter.Item2.GetMethod("ConvertBackward")); } else { il.BoxIfNeeded(property.PropertyType); } // directly call the inner object's get method of the property. il.Emit(OpCodes.Callvirt, setItemMethod); il.Emit(OpCodes.Ret); propertyBuilder.SetSetMethod(setMethod); typeBuilder.DefineMethodOverride(setMethod, property.ReflectedType.GetMethod(setMethodName)); } }
private static PropertyMapper GenerateIndexerDelegate(Type indexerType, Type targetType, bool autoTypeCoercion) { var method = new DynamicMethod("Map_" + indexerType.FullName + "_" + targetType.FullName, null, new[] { typeof(object), typeof(object) }, typeof(Mapper).Module); var il = method.GetILGenerator(); var targetProperties = Reflector.GetPropertyMap(targetType); var entityMap = MappingFactory.GetEntityMap(targetType); var getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle"); var getDefaultValue = typeof(System.Activator).GetMethods().FirstOrDefault(m => m.Name == "CreateInstance" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Type)); var useIndexerMethod = true; if (!GetItemMethods.TryGetValue(indexerType, out var getItem) || getItem == null) { getItem = indexerType.GetMethod("get_Item", new[] { typeof(string) }); useIndexerMethod = false; } var matches = targetProperties.Where(t => t.Value.IsSelectable && t.Key.PropertyType.IsPublic && t.Key.CanWrite && (t.Value.IsSimpleList || t.Value.IsSimpleType || t.Value.IsBinary)); foreach (var match in matches) { var typeConverter = MappingFactory.GetTypeConverter(getItem.ReturnType, match.Key, entityMap); if (match.Value.IsSimpleList && typeConverter == null) { continue; } typeConverter = MatchTypeConverter(targetType, match.Value, getItem.ReturnType, typeConverter, autoTypeCoercion); il.Emit(OpCodes.Ldarg_1); if (typeConverter.Item1 != null) { // New the converter il.Emit(OpCodes.Newobj, typeConverter.Item1.GetConstructor(Type.EmptyTypes)); } il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, MappingFactory.GetPropertyOrColumnName(match.Key, false, entityMap, true)); if (!useIndexerMethod) { il.Emit(OpCodes.Callvirt, getItem); } else { var propertyType = match.Value.PropertyType; if (propertyType.IsValueType) { var ctor = propertyType.GetConstructor(Type.EmptyTypes); if (ctor != null) { il.Emit(OpCodes.Newobj, ctor); il.BoxIfNeeded(propertyType); } else if (propertyType.IsPrimitive) { if (propertyType == typeof(double)) { il.Emit(OpCodes.Ldc_R8, 0.0); } else if (propertyType == typeof(float)) { il.Emit(OpCodes.Ldc_R4, 0.0f); } else { il.EmitFastInt(0); if (propertyType == typeof(long) || propertyType == typeof(ulong)) { il.Emit(OpCodes.Conv_I8); } } il.BoxIfNeeded(propertyType); } else { il.Emit(OpCodes.Ldtoken, propertyType); il.Emit(OpCodes.Call, getTypeFromHandle); il.Emit(OpCodes.Call, getDefaultValue); } } else { il.Emit(OpCodes.Ldnull); } il.Emit(OpCodes.Call, getItem); } if (typeConverter.Item1 == null) { il.EmitCastToReference(match.Key.PropertyType); } else { // Call the convert method il.Emit(OpCodes.Callvirt, typeConverter.Item2.GetMethod("ConvertForward")); } il.EmitCall(OpCodes.Callvirt, match.Key.GetSetMethod(), null); } il.Emit(OpCodes.Ret); var mapper = (PropertyMapper)method.CreateDelegate(typeof(PropertyMapper)); return(mapper); }