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 DefineProperties(Type objectType, TypeBuilder typeBuilder, FieldInfo field, Type interfaceType, DynamicProxyType proxyType, bool ignoreMappings) { var entityMap = MappingFactory.GetEntityMap(interfaceType); foreach (var property in Reflector.GetAllProperties(interfaceType)) { // check if we can support the wrapping. var propertyName = MappingFactory.GetPropertyOrColumnName(property, ignoreMappings, entityMap, false); var objectProperty = objectType != null?objectType.GetProperty(propertyName) : null; if (objectProperty != null && ((property.CanRead && !objectProperty.CanRead) || (property.CanWrite && !objectProperty.CanWrite))) { throw new InvalidCastException("Can't cast because the property is missing or does not have the required implementation."); } // check the property types. if (objectProperty != null && objectProperty.PropertyType != property.PropertyType) { throw new InvalidCastException("Can't cast because property types do not match."); } // define the property. if (proxyType == DynamicProxyType.FullIndexer) { DefineIndexerProperty(property, typeBuilder, field, objectType, ignoreMappings, entityMap); } else if (proxyType == DynamicProxyType.SimpleIndexer && IsWrappable(property, entityMap)) { DefineIndexerProperty(property, typeBuilder, field, objectType, ignoreMappings, entityMap); } else if (proxyType == DynamicProxyType.Guard) { DefineGuardedProperty(property, typeBuilder, field, objectType, ignoreMappings, entityMap); } else if (objectProperty != null) { DefineProperty(property, typeBuilder, field, objectType, objectProperty); } else { DefineDefaultProperty(property, typeBuilder); } } }
private static void DefineGuardedProperty(PropertyInfo property, TypeBuilder typeBuilder, FieldInfo field, Type objectType, bool ignoreMappings, IEntityMap entityMap) { // create the new property. var propertyBuilder = typeBuilder.DefineProperty(property.Name, System.Reflection.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; var 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) { // 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(); // directly call the inner object's get method of the property. Type elementType; if (Reflector.IsDataEntityList(property.PropertyType, out elementType)) { var isInterface = property.PropertyType.GetGenericTypeDefinition() == typeof(IList <>); var asReadOnlyMethod = typeof(ObjectExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "AsReadOnly").First(m => m.GetParameters()[0].ParameterType.Name == (isInterface ? "IList`1" : "List`1")); var result = il.DeclareLocal(property.PropertyType); // load the first argument (the instance itself) and the field. il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null); il.Emit(OpCodes.Call, asReadOnlyMethod.MakeGenericMethod(elementType)); il.Emit(OpCodes.Stloc_0, result); il.Emit(OpCodes.Ldloc_0); } else if (Reflector.IsDataEntity(property.PropertyType)) { var asReadOnlyMethod = typeof(ObjectExtensions).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "AsReadOnly").First(m => m.GetParameters()[0].ParameterType.IsGenericParameter); var result = il.DeclareLocal(property.PropertyType); // load the first argument (the instance itself) and the field. il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null); il.Emit(OpCodes.Call, asReadOnlyMethod.MakeGenericMethod(property.PropertyType)); il.Emit(OpCodes.Stloc_0, result); il.Emit(OpCodes.Ldloc_0); } else if (property.DeclaringType.InheritsFrom(typeof(ITrackableDataEntity)) && property.PropertyType == typeof(ObjectState) && property.Name == "ObjectState") { il.Emit(OpCodes.Ldc_I4, (int)ObjectState.ReadOnly); } else { // load the first argument (the instance itself) and the field. il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null); } 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) { // create the set method of the property. var setMethodName = "set_" + property.Name; var setMethod = typeBuilder.DefineMethod(setMethodName, getSetAttr, null, new Type[] { 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.Newobj, typeof(NotSupportedException).GetConstructor(Type.EmptyTypes)); il.Emit(OpCodes.Throw); propertyBuilder.SetSetMethod(setMethod); typeBuilder.DefineMethodOverride(setMethod, property.ReflectedType.GetMethod(setMethodName)); } }
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); }
private static PropertyMapper GenerateDelegate(Type sourceType, Type targetType) { var method = new DynamicMethod("Map_" + sourceType.FullName + "_" + targetType.FullName, null, new[] { typeof(object), typeof(object) }, true); var il = method.GetILGenerator(); var sourceProperties = Reflector.GetAllProperties(sourceType); var targetProperties = Reflector.GetAllProperties(targetType); var entityMap = MappingFactory.GetEntityMap(targetType); var matches = sourceProperties.CrossJoin(targetProperties).Where(t => (t.Item2.Name == t.Item3.Name || t.Item2.Name == MappingFactory.GetPropertyOrColumnName(t.Item3, false, entityMap, false)) && t.Item2.PropertyType == t.Item3.PropertyType && t.Item2.PropertyType.IsPublic && t.Item3.PropertyType.IsPublic //&& (t.Item3.PropertyType.IsValueType || t.Item3.PropertyType == typeof(string)) && t.Item2.CanRead && t.Item3.CanWrite); foreach (var match in matches) { il.Emit(OpCodes.Ldarg_1); il.EmitCastToReference(targetType); il.Emit(OpCodes.Ldarg_0); il.EmitCastToReference(sourceType); il.Emit(OpCodes.Callvirt, match.Item2.GetGetMethod()); il.Emit(OpCodes.Callvirt, match.Item3.GetSetMethod()); } il.Emit(OpCodes.Ret); var mapper = (PropertyMapper)method.CreateDelegate(typeof(PropertyMapper)); return(mapper); }