.NET内存中动态构造类并重载某函数

开发中,经常需要用到很多容器功能,而容器级别的功能大都是Reflection(类反射)所提供的,本文就是借这个名来看看如何在.NET 内存中动态构造类并重载某函数,具体的例子代码如下:

原类:TestClass

内存中动态生成类: TestClassEx

内存中动态生成类的工厂类:DynamicFactory

接口: ITest

复制以及重载的目标方法:TestMethod

调用集成采用Console方式进行,我们分别看看各个类的代码;

 

TestClass.cs

public class TestClass
    {
        private long m_lUsers = 0;
        private int m_iUsers = 0;
        private string m_strTest = null;
        private object m_oTest = null;

        public TestClass()
        {
            m_lUsers++;
            m_iUsers++;
            m_strTest = "aa";
            m_oTest = new object();
        }

        public long Users
        {
            set
            {
                m_lUsers = value;
            }
            get
            {
                return m_lUsers;
            }
        }

        public void TestMethod()
        {
            System.Console.WriteLine("TestMethod: Message output from Emit Console...");

            m_lUsers = 50;
            m_lUsers += 100;
            System.Console.WriteLine("Users :" + Convert.ToString(m_lUsers) + " people in current context");
        }

        public void EndMethod()
        {
            System.Console.WriteLine("EndMethod:Ending message logic*****");
        }

    }

 

ITest.cs

public interface ITest
    {
        void TestMethod();
    }

 

DynamicFactory.cs

public class DynamicFactory
    {
        private AssemblyBuilder assemblyBuilder = null;
        private ModuleBuilder moduleBuilder = null;
        private TypeBuilder typeBuilder = null;
        private ILGenerator generator = null;

        public DynamicFactory()
        {
        }
       
        public Type GenerateClass(Type typeForMirror)
        {
            this.GenerateAssembly();
           
            //build a type
            this.typeBuilder = moduleBuilder.DefineType("TestClassEx",
                                TypeAttributes.Public | TypeAttributes.BeforeFieldInit,
                                typeForMirror, new Type[] { typeof(ITest) });

            this.GenerateConstruct(typeBuilder);
            this.BuildFields(typeForMirror);

            this.BuildMethod(typeForMirror);
                       
            Type typeReturn = this.typeBuilder.CreateType(); //Close the type
            assemblyBuilder.Save("ExtendingAssembly.dll");
            return typeReturn;
        }

        private void BuildFields(Type typeForMirror)
        {
            FieldInfo[] fieldInfos = typeForMirror.GetFields(BindingFlags.NonPublic | BindingFlags.Public);
            for (int i = 0; i < fieldInfos.Length; i++)
            {
                FieldInfo fi = fieldInfos[i];
                typeBuilder.DefineField(fi.Name, fi.FieldType, fi.Attributes);           
            }
        }
       
        private void GenerateAssembly()
        {
            AppDomain currentDomain = Thread.GetDomain();
            AssemblyName assemblyName = new AssemblyName();
            assemblyName.Name = "Extending";
            assemblyBuilder = currentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            this.moduleBuilder = assemblyBuilder.DefineDynamicModule(
                "ExtendingAssembly",
                "ExtendingAssembly.dll");
        }
       
        private void GenerateConstruct(TypeBuilder typeBuilder)
        {
            ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
                 MethodAttributes.Public,
                 CallingConventions.Standard,
                 System.Type.EmptyTypes);

            this.generator = constructorBuilder.GetILGenerator();
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Call, typeBuilder.BaseType.GetConstructor(System.Type.EmptyTypes));
            generator.Emit(OpCodes.Ret);
        }
       
        /// <summary>
        /// Attention: here we need to overload the specified TestMethod function for our EmitConsole project.
        /// So the MethodAttributes.Virtual is necessary when we rebuild this function in memory.
        /// </summary>
        /// <param name="typeForMirror"></param>
        private void BuildMethod(Type typeForMirror)
        {
            // Now, let's build a method and add a custom attribute to it.
            MethodBuilder methodBuilder = typeBuilder.DefineMethod("TestMethod",
                            MethodAttributes.Public | MethodAttributes.HideBySig |
                            MethodAttributes.Virtual | MethodAttributes.NewSlot,
                            null,
                            new Type[] {});

            this.generator = methodBuilder.GetILGenerator();

            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Call, typeForMirror.GetMethod("TestMethod"));

            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Call, typeForMirror.GetMethod("EndMethod"));

            generator.Emit(OpCodes.Ret);
        }

    }

 

console的集成类program.cs:

class Program
    {
        static void Main(string[] args)
        {
            DynamicFactory df = new DynamicFactory();
       
            // type for mirroring testing method
            Type typeMirror = df.GenerateClass(typeof(TestClass));

            object o = Activator.CreateInstance(typeMirror);
            TestClass tc = (TestClass)o;
            tc.TestMethod();

            ITest it = (ITest)Activator.CreateInstance(typeMirror);
            it.TestMethod();

            System.Console.WriteLine("Ending finally...");
        }
    }

 

从最后的运行效果大家可以分析看看,采用TestClass强转后的instance与不转使用interface来直接集成的program最后的结果不一样,自己可以分析看看是啥原因产生的。

 本文中未提及到的Enum, Property等的复制产生可以参照:http://www.codeproject.com/KB/cs/DLR.aspx

能够在内存中动态重组类的作用非常大,可以实现基于AOP的拦截,实现基于标注的各类应用譬如自动组装Transaction、依赖注入等众多的高级应用,对于编写框架应用作用无疑巨大。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值