private static MethodBuilder GetFieldSetMethod(Type instanceType, TypeBuilder typeBuilder, PropertyInfo iProperty, FieldInfo field, FieldInfo instanceField) { var method = typeBuilder.DefineMethod("set_" + iProperty.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(void), new[] { iProperty.PropertyType }); var il = method.GetILGenerator(); var isPublicInstance = instanceType.IsPublic || instanceType.IsNestedPublic; if ((field.Attributes & FieldAttributes.InitOnly) != 0) { il.Emit(OpCodes.Newobj, typeof(DuckTypeFieldIsReadonlyException).GetConstructor(Type.EmptyTypes) !); il.Emit(OpCodes.Throw); return(method); } // Load instance if (!isPublicInstance || !field.IsPublic) { if (field.IsStatic) { il.Emit(OpCodes.Ldnull); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, instanceField); } } else if (!field.IsStatic) { ILHelpers.LoadInstance(il, instanceField, instanceType); } // Check if a duck type object var iPropTypeInterface = iProperty.PropertyType; if (iPropTypeInterface.IsGenericType) { iPropTypeInterface = iPropTypeInterface.GetGenericTypeDefinition(); } if (iProperty.PropertyType != field.FieldType && !iProperty.PropertyType.IsValueType && !iProperty.PropertyType.IsAssignableFrom(field.FieldType)) { if (field.IsStatic) { var innerField = DynamicFields.GetOrAdd(new VTuple <string, TypeBuilder>("_dtStatic" + iProperty.Name, typeBuilder), tuple => tuple.Item2.DefineField(tuple.Item1, typeof(DuckType), FieldAttributes.Private | FieldAttributes.Static)); il.Emit(OpCodes.Ldsflda, innerField); } else { var innerField = DynamicFields.GetOrAdd(new VTuple <string, TypeBuilder>("_dt" + iProperty.Name, typeBuilder), tuple => tuple.Item2.DefineField(tuple.Item1, typeof(DuckType), FieldAttributes.Private)); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldflda, innerField); } // Load value il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Castclass, typeof(DuckType)); il.EmitCall(OpCodes.Call, SetInnerDuckTypeMethodInfo, null); } else { // Load value il.Emit(OpCodes.Ldarg_1); } // Call method if (isPublicInstance && field.IsPublic) { var fieldRootType = Util.GetRootType(field.FieldType); var iPropRootType = Util.GetRootType(iProperty.PropertyType); ILHelpers.TypeConversion(il, iPropRootType, fieldRootType); il.Emit(field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, field); } else { var dynValueType = typeof(object); if (field.FieldType.IsPublic || field.FieldType.IsNestedPublic) { dynValueType = field.FieldType; } var iPropRootType = Util.GetRootType(iProperty.PropertyType); ILHelpers.TypeConversion(il, iPropRootType, dynValueType); var dynParameters = new[] { typeof(object), dynValueType }; var dynMethod = new DynamicMethod($"_setField+{field.DeclaringType!.Name}.{field.Name}", typeof(void), dynParameters, typeof(EmitAccessors).Module); EmitAccessors.CreateSetAccessor(dynMethod.GetILGenerator(), field, dynParameters[0], dynParameters[1]); var handle = GetRuntimeHandle(dynMethod); il.Emit(OpCodes.Ldc_I8, (long)handle.GetFunctionPointer()); il.Emit(OpCodes.Conv_I); il.EmitCalli(OpCodes.Calli, dynMethod.CallingConvention, typeof(void), dynParameters, null); DynamicMethods.Add(dynMethod); } il.Emit(OpCodes.Ret); return(method); }
private static MethodBuilder GetFieldGetMethod(Type instanceType, TypeBuilder typeBuilder, PropertyInfo iProperty, FieldInfo field, FieldInfo instanceField) { var method = typeBuilder.DefineMethod("get_" + iProperty.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, iProperty.PropertyType, Type.EmptyTypes); var il = method.GetILGenerator(); var isPublicInstance = instanceType.IsPublic || instanceType.IsNestedPublic; var returnType = field.FieldType; var innerDuck = false; var iPropTypeInterface = iProperty.PropertyType; if (iPropTypeInterface.IsGenericType) { iPropTypeInterface = iPropTypeInterface.GetGenericTypeDefinition(); } if (iProperty.PropertyType != field.FieldType && !iProperty.PropertyType.IsValueType && !iProperty.PropertyType.IsAssignableFrom(field.FieldType)) { if (field.IsStatic) { var innerField = DynamicFields.GetOrAdd(new VTuple <string, TypeBuilder>("_dtStatic" + iProperty.Name, typeBuilder), tuple => tuple.Item2.DefineField(tuple.Item1, typeof(DuckType), FieldAttributes.Private | FieldAttributes.Static)); il.Emit(OpCodes.Ldsflda, innerField); } else { var innerField = DynamicFields.GetOrAdd(new VTuple <string, TypeBuilder>("_dt" + iProperty.Name, typeBuilder), tuple => tuple.Item2.DefineField(tuple.Item1, typeof(DuckType), FieldAttributes.Private)); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldflda, innerField); } il.Emit(OpCodes.Ldtoken, iProperty.PropertyType); il.EmitCall(OpCodes.Call, GetTypeFromHandleMethodInfo, null); innerDuck = true; } if (isPublicInstance && field.IsPublic) { if (field.IsStatic) { il.Emit(OpCodes.Ldsfld, field); } else { ILHelpers.LoadInstance(il, instanceField, instanceType); il.Emit(OpCodes.Ldfld, field); } } else { if (field.IsStatic) { il.Emit(OpCodes.Ldnull); } else { ILHelpers.LoadInstance(il, instanceField, instanceType); } returnType = typeof(object); if (field.FieldType.IsPublic || field.FieldType.IsNestedPublic) { returnType = field.FieldType; } var dynParameters = new[] { typeof(object) }; var dynMethod = new DynamicMethod($"_getField+{field.DeclaringType!.Name}.{field.Name}", returnType, dynParameters, typeof(EmitAccessors).Module); EmitAccessors.CreateGetAccessor(dynMethod.GetILGenerator(), field, typeof(object), returnType); var handle = GetRuntimeHandle(dynMethod); il.Emit(OpCodes.Ldc_I8, (long)handle.GetFunctionPointer()); il.Emit(OpCodes.Conv_I); il.EmitCalli(OpCodes.Calli, dynMethod.CallingConvention, returnType, dynParameters, null); DynamicMethods.Add(dynMethod); } if (innerDuck) { ILHelpers.TypeConversion(il, returnType, typeof(object)); il.EmitCall(OpCodes.Call, GetInnerDuckTypeMethodInfo, null); } else if (returnType != iProperty.PropertyType) { ILHelpers.TypeConversion(il, returnType, iProperty.PropertyType); } il.Emit(OpCodes.Ret); return(method); }
private static MethodBuilder GetPropertyGetMethod(Type instanceType, TypeBuilder typeBuilder, PropertyInfo iProperty, PropertyInfo prop, FieldInfo instanceField) { var parameterTypes = GetPropertyParameterTypes(iProperty, false); var method = typeBuilder.DefineMethod("get_" + iProperty.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, iProperty.PropertyType, parameterTypes); var il = method.GetILGenerator(); if (!prop.CanRead) { il.Emit(OpCodes.Newobj, typeof(DuckTypePropertyCantBeReadException).GetConstructor(Type.EmptyTypes) !); il.Emit(OpCodes.Throw); return(method); } var propMethod = prop.GetMethod; var publicInstance = instanceType.IsPublic || instanceType.IsNestedPublic; // Check if an inner duck type is needed var innerDuck = false; var iPropTypeInterface = iProperty.PropertyType; if (iPropTypeInterface.IsGenericType) { iPropTypeInterface = iPropTypeInterface.GetGenericTypeDefinition(); } if (iProperty.PropertyType != prop.PropertyType && parameterTypes.Length == 0 && !iProperty.PropertyType.IsValueType && !iProperty.PropertyType.IsAssignableFrom(prop.PropertyType)) { if (propMethod.IsStatic) { var innerField = DynamicFields.GetOrAdd(new VTuple <string, TypeBuilder>("_dtStatic" + iProperty.Name, typeBuilder), tuple => tuple.Item2.DefineField(tuple.Item1, typeof(DuckType), FieldAttributes.Private | FieldAttributes.Static)); il.Emit(OpCodes.Ldsflda, innerField); } else { var innerField = DynamicFields.GetOrAdd(new VTuple <string, TypeBuilder>("_dt" + iProperty.Name, typeBuilder), tuple => tuple.Item2.DefineField(tuple.Item1, typeof(DuckType), FieldAttributes.Private)); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldflda, innerField); } il.Emit(OpCodes.Ldtoken, iProperty.PropertyType); il.EmitCall(OpCodes.Call, GetTypeFromHandleMethodInfo, null); innerDuck = true; } // Load the instance if (!propMethod.IsStatic) { ILHelpers.LoadInstance(il, instanceField, instanceType); } if (publicInstance) { // If we have index parameters we need to pass it if (parameterTypes.Length > 0) { var propIdxParams = prop.GetIndexParameters(); for (var i = 0; i < parameterTypes.Length; i++) { ILHelpers.WriteLoadArgument(i, il, propMethod.IsStatic); var iPType = Util.GetRootType(parameterTypes[i]); var pType = Util.GetRootType(propIdxParams[i].ParameterType); ILHelpers.TypeConversion(il, iPType, pType); } } // Method call if (propMethod.IsPublic) { il.EmitCall(propMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, propMethod, null); } else { il.Emit(OpCodes.Ldc_I8, (long)propMethod.MethodHandle.GetFunctionPointer()); il.Emit(OpCodes.Conv_I); il.EmitCalli(OpCodes.Calli, propMethod.CallingConvention, propMethod.ReturnType, propMethod.GetParameters().Select(p => p.ParameterType).ToArray(), null); } // Handle return value if (innerDuck) { ILHelpers.TypeConversion(il, prop.PropertyType, typeof(object)); il.EmitCall(OpCodes.Call, GetInnerDuckTypeMethodInfo, null); } else if (prop.PropertyType != iProperty.PropertyType) { ILHelpers.TypeConversion(il, prop.PropertyType, iProperty.PropertyType); } } else { if (propMethod.IsStatic) { il.Emit(OpCodes.Ldnull); } var dynReturnType = typeof(object); var dynParameters = new[] { typeof(object) }; if (prop.PropertyType.IsPublic || prop.PropertyType.IsNestedPublic) { dynReturnType = prop.PropertyType; } var dynMethod = new DynamicMethod("getDyn_" + prop.Name, dynReturnType, dynParameters, typeof(EmitAccessors).Module); EmitAccessors.CreateGetAccessor(dynMethod.GetILGenerator(), prop, typeof(object), dynReturnType); var handle = GetRuntimeHandle(dynMethod); il.Emit(OpCodes.Ldc_I8, (long)handle.GetFunctionPointer()); il.Emit(OpCodes.Conv_I); il.EmitCalli(OpCodes.Calli, dynMethod.CallingConvention, dynMethod.ReturnType, dynParameters, null); DynamicMethods.Add(dynMethod); // Handle return value if (innerDuck) { ILHelpers.TypeConversion(il, dynReturnType, typeof(object)); il.EmitCall(OpCodes.Call, GetInnerDuckTypeMethodInfo, null); } else { ILHelpers.TypeConversion(il, dynReturnType, iProperty.PropertyType); } } il.Emit(OpCodes.Ret); return(method); }