public static T ReadVersionSerializable <T>(IPrimitiveReader reader) where T : IVersionSerializable { var version = reader.ReadVarInt32(); if (version == -1) { return(default(T)); } if (version < 0) { throw new InvalidDataException(); } var instance = DynamicMethods.GetCtor <T>()(); reader.Response = SerializationResponse.Success; instance.Deserialize(reader, version); if (reader.Response != SerializationResponse.Success) { throw new UnhandledVersionException(string.Format( "IPrimitiveReader.Response set to {0} by IVersionSerializable code in Type=\"{1}\", CurrentVersion=\"{2}\", StreamVersion=\"{3}\"", reader.Response, typeof(T).FullName, instance.CurrentVersion, version)); } return(instance); }
public void TestAdd() { { var c1 = new MyCollection(); var item1 = new Item { Name = "item1" }; var adder = DynamicMethods.Adder(c1, item1, typeof(Item)); Assert.AreEqual(0, c1.Count); adder(c1, item1); Assert.AreEqual(1, c1.Count); Assert.AreSame(item1, c1[0]); } { var c1 = new MyCollection(); var item1 = new Item { Name = "item1" }; var adder = DynamicMethods.Adder(c1, item1, typeof(object)); Assert.AreEqual(0, c1.Count); adder(c1, item1); Assert.AreEqual(1, c1.Count); Assert.AreSame(item1, c1[0]); } }
public void TestSetProperty() { var setter = DynamicMethods.Setter <Item, string>(x => x.Name); var item = new Item(); setter(item, "test"); Assert.AreEqual("test", item.Name); Assert.IsNull(item.Field); Assert.IsNull(DynamicMethods.Setter <Item, string>(x => x.FullName)); }
public void CompileAdd() { var items = new ItemCollection(); var func = DynamicMethods.CompileAdd(items.GetType()); var item = (Item)func(items, new object[] { "a" }); Assert.AreEqual(1, items.Count); Assert.IsNotNull(item); Assert.AreEqual("a", item.Name); }
public void CompileRemoveAt() { var items = new ItemCollection { "a" }; var func = DynamicMethods.CompileRemoveAt(items.GetType()); var result = (Item)func(items, 0); Assert.IsNull(result); Assert.AreEqual(0, items.Count); }
public void CompileIndexer() { var items = new ItemCollection { "a" }; var func = DynamicMethods.CompileIndexer(items.GetType()); var item = (Item)func(items, 0); Assert.IsNotNull(item); Assert.AreSame(items[0], item); }
public void TestSetField() { var setter = DynamicMethods.Setter <Item, string>(x => x.Field); var item = new Item { Field = "abc" }; setter(item, "test"); Assert.AreEqual("test", item.Field); Assert.IsNull(item.Name); }
public void FieldGetter() { var item = new Item { Field = "a" }; var type = item.GetType(); var field = type.GetField("Field"); var getter = DynamicMethods.CompileGetter(type, field); var value = getter(item); Assert.AreEqual(item.Field, value); }
public void CompileSetter() { var item = new Item { Name = "a" }; var type = item.GetType(); var property = type.GetProperty("Name"); var setter = DynamicMethods.CompileSetter(type, property); setter(item, "b"); Assert.AreEqual("b", item.Name); }
public void CompileGetter() { var item = new Item { Name = "a" }; var type = item.GetType(); var property = type.GetProperty("Name"); var getter = DynamicMethods.CompileGetter(type, property); var value = getter(item); Assert.AreEqual(item.Name, value); }
public void FieldSetter() { var item = new Item { Field = "a" }; var type = item.GetType(); var field = type.GetField("Field"); var setter = DynamicMethods.CompileSetter(type, field); setter(item, "b"); Assert.AreEqual("b", item.Field); }
private Action <object, object> ResolveAddMethod(object target, object item) { var itemType = item != null?item.GetType() : _elementType; Action <object, object> action; if (_addMethods.TryGetValue(itemType, out action)) { return(action); } action = DynamicMethods.Adder(target, item, _elementType); _addMethods.Add(itemType, action); return(action); }
public static T ReadCustomSerializable <T>(IPrimitiveReader reader) where T : ICustomSerializable { int header = reader.ReadVarInt32(); if (header == -1) { return(default(T)); } if (header != 0) { throw new UnhandledVersionException(0, header); } var instance = DynamicMethods.GetCtor <T>()(); instance.Deserialize(reader); return(instance); }
private IPropertyDef Create <TValue>(Expression <Func <T, TValue> > property, Func <TValue, bool> isDefaultValue, XNamespace ns, XName name) { var member = property.ResolveMember(); if (name == null) { name = GetDefaultName(member, ns); } ns = name.Namespace; var elementName = ns + name.LocalName.ToSingular(); var itemAttr = member.ResolveAttribute <ItemNameAttribute>(true); if (itemAttr != null) { elementName = string.IsNullOrEmpty(itemAttr.Namespace) ? ns + itemAttr.Name : XNamespace.Get(itemAttr.Namespace) + itemAttr.Name; } if (isDefaultValue == null) { var defaultValueAttr = member.ResolveAttribute <DefaultValueAttribute>(true); if (defaultValueAttr != null) { var defaultValue = defaultValueAttr.Value; isDefaultValue = value => Equals(value, defaultValue); } } var argAttr = member.ResolveAttribute <ArgAttribute>(true); if (argAttr != null) { _elementDef._ctorIndex[name.LocalName] = argAttr.Index; } var getter = property.Compile(); var setter = DynamicMethods.Setter(property); return(new PropertyDef <TValue>(member.Name, name, elementName, getter, setter, isDefaultValue)); }
/// <summary> /// Gets the parameterless constructor for <typeparamref name="T"/>, if any. /// </summary> /// <typeparam name="T">The type of object to create.</typeparam> /// <returns>Null if <typeparamref name="T"/> isn't the same as /// <see cref="Type"/>, or the parameterless constructor of /// <typeparamref name="T"/> if any.</returns> public Factory <T> GetCreator <T>() { var type = typeof(T); if (!type.Equals(Type)) { return(null); } try { return(DynamicMethods.GetCtor <T>()); } catch (ArgumentException exc) { if (exc.ParamName != "TResult") { throw; } return(null); } }
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); }
public static object UnboxNullable(this object value) { if (value == null) { return(null); } var type = value.GetType(); if (!type.IsNullable()) { return(value); } var valueType = type.GetGenericArguments()[0]; switch (Type.GetTypeCode(valueType)) { case TypeCode.Boolean: return((bool)value); case TypeCode.Char: return((char)value); case TypeCode.SByte: return((sbyte)value); case TypeCode.Byte: return((byte)value); case TypeCode.Int16: return((Int16)value); case TypeCode.UInt16: return((UInt16)value); case TypeCode.Int32: return((int)value); case TypeCode.UInt32: return((uint)value); case TypeCode.Int64: return((Int64)value); case TypeCode.UInt64: return((UInt64)value); case TypeCode.Single: return((Single)value); case TypeCode.Double: return((Double)value); case TypeCode.Decimal: return((Decimal)value); case TypeCode.DateTime: return((DateTime)value); case TypeCode.String: return(value); default: return(DynamicMethods.UnboxNullable(type)(value)); } }
private static MethodBuilder GetPropertySetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, PropertyInfo targetProperty, FieldInfo instanceField) { string proxyMemberName = null; Type[] proxyParameterTypes = Type.EmptyTypes; Type[] targetParametersTypes = GetPropertySetParametersTypes(targetProperty, true).ToArray(); if (proxyMember is PropertyInfo proxyProperty) { proxyMemberName = proxyProperty.Name; proxyParameterTypes = GetPropertySetParametersTypes(proxyProperty, true).ToArray(); if (proxyParameterTypes.Length != targetParametersTypes.Length) { DuckTypePropertyArgumentsLengthException.Throw(proxyProperty); } } else if (proxyMember is FieldInfo proxyField) { proxyMemberName = proxyField.Name; proxyParameterTypes = new Type[] { proxyField.FieldType }; if (proxyParameterTypes.Length != targetParametersTypes.Length) { DuckTypePropertyArgumentsLengthException.Throw(targetProperty); } } MethodBuilder proxyMethod = proxyTypeBuilder.DefineMethod( "set_" + proxyMemberName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(void), proxyParameterTypes); ILGenerator il = proxyMethod.GetILGenerator(); MethodInfo targetMethod = targetProperty.SetMethod; // Load the instance if needed if (!targetMethod.IsStatic) { il.Emit(OpCodes.Ldarg_0); il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField); } // Load the indexer keys and set value to the stack for (int pIndex = 0; pIndex < proxyParameterTypes.Length; pIndex++) { Type proxyParamType = proxyParameterTypes[pIndex]; Type targetParamType = targetParametersTypes[pIndex]; // Check if the type can be converted of if we need to enable duck chaining if (NeedsDuckChaining(targetParamType, proxyParamType)) { // Load the argument and cast it as Duck type il.WriteLoadArgument(pIndex, false); il.Emit(OpCodes.Castclass, typeof(IDuckType)); // Call IDuckType.Instance property to get the actual value il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod, null); targetParamType = typeof(object); } else { il.WriteLoadArgument(pIndex, false); } // If the target parameter type is public or if it's by ref we have to actually use the original target type. targetParamType = UseDirectAccessTo(targetParamType) || targetParamType.IsByRef ? targetParamType : typeof(object); il.WriteTypeConversion(proxyParamType, targetParamType); targetParametersTypes[pIndex] = targetParamType; } // Call the setter method if (UseDirectAccessTo(targetType)) { // If the instance is public we can emit directly without any dynamic method if (targetMethod.IsPublic) { // We can emit a normal call if we have a public instance with a public property method. il.EmitCall(targetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null); } else { // In case we have a public instance and a non public property method we can use [Calli] with the function pointer il.WriteMethodCalli(targetMethod); } } else { // If the instance is not public we need to create a Dynamic method to overpass the visibility checks // we can't access non public types so we have to cast to object type (in the instance object and the return type). string dynMethodName = $"_setNonPublicProperty+{targetProperty.DeclaringType.Name}.{targetProperty.Name}"; // We create the dynamic method Type[] targetParameters = GetPropertySetParametersTypes(targetProperty, false, !targetMethod.IsStatic).ToArray(); Type[] dynParameters = targetMethod.IsStatic ? targetParametersTypes : (new[] { typeof(object) }).Concat(targetParametersTypes).ToArray(); DynamicMethod dynMethod = new DynamicMethod(dynMethodName, typeof(void), dynParameters, typeof(DuckType).Module, true); // We store the dynamic method in a bag to avoid getting collected by the GC. DynamicMethods.Add(dynMethod); // Emit the dynamic method body ILGenerator dynIL = dynMethod.GetILGenerator(); if (!targetMethod.IsStatic) { dynIL.LoadInstanceArgument(typeof(object), targetProperty.DeclaringType); } for (int idx = targetMethod.IsStatic ? 0 : 1; idx < dynParameters.Length; idx++) { dynIL.WriteLoadArgument(idx, true); dynIL.WriteTypeConversion(dynParameters[idx], targetParameters[idx]); } dynIL.EmitCall(targetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null); dynIL.Emit(OpCodes.Ret); // Emit the call to the dynamic method il.WriteMethodCalli(dynMethod, dynParameters); } il.Emit(OpCodes.Ret); return(proxyMethod); }
private static MethodBuilder GetFieldSetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, FieldInfo targetField, FieldInfo instanceField) { string proxyMemberName = proxyMember.Name; Type proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType : proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object); MethodBuilder method = proxyTypeBuilder.DefineMethod( "set_" + proxyMemberName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(void), new[] { proxyMemberReturnType }); ILGenerator il = method.GetILGenerator(); Type currentValueType = proxyMemberReturnType; // Load instance if (!targetField.IsStatic) { il.Emit(OpCodes.Ldarg_0); il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField); } // Check if the type can be converted of if we need to enable duck chaining if (NeedsDuckChaining(targetField.FieldType, proxyMemberReturnType)) { // Load the argument and convert it to Duck type il.Emit(OpCodes.Ldarg_1); il.WriteTypeConversion(proxyMemberReturnType, typeof(IDuckType)); // Call IDuckType.Instance property to get the actual value il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod, null); currentValueType = typeof(object); } else { // Load the value into the stack il.Emit(OpCodes.Ldarg_1); } // We set the field value if (UseDirectAccessTo(targetType) && targetField.IsPublic) { // If the instance and the field are public then is easy to set. il.WriteTypeConversion(currentValueType, targetField.FieldType); il.Emit(targetField.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, targetField); } else { // If the instance or the field are non public we need to create a Dynamic method to overpass the visibility checks string dynMethodName = $"_setField+{targetField.DeclaringType.Name}.{targetField.Name}"; // Convert the field type for the dynamic method Type dynValueType = UseDirectAccessTo(targetField.FieldType) ? targetField.FieldType : typeof(object); il.WriteTypeConversion(currentValueType, dynValueType); // Create dynamic method Type[] dynParameters = targetField.IsStatic ? new[] { dynValueType } : new[] { typeof(object), dynValueType }; DynamicMethod dynMethod = new DynamicMethod(dynMethodName, typeof(void), dynParameters, typeof(DuckType).Module, true); DynamicMethods.Add(dynMethod); // Write the dynamic method body ILGenerator dynIL = dynMethod.GetILGenerator(); dynIL.Emit(OpCodes.Ldarg_0); if (targetField.IsStatic) { dynIL.WriteTypeConversion(dynValueType, targetField.FieldType); dynIL.Emit(OpCodes.Stsfld, targetField); } else { if (targetField.DeclaringType != typeof(object)) { dynIL.Emit(OpCodes.Castclass, targetField.DeclaringType); } dynIL.Emit(OpCodes.Ldarg_1); dynIL.WriteTypeConversion(dynValueType, targetField.FieldType); dynIL.Emit(OpCodes.Stfld, targetField); } dynIL.Emit(OpCodes.Ret); // Emit the call to the dynamic method il.WriteMethodCalli(dynMethod, dynParameters); } il.Emit(OpCodes.Ret); return(method); }
private static MethodBuilder GetFieldGetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, FieldInfo targetField, FieldInfo instanceField) { string proxyMemberName = proxyMember.Name; Type proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType : proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object); MethodBuilder proxyMethod = proxyTypeBuilder.DefineMethod( "get_" + proxyMemberName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, proxyMemberReturnType, Type.EmptyTypes); ILGenerator il = proxyMethod.GetILGenerator(); Type returnType = targetField.FieldType; // Load the instance if (!targetField.IsStatic) { il.Emit(OpCodes.Ldarg_0); il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField); } // Load the field value to the stack if (UseDirectAccessTo(targetType) && targetField.IsPublic) { // In case is public is pretty simple il.Emit(targetField.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, targetField); } else { // If the instance or the field are non public we need to create a Dynamic method to overpass the visibility checks // we can't access non public types so we have to cast to object type (in the instance object and the return type if is needed). string dynMethodName = $"_getNonPublicField+{targetField.DeclaringType.Name}.{targetField.Name}"; returnType = UseDirectAccessTo(targetField.FieldType) ? targetField.FieldType : typeof(object); // We create the dynamic method Type[] dynParameters = targetField.IsStatic ? Type.EmptyTypes : new[] { typeof(object) }; DynamicMethod dynMethod = new DynamicMethod(dynMethodName, returnType, dynParameters, typeof(DuckType).Module, true); // We store the dynamic method in a bag to avoid getting collected by the GC. DynamicMethods.Add(dynMethod); // Emit the dynamic method body ILGenerator dynIL = dynMethod.GetILGenerator(); if (!targetField.IsStatic) { // Emit the instance load in the dynamic method dynIL.Emit(OpCodes.Ldarg_0); if (targetField.DeclaringType != typeof(object)) { dynIL.Emit(targetField.DeclaringType !.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, targetField.DeclaringType); } } // Emit the field and convert before returning (in case of boxing) dynIL.Emit(targetField.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, targetField); dynIL.WriteTypeConversion(targetField.FieldType, returnType); dynIL.Emit(OpCodes.Ret); // Emit the call to the dynamic method il.WriteMethodCalli(dynMethod, dynParameters); } // Check if the type can be converted or if we need to enable duck chaining if (NeedsDuckChaining(targetField.FieldType, proxyMemberReturnType)) { // We call DuckType.CreateCache<>.Create() MethodInfo getProxyMethodInfo = typeof(CreateCache <>) .MakeGenericType(proxyMemberReturnType).GetMethod("Create"); il.Emit(OpCodes.Call, getProxyMethodInfo); } else if (returnType != proxyMemberReturnType) { // If the type is not the expected type we try a conversion. il.WriteTypeConversion(returnType, proxyMemberReturnType); } il.Emit(OpCodes.Ret); return(proxyMethod); }
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 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); }
public void TestSetReadOnlyField() { var setter = DynamicMethods.Setter <Item2, string>(x => x.Name); Assert.IsNull(setter); }