IL實現簡單的IOC容器

来源:http://www.cnblogs.com/lflyq/archive/2016/12/26/6221582.html
-Advertisement-
Play Games

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


   既然瞭解了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對比在性能上也還是有差距的。這塊為什麼會產生這些差異在之後學習再進行分享。也請知道的園友給點指導!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.地址 2.Units單位 1 配置大小單位,開頭定義了一些基本的度量單位,只支持bytes,不支持bit 2 對大小寫不敏感 3.includes包含 ...
  • 存儲過程語法、概念、介紹;如何處理並記錄複雜存儲過程中發生的錯誤 ...
  • 本文出處:http://www.cnblogs.com/wy123/p/6217772.html 字元串自身相加, 雖然賦值給了varchar(max)類型的變了,在某些特殊情況下仍然會被“截斷”,這到底是varchar(max)長度的問題還是操作的問題? 1,兩個不超過8000長度的字元串自身相加 ...
  • 隔離級別定義事務操作資源和更新數據的隔離程度,在SQL Server中,隔離級別隻會影響讀操作申請的共用鎖,而不會影響寫操作申請的互斥鎖。隔離級別控制事務在執行讀操作時: 在讀數據時是否使用共用鎖,申請何種類型的隔離級別; 事務持有讀鎖的時間 讀操作引用其他事務更新的數據行時,控制讀操作的行為: 被 ...
  • Linux環境下寫代碼雖然沒有IDE,但通過給vim配置幾個插件也足夠好用。一般常用的插件主要包括幾類,查找文件,查找符號的定義或者聲明(函數,變數等)以及自動補全功能。一般流程都是下載需要的工具,然後在vimrc文件中配置載入工具選項,一直這麼用也沒覺得啥。但最近發現通過vundle工具可以很方便 ...
  • TCP/IP之Nagle演算法與40ms延遲提到了Nagle 演算法。這樣雖然提高了網路吞吐量,但是實時性卻降低了,在一些交互性很強的應用程式來說是不允許的,使用TCP_NODELAY選項可以禁止Nagle 演算法。禁止Nagle後應用程式向內核遞交的每個數據包都會立即發送出去。但是禁止Nagle,網路傳 ...
  • Nagle演算法是針對網路上存在的微小分組可能會在廣域網上造成擁塞而設計的。該演算法要求一個TCP連接上最多只能有一個未被確認的未完成的小分組,在該分組確認到達之前不能發送其他的小分組。同時,TCP收集這些少量的分組,併在確認到來時以一個分組發出去。它的設計規則如下: (1)如果包長度達到最大報文長度( ...
  • 1.1在這之前,我們需要瞭解程式的編譯過程 a.預處理:檢查語法錯誤,展開巨集,包含頭文件等 b.編譯:*.c-->*.S c.彙編:*.S-->*.o d.鏈接:.o +庫文件=*.exe 1.2體驗在VC下程式的編譯 a.先編譯,在鏈接 b.修改了哪個文件,就單獨編譯此文件,在鏈接 c.修改了哪個 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...