Esempio n. 1
0
        public static Type CreateInterfaceProxy(Type interfaceType)
        {
            if (null == interfaceType)
            {
                throw new ArgumentNullException(nameof(interfaceType));
            }
            if (!interfaceType.IsInterface)
            {
                throw new InvalidOperationException($"{interfaceType.FullName} is not an interface");
            }

            var proxyTypeName = _proxyTypeNameResolver(interfaceType, null);

            if (_proxyTypes.TryGetValue(proxyTypeName, out var proxyType))
            {
                return(proxyType);
            }

            lock (_typeLock)
            {
                if (_proxyTypes.TryGetValue(proxyTypeName, out proxyType))
                {
                    return(proxyType);
                }

                var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(object), new[] { interfaceType });

                GenericParameterUtils.DefineGenericParameter(interfaceType, typeBuilder);

                // define default constructor
                typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);

                // properties
                var propertyMethods = new HashSet <string>();

                var properties = interfaceType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
                foreach (var property in properties)
                {
                    var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes);
                    var field           = typeBuilder.DefineField($"_{property.Name}", property.PropertyType, FieldAttributes.Private);
                    if (property.CanRead)
                    {
                        var methodBuilder = typeBuilder.DefineMethod(property.GetMethod.Name, InterfaceMethodAttributes, property.GetMethod.CallingConvention, property.GetMethod.ReturnType, property.GetMethod.GetParameters().Select(p => p.ParameterType).ToArray());
                        var ilGen         = methodBuilder.GetILGenerator();
                        ilGen.Emit(OpCodes.Ldarg_0);
                        ilGen.Emit(OpCodes.Ldfld, field);
                        ilGen.Emit(OpCodes.Ret);
                        typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod);
                        propertyBuilder.SetGetMethod(methodBuilder);
                        propertyMethods.Add(property.GetMethod.Name);
                    }
                    if (property.CanWrite)
                    {
                        var methodBuilder = typeBuilder.DefineMethod(property.SetMethod.Name, InterfaceMethodAttributes, property.SetMethod.CallingConvention, property.SetMethod.ReturnType, property.SetMethod.GetParameters().Select(p => p.ParameterType).ToArray());
                        var ilGen         = methodBuilder.GetILGenerator();
                        ilGen.Emit(OpCodes.Ldarg_0);
                        ilGen.Emit(OpCodes.Ldarg_1);
                        ilGen.Emit(OpCodes.Stfld, field);
                        ilGen.Emit(OpCodes.Ret);
                        typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod);
                        propertyBuilder.SetSetMethod(methodBuilder);
                        propertyMethods.Add(property.SetMethod.Name);
                    }
                    foreach (var customAttributeData in property.CustomAttributes)
                    {
                        propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData));
                    }
                }

                // methods
                var methods = interfaceType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                foreach (var method in methods.Where(x => !propertyMethods.Contains(x.Name) && !_ignoredMethods.Contains(x.Name)))
                {
                    MethodUtils.DefineInterfaceMethod(typeBuilder, method, null);
                }

                foreach (var implementedInterface in interfaceType.GetImplementedInterfaces())
                {
                    properties = implementedInterface.GetProperties(BindingFlags.Instance | BindingFlags.Public);
                    foreach (var property in properties)
                    {
                        var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes);
                        var field           = typeBuilder.DefineField($"_{property.Name}", property.PropertyType, FieldAttributes.Private);
                        if (property.CanRead)
                        {
                            var methodBuilder = typeBuilder.DefineMethod(property.GetMethod.Name, InterfaceMethodAttributes, property.GetMethod.CallingConvention, property.GetMethod.ReturnType, property.GetMethod.GetParameters().Select(p => p.ParameterType).ToArray());
                            var ilGen         = methodBuilder.GetILGenerator();
                            ilGen.Emit(OpCodes.Ldarg_0);
                            ilGen.Emit(OpCodes.Ldfld, field);
                            ilGen.Emit(OpCodes.Ret);
                            typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod);
                            propertyBuilder.SetGetMethod(methodBuilder);
                            propertyMethods.Add(property.GetMethod.Name);
                        }
                        if (property.CanWrite)
                        {
                            var methodBuilder = typeBuilder.DefineMethod(property.SetMethod.Name, InterfaceMethodAttributes, property.SetMethod.CallingConvention, property.SetMethod.ReturnType, property.SetMethod.GetParameters().Select(p => p.ParameterType).ToArray());
                            var ilGen         = methodBuilder.GetILGenerator();
                            ilGen.Emit(OpCodes.Ldarg_0);
                            ilGen.Emit(OpCodes.Ldarg_1);
                            ilGen.Emit(OpCodes.Stfld, field);
                            ilGen.Emit(OpCodes.Ret);
                            typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod);
                            propertyBuilder.SetSetMethod(methodBuilder);
                            propertyMethods.Add(property.SetMethod.Name);
                        }
                        foreach (var customAttributeData in property.CustomAttributes)
                        {
                            propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData));
                        }
                    }

                    methods = implementedInterface.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                    foreach (var method in methods.Where(x => !propertyMethods.Contains(x.Name) && !_ignoredMethods.Contains(x.Name)))
                    {
                        MethodUtils.DefineInterfaceMethod(typeBuilder, method, null);
                    }
                }

                proxyType = typeBuilder.CreateType();
                _proxyTypes[proxyTypeName] = proxyType;
                return(proxyType);
            }
        }
        public static Type CreateInterfaceProxy(Type interfaceType, Type implementType)
        {
            if (null == interfaceType)
            {
                throw new ArgumentNullException(nameof(interfaceType));
            }
            if (!interfaceType.IsInterface)
            {
                throw new InvalidOperationException($"{interfaceType.FullName} is not an interface");
            }

            if (null == implementType)
            {
                return(CreateInterfaceProxy(interfaceType));
            }

            if (implementType.IsSealed)
            {
                throw new InvalidOperationException("the implementType is sealed");
            }

            var proxyTypeName = _proxyTypeNameResolver(interfaceType, implementType);
            var type          = _proxyTypes.GetOrAdd(proxyTypeName, name =>
            {
                var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, implementType.Attributes, implementType, new[] { interfaceType });
                GenericParameterUtils.DefineGenericParameter(interfaceType, typeBuilder);

                var targetField = typeBuilder.DefineField(TargetFieldName, implementType, FieldAttributes.Private);
                // constructors
                foreach (var constructor in implementType.GetConstructors())
                {
                    var constructorTypes   = constructor.GetParameters().Select(o => o.ParameterType).ToArray();
                    var constructorBuilder = typeBuilder.DefineConstructor(
                        constructor.Attributes,
                        constructor.CallingConvention,
                        constructorTypes);
                    foreach (var customAttribute in constructor.CustomAttributes)
                    {
                        constructorBuilder.SetCustomAttribute(DefineCustomAttribute(customAttribute));
                    }
                    var il = constructorBuilder.GetILGenerator();

                    il.EmitThis();
                    for (var i = 0; i < constructorTypes.Length; i++)
                    {
                        il.Emit(OpCodes.Ldarg, i + 1);
                    }
                    il.Call(constructor);

                    il.EmitThis();
                    il.EmitThis();
                    il.Emit(OpCodes.Stfld, targetField);

                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ret);
                }

                // properties
                var propertyMethods = new HashSet <string>();
                var properties      = interfaceType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
                foreach (var property in properties)
                {
                    var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes);
                    if (property.CanRead)
                    {
                        var methodBuilder = MethodUtils.DefineInterfaceMethod(typeBuilder, property.GetMethod, targetField);
                        typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod);
                        propertyBuilder.SetGetMethod(methodBuilder);
                        propertyMethods.Add(property.GetMethod.Name);
                    }
                    if (property.CanWrite)
                    {
                        var methodBuilder = MethodUtils.DefineInterfaceMethod(typeBuilder, property.SetMethod, targetField);
                        typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod);
                        propertyBuilder.SetSetMethod(methodBuilder);
                        propertyMethods.Add(property.SetMethod.Name);
                    }
                    foreach (var customAttributeData in property.CustomAttributes)
                    {
                        propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData));
                    }
                }

                //
                var methods = interfaceType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                foreach (var method in methods)
                {
                    if (propertyMethods.Contains(method.Name) || _ignoredMethods.Contains(method.Name))
                    {
                        continue;
                    }
                    MethodUtils.DefineInterfaceMethod(typeBuilder, method, targetField);
                }

                foreach (var implementedInterface in interfaceType.GetImplementedInterfaces())
                {
                    properties = implementedInterface.GetProperties(BindingFlags.Instance | BindingFlags.Public);
                    foreach (var property in properties)
                    {
                        var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes);
                        var field           = typeBuilder.DefineField($"_{property.Name}", property.PropertyType, FieldAttributes.Private);
                        if (property.CanRead)
                        {
                            var methodBuilder = typeBuilder.DefineMethod(property.GetMethod.Name, InterfaceMethodAttributes, property.GetMethod.CallingConvention, property.GetMethod.ReturnType, property.GetMethod.GetParameters().Select(p => p.ParameterType).ToArray());
                            var ilGen         = methodBuilder.GetILGenerator();
                            ilGen.Emit(OpCodes.Ldarg_0);
                            ilGen.Emit(OpCodes.Ldfld, field);
                            ilGen.Emit(OpCodes.Ret);
                            typeBuilder.DefineMethodOverride(methodBuilder, property.GetMethod);
                            propertyBuilder.SetGetMethod(methodBuilder);
                            propertyMethods.Add(property.GetMethod.Name);
                        }
                        if (property.CanWrite)
                        {
                            var methodBuilder = typeBuilder.DefineMethod(property.SetMethod.Name, InterfaceMethodAttributes, property.SetMethod.CallingConvention, property.SetMethod.ReturnType, property.SetMethod.GetParameters().Select(p => p.ParameterType).ToArray());
                            var ilGen         = methodBuilder.GetILGenerator();
                            ilGen.Emit(OpCodes.Ldarg_0);
                            ilGen.Emit(OpCodes.Ldarg_1);
                            ilGen.Emit(OpCodes.Stfld, field);
                            ilGen.Emit(OpCodes.Ret);
                            typeBuilder.DefineMethodOverride(methodBuilder, property.SetMethod);
                            propertyBuilder.SetSetMethod(methodBuilder);
                            propertyMethods.Add(property.SetMethod.Name);
                        }
                        foreach (var customAttributeData in property.CustomAttributes)
                        {
                            propertyBuilder.SetCustomAttribute(DefineCustomAttribute(customAttributeData));
                        }
                    }

                    methods = implementedInterface.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                    foreach (var method in methods.Where(x => !propertyMethods.Contains(x.Name) && !_ignoredMethods.Contains(x.Name)))
                    {
                        MethodUtils.DefineInterfaceMethod(typeBuilder, method, null);
                    }
                }

                return(typeBuilder.CreateType());
            });

            return(type);
        }