示例#1
0
        public static bool DuckIs(this object instance, Type targetType)
        {
            if (instance is null)
            {
                DuckTypeTargetObjectInstanceIsNull.Throw();
            }

            if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
            {
                return(DuckType.CanCreate(targetType, instance));
            }

            return(false);
        }
示例#2
0
        public static bool DuckIs <T>(this object instance)
        {
            if (instance is null)
            {
                DuckTypeTargetObjectInstanceIsNull.Throw();
            }

            if (DuckType.CreateCache <T> .IsVisible)
            {
                return(DuckType.CanCreate <T>(instance));
            }

            return(false);
        }
示例#3
0
        public static object DuckAs(this object instance, Type targetType)
        {
            if (instance is null)
            {
                DuckTypeTargetObjectInstanceIsNull.Throw();
            }

            if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
            {
                var proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
                if (proxyResult.Success)
                {
                    return(proxyResult.CreateInstance(instance));
                }
            }

            return(null);
        }
示例#4
0
        public static bool TryDuckCast(this object instance, Type targetType, out object value)
        {
            if (instance is null)
            {
                DuckTypeTargetObjectInstanceIsNull.Throw();
            }

            if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
            {
                var proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
                if (proxyResult.Success)
                {
                    value = proxyResult.CreateInstance(instance);
                    return(true);
                }
            }

            value = default;
            return(false);
        }
示例#5
0
        private static MethodBuilder GetFieldGetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, FieldInfo targetField,
                                                       FieldInfo instanceField
                                                       )
        {
            var proxyMemberName       = proxyMember.Name;
            var proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType :
                                        proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object);

            var proxyMethod = proxyTypeBuilder.DefineMethod(
                "get_" + proxyMemberName,
                MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig
                | MethodAttributes.Virtual,
                proxyMemberReturnType,
                Type.EmptyTypes);

            var il         = new LazyILGenerator(proxyMethod.GetILGenerator());
            var 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(proxyTypeBuilder, 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).
                var dynMethodName = $"_getNonPublicField_{targetField.DeclaringType.Name}_{targetField.Name}";
                returnType = UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType) ? targetField.FieldType : typeof(object);

                // We create the dynamic method
                var dynParameters = targetField.IsStatic ? Type.EmptyTypes : new[] { typeof(object) };
                var dynMethod     = new DynamicMethod(dynMethodName, returnType, dynParameters, proxyTypeBuilder.Module, true);

                // Emit the dynamic method body
                var dynIL = new LazyILGenerator(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);
                dynIL.Flush();

                // Emit the call to the dynamic method
                il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder);
            }

            // Check if the type can be converted or if we need to enable duck chaining
            if (DuckType.NeedsDuckChaining(targetField.FieldType, proxyMemberReturnType))
            {
                if (UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType) && targetField.FieldType.IsValueType)
                {
                    il.Emit(OpCodes.Box, targetField.FieldType);
                }

                // We call DuckType.CreateCache<>.Create()
                var getProxyMethodInfo = typeof(DuckType.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);
            il.Flush();
            _methodBuilderGetToken.Invoke(proxyMethod, null);
            return(proxyMethod);
        }
示例#6
0
        private static MethodBuilder GetFieldSetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, FieldInfo targetField,
                                                       FieldInfo instanceField
                                                       )
        {
            var proxyMemberName       = proxyMember.Name;
            var proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType :
                                        proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object);

            var method = proxyTypeBuilder.DefineMethod(
                "set_" + proxyMemberName,
                MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig
                | MethodAttributes.Virtual,
                typeof(void),
                new[] { proxyMemberReturnType });

            var il = new LazyILGenerator(method.GetILGenerator());
            var 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 (DuckType.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(proxyTypeBuilder, 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

                var dynMethodName = $"_setField_{targetField.DeclaringType.Name}_{targetField.Name}";

                // Convert the field type for the dynamic method
                var dynValueType = UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType) ? targetField.FieldType : typeof(object);
                il.WriteTypeConversion(currentValueType, dynValueType);

                // Create dynamic method
                var dynParameters = targetField.IsStatic ? new[] { dynValueType } : new[] { typeof(object), dynValueType };
                var dynMethod     = new DynamicMethod(dynMethodName, typeof(void), dynParameters, proxyTypeBuilder.Module, true);

                // Write the dynamic method body
                var dynIL = new LazyILGenerator(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);
                dynIL.Flush();

                // Emit the call to the dynamic method
                il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder);
            }

            il.Emit(OpCodes.Ret);
            il.Flush();
            _methodBuilderGetToken.Invoke(method, null);
            return(method);
        }
示例#7
0
 public static object DuckCast(this object instance, Type targetType)
 => DuckType.Create(targetType, instance);
示例#8
0
 public static T DuckCast <T>(this object instance)
 => DuckType.Create <T>(instance);