C#Emit实现动态代理:配置信息保存和实现

2010-03-23 16:16:17 |

我实现这个动态代理的初衷是,我自己编写了一个配置信息库,可以将配置信息保存到特定的文件中,提供加密的选项,保证数据不会被恶意的读取,但是面对多个应用,不同的配置项带来大量的重复编码工作。

以下是基础配置的读取和设置函数

public object setValue(string key, object v);

public object getValue(string key);

针对某个网站应用的配置类为:

public class WebConfig: ConfigBase

{

public string WebServer

{

get{return getValue(“Server”) as string;}

set{setValue(“Server”,value);

}

public int Port
{
get{return getValue(Port) as int;}
set{setValue(Port,value);
}
public DateTime LastAcessDate
{
get{return getValue(“LastAccess”) as string;}
set{setValue(“LastAccess”,value);
}

}

代码很繁琐,而且很多重复的代码,这是没有什么意义的,所以我考虑用动态代理实现这个类,最终的配置信息变成:

public interface WebConfig

{

string WebServer{get;set;}

int Port{get;set;}

DateTime LastAccessDate{get;set;}

}

WebConfig a=ConfigBase.getConfigItem(typeof(WebConfig));

a.WebServer=”ssss”;

在getConfigItem中返回的实体类中包含了配置信息的读写操作,注意WebConfig没有继承任何基础接口;没有任何类实现了WebConfig的接口函数和属性,嗯,就是能工作,关键就在于Emit生成动态的WebConfig的继承类的实例,然后返回这个实例;同时监视这个实例的函数调用并读写配置文件。

配置实例

public TypedAppConfig()
        {
            m_configurationType = typeof(T);//T template parameter
            m_strSection=m_configurationType.Name+"_configuration";
            m_configurationObject=DynamicProxyFactory.CreateProxy(
                DynamicProxyFactory.CreateImplement<T>(),
                delegate(object target
                    , System.Reflection.MethodBase method
                    , object[] parameters)
                {
                    //Only listen get and set functionality
                    string key = method.Name;
                    if (key.StartsWith("get_"))
                    {
                        key = key.Substring("get_".Length);
                        return DataTypesCopy.FromClass((method as MethodInfo).ReturnType)
                            .CastValue( this.GetValue(m_strSection,key));
                    }
                    else if (key.StartsWith("set_"))
                    {
                        key = key.Substring("set_".Length);
                        this.SetValue(m_strSection,key,parameters[0]);
                        object ret= method.Invoke(target, parameters);
                        return ret;
                    }
                    else
                    {
                        return method.Invoke(target, parameters);
                    }
                }) as T;
               }

下面是核心代码

参考:

http://www.codeproject.com/KB/dotnet/dynamicproxy.aspx

http://www.cnblogs.com/xiaotie/archive/2009/02/01/1381825.html

http://www.pin5i.com/showtopic-22460.html

代码作出了相应的调整

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

public class DynamicProxyFactory
    {
        private DynamicProxyFactory()
        {
        }
        public static object CreateProxy(Type target, InvocationDelegate invocationHandler)
        {
            return CreateProxy(CreateImplement(target), invocationHandler);
        }
        public static object CreateProxy(object target, InvocationDelegate invocationHandler)
        {
            return CreateProxy(target, invocationHandler, false, null);
        }
        public static object CreateProxy(Type target, InvocationDelegate invocationHandler, bool strict)
        {
            return CreateProxy(CreateImplement(target), invocationHandler, strict);
        }
        public static object CreateProxy(object target, InvocationDelegate invocationHandler, bool strict)
        {
            return CreateProxy(target, invocationHandler, strict, null);
        }
        public static object CreateProxy(Type target, InvocationDelegate invocationHandler, bool strict, Type[] supportedTypes)
        {
            return CreateProxy(CreateImplement(target), invocationHandler, strict, supportedTypes);
        }
        public static object CreateProxy(object target, InvocationDelegate invocationHandler, bool strict, Type[] supportedTypes)
        {
            return new DynamicProxyImpl(target, invocationHandler, strict, supportedTypes).GetTransparentProxy();
        }

        #region GenerateInterfaceImplementType
        private static string Interface_DefaultNameSpace = "LonelySkald.DynamicTypes.Proxy.Assembly";
        private static Dictionary<string, Type> Interface_HashTypes = new Dictionary<string, Type>();
        #region create implements
        public static INTERFACE CreateImplement<INTERFACE>(object instance)
            where INTERFACE : class
        {
            return CreateImplement(typeof(INTERFACE), instance) as INTERFACE;
        }
        public static object CreateImplement(Type interfaceType, object inpmlementInstance)
        {
            if (null == interfaceType)
            {
                throw new ArgumentException("The first parameter must not be null!");
            }
            if (null == inpmlementInstance)
            {
                return CreateImplement(interfaceType);
            }
            else
            {
                Type type = GenerateInterfaceImplementType(interfaceType, inpmlementInstance.GetType());
                return Activator.CreateInstance(type, inpmlementInstance);
            }
        }
        public static object CreateImplement(Type interfaceType)
        {
            if (null == interfaceType)
            {
                throw new ArgumentException("The first parameter must not be null!");
            }
            if (interfaceType.IsInterface)
            {
                Type type = GenerateInterfaceImplementType(interfaceType, null);
                return Activator.CreateInstance(type);
            }
            else
            {
                //Guess interface
                Type[] ints = interfaceType.GetInterfaces();
                if (null == ints)
                {
                    throw new ArgumentException(interfaceType.FullName + ": could not found the interface it derived.");
                }
                if (ints.Length > 1)
                {
                    throw new ArgumentException(interfaceType.FullName + ": More than one interfaces it derived.");
                }
                //create a new instance of the target class
                object instance = Activator.CreateInstance(interfaceType);
                Type type = GenerateInterfaceImplementType(interfaceType, ints[0]);
                return Activator.CreateInstance(type, instance);
            }
        }
        public static INTERFACE CreateImplement<INTERFACE>()
            where INTERFACE : class
        {
            return CreateImplement(typeof(INTERFACE)) as INTERFACE;
        }
        #endregion
        #region generate types
        private static Type GenerateInterfaceImplementType(Type typeInterface)
        {
            return GenerateInterfaceImplementType(typeInterface, null);
        }
        public static Type GenerateInterfaceImplementType(Type typeInterface, Type typeImplement)
        {
            if (null == typeInterface)
            {
                throw new ArgumentException("The first argument must not be null!");
            }
            if (typeInterface.IsInterface==false)
            {
                throw new ArgumentException(typeInterface.FullName + " must be an interface instead of a class");
            }
            string strTypeName = "_DynamicTypes" + typeInterface.ToString() + "_" + (typeImplement == null ? "Default" : typeImplement.ToString());
            if (Interface_HashTypes.ContainsKey(strTypeName))
            {
                return Interface_HashTypes[strTypeName];
            }
            lock (Interface_HashTypes)
            {
                PropertyInfo[] pisInterface = typeInterface.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                MethodInfo[] misInterface = typeInterface.GetMethods(BindingFlags.Public | BindingFlags.Instance);
                List<MethodInfo> misInterfaceList = new List<MethodInfo>();
                foreach (var item in misInterface)
                {
                    if (item.IsSpecialName == false) misInterfaceList.Add(item);
                }

                MethodInfo[] misImplex = typeImplement == null ? null : typeImplement.GetMethods(BindingFlags.Public | BindingFlags.Instance);
                AssemblyName aName = new AssemblyName(Interface_DefaultNameSpace);
                AssemblyBuilder ab =
                    AppDomain.CurrentDomain.DefineDynamicAssembly(
                        aName,
                        AssemblyBuilderAccess.RunAndSave);
                ModuleBuilder moduleBuilder =
                    ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

                TypeBuilder typeBuilder = moduleBuilder.DefineType(strTypeName,
                    TypeAttributes.Public, null, new Type[] { typeInterface });
                FieldBuilder fieldBuilder = typeBuilder.DefineField(
                    "__wrappedInstance",
                    null == typeImplement ? typeof(Object) : typeImplement,
                    FieldAttributes.Private);

                ConstructorBuilder ctor1 = typeBuilder.DefineConstructor(
                    MethodAttributes.Public,
                    CallingConventions.Standard,
                    null == typeImplement ? null : new Type[] { typeImplement });

                ILGenerator ctor1IL = ctor1.GetILGenerator();
                ctor1IL.Emit(OpCodes.Ldarg_0);
                ctor1IL.Emit(OpCodes.Call,
                    typeof(object).GetConstructor(Type.EmptyTypes));
                ctor1IL.Emit(OpCodes.Ldarg_0);
                ctor1IL.Emit(OpCodes.Ldarg_1);
                ctor1IL.Emit(OpCodes.Stfld, fieldBuilder);
                ctor1IL.Emit(OpCodes.Ret);

                foreach (PropertyInfo item in pisInterface)
                {
                    MethodInfo getMi = _FindGetMethodInfo(misImplex, item);
                    MethodInfo setMi = FindSetMethodInfo(misImplex, item);
                    _CreateProperty(typeBuilder, fieldBuilder, item, getMi, setMi);
                }

                foreach (MethodInfo item in misInterfaceList)
                {
                    MethodInfo instanceMi = _FindMethodInfo(misImplex, item);
                    _CreateMethod(typeBuilder, fieldBuilder, item, instanceMi);
                }
                Type newType = typeBuilder.CreateType();
                Interface_HashTypes.Add(strTypeName, newType);
                return newType;
            }
        }

        private static MethodInfo _FindGetMethodInfo(MethodInfo[] miList, PropertyInfo pi)
        {
            if (null == miList || null == pi)
            {
                return null;
            }
            foreach (var item in miList)
            {
                if (item.Name.Equals("get_" + pi.Name) && item.IsSpecialName) return item;
            }

            return null;
        }

        private static MethodInfo FindSetMethodInfo(MethodInfo[] miList, PropertyInfo pi)
        {
            if (null == miList || null == pi)
            {
                return null;
            }
            foreach (var item in miList)
            {
                if (item.Name.Equals("set_" + pi.Name) && item.IsSpecialName) return item;
            }

            return null;
        }

        private static MethodInfo _FindMethodInfo(MethodInfo[] miList, MethodInfo mi)
        {
            if (null == miList || null == mi)
            {
                return null;
            }
            foreach (var item in miList)
            {
                if (_MethodInfoEqual(item, mi)) return item;
            }

            return null;
        }

        private static Boolean _MethodInfoEqual(MethodInfo mi1, MethodInfo mi2)
        {
            if (mi1.IsSpecialName == true || mi2.IsSpecialName == true) return false;
            if (mi1.Name != mi2.Name) return false;
            if (mi1.ReturnType != mi2.ReturnType) return false;
            ParameterInfo[] pis1 = mi1.GetParameters();
            ParameterInfo[] pis2 = mi2.GetParameters();
            if (pis1.Length != pis2.Length) return false;
            for (int i = 0; i < pis1.Length; i++)
            {
                ParameterInfo pi1 = pis1[i];
                ParameterInfo pi2 = pis2[i];
                if (pi1.ParameterType != pi2.ParameterType) return false;
            }
            return true;
        }

        private static void _CreateProperty(TypeBuilder typeBuilder, FieldBuilder fieldBuilder, PropertyInfo pi, MethodInfo getMi, MethodInfo setMi)
        {
            String name = pi.Name;
            Type type = pi.PropertyType;

            PropertyBuilder pb = typeBuilder.DefineProperty(
                name,
                PropertyAttributes.HasDefault,
                type,
                null);

            MethodAttributes getSetAttr = MethodAttributes.Public |
                MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final;
            MethodBuilder mbGetAccessor = typeBuilder.DefineMethod(
                "get_" + name,
                getSetAttr,
                type,
                Type.EmptyTypes);

            ILGenerator getIL = mbGetAccessor.GetILGenerator();
            if (getMi == null)
            {
                getIL.Emit(OpCodes.Ldarg_0);
                getIL.Emit(OpCodes.Ldfld, fieldBuilder);
                getIL.Emit(OpCodes.Ret);
            }
            else
            {
                getIL.Emit(OpCodes.Ldarg_0);
                getIL.Emit(OpCodes.Ldfld, fieldBuilder);
                getIL.Emit(OpCodes.Callvirt, getMi);
                getIL.Emit(OpCodes.Ret);
            }

            MethodBuilder mbSetAccessor = typeBuilder.DefineMethod(
                "set_" + name,
                getSetAttr,
                null,
                new Type[] { type });

            ILGenerator setIL = mbSetAccessor.GetILGenerator();
            if (setMi == null)
            {
                setIL.Emit(OpCodes.Ldarg_0);
                setIL.Emit(OpCodes.Ldarg_1);
                setIL.Emit(OpCodes.Stfld, fieldBuilder);
                setIL.Emit(OpCodes.Ret);
            }
            else
            {
                setIL.Emit(OpCodes.Ldarg_0);
                setIL.Emit(OpCodes.Ldfld, fieldBuilder);
                setIL.Emit(OpCodes.Ldarg_1);
                setIL.Emit(OpCodes.Callvirt, setMi);
                setIL.Emit(OpCodes.Ret);
            }

            pb.SetGetMethod(mbGetAccessor);
            pb.SetSetMethod(mbSetAccessor);
        }

        private static void _CreateMethod(TypeBuilder typeBuilder, FieldBuilder fieldBuilder, MethodInfo mi, MethodInfo instanceMi)
        {
            List<Type> paramTyleList = new List<Type>();
            foreach (var item in mi.GetParameters())
                paramTyleList.Add(item.ParameterType);

            MethodBuilder mb = typeBuilder.DefineMethod(
              mi.Name,
              MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
              mi.ReturnType,
              paramTyleList.ToArray());

            ILGenerator il = mb.GetILGenerator();
            if (instanceMi == null)
            {
                il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[] { }));
                il.Emit(OpCodes.Throw);
            }
            else
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, fieldBuilder);
                switch (paramTyleList.Count)
                {
                    case 0:
                        break;
                    case 1:
                        il.Emit(OpCodes.Ldarg_1);
                        break;
                    case 2:
                        il.Emit(OpCodes.Ldarg_1);
                        il.Emit(OpCodes.Ldarg_2);
                        break;
                    case 3:
                        il.Emit(OpCodes.Ldarg_1);
                        il.Emit(OpCodes.Ldarg_2);
                        il.Emit(OpCodes.Ldarg_3);
                        break;
                    default:
                        il.Emit(OpCodes.Ldarg_1);
                        il.Emit(OpCodes.Ldarg_2);
                        il.Emit(OpCodes.Ldarg_3);

                        Int32 sCount = Math.Min(paramTyleList.Count, 127);
                        for (int i = 4; i <= sCount; i++)
                        {
                            il.Emit(OpCodes.Ldarg_S, i);
                        }

                        for (int i = 128; i <= paramTyleList.Count; i++)
                        {
                            il.Emit(OpCodes.Ldarg, i);
                        }

                        break;
                }
                //Invoke the old functionality
                il.Emit(OpCodes.Callvirt, instanceMi);
                il.Emit(OpCodes.Ret);
            }
        }
        #endregion
        #endregion

    }
    #region helper classes
    public class DynamicProxyImpl :
        System.Runtime.Remoting.Proxies.RealProxy, IDynamicProxy
        , System.Runtime.Remoting.IRemotingTypeInfo
    {
        private object proxyTarget;
        private bool strict;
        private Type[] supportedTypes;
        private InvocationDelegate invocationHandler;
        protected internal DynamicProxyImpl(object proxyTarget
            , InvocationDelegate invocationHandler
            , bool strict
            , Type[] supportedTypes)
            : base(typeof(IDynamicProxy))
        {
            this.proxyTarget = proxyTarget;
            this.invocationHandler = invocationHandler;
            this.strict = strict;
            this.supportedTypes = supportedTypes;
        }
        public override System.Runtime.Remoting.ObjRef CreateObjRef(System.Type type)
        {
            throw new NotSupportedException("ObjRef for DynamicProxy isn't supported");
        }
        public bool CanCastTo(System.Type toType, object obj)
        {
            // Assume we can (which is the default unless strict is true)
            bool canCast = true;

            if (strict)
            {
                // First check if the proxyTarget supports the cast
                if (toType.IsAssignableFrom(proxyTarget.GetType()))
                {
                    canCast = true;
                }
                else if (supportedTypes != null)
                {
                    canCast = false;
                    // Check if the list of supported interfaces supports the cast
                    foreach (Type type in supportedTypes)
                    {
                        if (toType == type)
                        {
                            canCast = true;
                            break;
                        }
                    }
                }
                else
                {
                    canCast = false;
                }
            }

            return canCast;
        }
        public string TypeName
        {
            get { throw new System.NotSupportedException("TypeName for DynamicProxy isn't supported"); }
            set { throw new System.NotSupportedException("TypeName for DynamicProxy isn't supported"); }
        }
        public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage message)
        {
            // Convert to a MethodCallMessage
            System.Runtime.Remoting.Messaging.IMethodCallMessage methodMessage = new System.Runtime.Remoting.Messaging.MethodCallMessageWrapper((System.Runtime.Remoting.Messaging.IMethodCallMessage)message);

            // Extract the method being called
            System.Reflection.MethodBase method = methodMessage.MethodBase;

            // Perform the call
            object returnValue = null;
            if (method.DeclaringType == typeof(IDynamicProxy))
            {
                // Handle IDynamicProxy interface calls on this instance instead of on the proxy target instance
                returnValue = method.Invoke(this, methodMessage.Args);
            }
            else
            {
                // Delegate to the invocation handler
                returnValue = invocationHandler(proxyTarget, method, methodMessage.Args);
            }

            // Create the return message (ReturnMessage)
            System.Runtime.Remoting.Messaging.ReturnMessage returnMessage = new System.Runtime.Remoting.Messaging.ReturnMessage(returnValue, methodMessage.Args, methodMessage.ArgCount, methodMessage.LogicalCallContext, methodMessage);
            return returnMessage;
        }
        public object ProxyTarget
        {
            get { return proxyTarget; }
            set { proxyTarget = value; }
        }
        public InvocationDelegate InvocationHandler
        {
            get { return invocationHandler; }
            set { invocationHandler = value; }
        }
        public bool Strict
        {
            get { return strict; }
            set { strict = value; }
        }
        public Type[] SupportedTypes
        {
            get { return supportedTypes; }
            set { supportedTypes = value; }
        }

    }
    public delegate object InvocationDelegate(object target
    , System.Reflection.MethodBase method
    , object[] parameters);
    public interface IDynamicProxy
    {
        object ProxyTarget
        {
            get;
            set;
        }
        InvocationDelegate InvocationHandler
        {
            get;
            set;
        }
        bool Strict
        {
            get;
            set;
        }
        Type[] SupportedTypes
        {
            get;
            set;
        }
    }
    #endregion


Jeason Zhao (沈胜衣,斛律光) ------雪饮再现,一个人的江湖
我知道我是谁,我是沈胜衣,默默的活着,就像空气。

Add comment




biuquote
  • Comment
  • Preview
Loading