Esempio n. 1
0
        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);
        }
Esempio n. 2
0
 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]);
     }
 }
Esempio n. 3
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);
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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);
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
            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);
            }
Esempio n. 13
0
        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));
            }
Esempio n. 15
0
        /// <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);
            }
        }
Esempio n. 16
0
        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);
        }
Esempio n. 17
0
        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);
        }
Esempio n. 19
0
        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);
        }
Esempio n. 20
0
        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);
        }
Esempio n. 21
0
        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);
        }
Esempio n. 22
0
        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);
        }
Esempio n. 23
0
        public void TestSetReadOnlyField()
        {
            var setter = DynamicMethods.Setter <Item2, string>(x => x.Name);

            Assert.IsNull(setter);
        }