程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> IL實現簡單的IOC容器,ilioc容器

IL實現簡單的IOC容器,ilioc容器

編輯:關於.NET

IL實現簡單的IOC容器,ilioc容器


   既然了解了IL的接口和動態類之間的知識,何不使用進來項目實驗一下呢?而第一反應就是想到了平時經常說的IOC容器,在園子裡搜索了一下也有這類型的文章http://www.cnblogs.com/kklldog/p/3395641.html,借鑒一下前人的知識就來實現一下吧。IOC的概念就不介紹了,想了解的同學就百度一下。

一、定義接口

  首先自定義兩個接口和實現

    public interface IAnimal
    {
        string Cat();

        string Dog();
    }

    public class Animal:IAnimal
    {
        public string Cat()
        {
            return "I Am Cat";
        }

        public string Dog()
        {
            return "I Am Dog";
        }
    }
IAnimal
    public interface IMail
    {
        string SendMail();

        string ReceiveMail();
    }

    public class Mail:IMail
    {
        public string SendMail()
        {
            return "Success Send";
        }

        public string ReceiveMail()
        {
            return "Success Receive";
        }
    }
IMail

二、配置

  這裡我就直接寫一個方法來進行配置,不再定義接口了

        public Dictionary<string,string> GetAllConfig()
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("IOC.Interface.IMail", "IOC.Interface.Mail,IOC");
            dic.Add("IOC.Interface.IAnimal", "IOC.Interface.Animal,IOC");
            return dic;
        }
Config

三、反射實現

        public static object GetInstance(string InterfaceName)
        {
            //已經存在的對象直接使用
            if (dicObj.ContainsKey(InterfaceName))
            {
                return dicObj[InterfaceName];
            }

            var dicConfig = new Config.Config().GetAllConfig();
            if (!dicConfig.ContainsKey(InterfaceName))
            {
                throw new Exception("未配置");
            }
            var config = dicConfig[InterfaceName];

            Type taskType = Type.GetType(config);

           // var taskObj1 = CreateInstance(taskType);
            var taskObj= CreateInstanceByEmit(taskType);


            if (null == taskObj)
                throw new Exception("實例化接口錯誤");

            dicObj.Add(InterfaceName, taskObj);
            return taskObj;
        }
GetInstance
        private static Object CreateInstance(Type taskType)
        {
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            object taskObj = Activator.CreateInstance(taskType);
            stopWatch.Stop();
            TimeSpan ts = stopWatch.Elapsed;

            string elapsedTime = String.Format("{0}",ts.Ticks );
            Console.WriteLine("CreateInstance RunTime " + elapsedTime);
            return taskObj;
        }
CreateInstance

通過傳入接口,再去配置列表中找到對應的實現進行實例化。如果存在就直接使用實例化後的對象

四、Emit實現

要想知道Emit是如何獲取接口對應實例化的對象,可以先進行一下的嘗試。比如我要獲取IAnimal接口實例化的對象

        public IAnimal GetInterface()
        {
            var realize= new Animal();
            return (IAnimal)realize;
        }

通過反編譯工具得到以下的IL信息

IL解釋:

L_0001:創建一個新的對象(構造函數)到計算堆棧上

L_0006-L_0007:先存儲到指定位置再獲取推送到計算堆棧上(實現中可省略)

L_0008-L_000b:同樣是先存儲到指定位置再獲取推送到堆棧上(實現中可省略),br.s跳轉到L_000b執行(針對這段IL沒必要用到這個操作)

L_000c:返回

然後我們可以通過IL代碼進行實現

        private static Object CreateInstanceByEmit(Type taskType)
        {
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            BindingFlags defaultFlags = BindingFlags.Public | BindingFlags.Instance;
            var constructor = taskType.GetConstructors(defaultFlags)[0];//獲取默認構造函數

            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString("N"), typeof(Object), new[] { typeof(object[]) }, true);
            ILGenerator IL = dynamicMethod.GetILGenerator();
            IL.Emit(OpCodes.Newobj, constructor);
            if (constructor.ReflectedType.IsValueType)
                IL.Emit(OpCodes.Box, constructor.ReflectedType);
            IL.Emit(OpCodes.Ret);
            //關聯方法
            var func = (Func<Object>)dynamicMethod.CreateDelegate(typeof(Func<Object>));

            stopWatch.Stop();
            TimeSpan ts = stopWatch.Elapsed;
            string elapsedTime = String.Format("{0}", ts.Ticks);
            Console.WriteLine("CreateInstanceByEmit RunTime " + elapsedTime);

            return func.Invoke();
        }
CreateInstanceByEmit

五、執行

IAnimal iMail = ServiceTaker.GetService<IOC.Interface.IAnimal>();
Console.WriteLine(iMail.Cat());

通過以上的例子算是對Emit加深一下了解,也可以了解一下IOC的實現,當然IOC還有其他東西需要注意這就不一一介紹了。有興趣的同學也歡迎來進行交流

源碼:IOC

 

=============================================================

在實例化對象過程中,發現反射執行的速度還是優於Emit的,在參考http://kb.cnblogs.com/page/171668/發現反射和Emit對比在性能上也還是有差距的。這塊為什麼會產生這些差異在之後學習再進行分享。也請知道的園友給點指導!

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved