一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

IoC原理-使用反射/Emit來實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的IoC容器

 賈朋亮博客 2013-10-30

從Unity到Spring.Net,到Ninject,幾年來陸陸續(xù)續(xù)用過幾個(gè)IoC 框架。雖然會(huì)用,但也沒有一直仔細(xì)的研究過IoC實(shí)現(xiàn)的過程。最近花了點(diǎn)時(shí)間,下了Ninject的源碼,研究了一番,頗有收獲。下面我要實(shí)現(xiàn)一個(gè)最最簡(jiǎn) 單的IoC容器,以讓跟我一樣的小菜能更好的理解IoC框架的到底為我們做了什么。

什么是IoC

IoC是英文Inversion of Control的縮寫。我們一般叫它“控制反轉(zhuǎn)”。IoC技術(shù)是用來解決面向?qū)ο笤O(shè)計(jì)一大原則依賴倒置而出現(xiàn)的技術(shù)??梢愿玫膶?shí)現(xiàn)面向接口編程,來使各個(gè)組件之間解耦。

IoC的實(shí)現(xiàn)原理

.NET IoC容器的一般就是兩種,一是反射,二是使用Emit來直接寫IL。

廢話不多了,想要了解跟多的IoC的知識(shí)請(qǐng)Google。

關(guān)于實(shí)現(xiàn)

先上一張類圖

image

1.定義IIoCConfig接口

  public interface IIoCConfig
    {
        void AddConfig<TInterface,TType>();

        Dictionary<Type, Type> ConfigDictionary { get; }
    }

 

2.定義IoCConfig實(shí)現(xiàn)

   public class IoCConfig:IIoCConfig
    {
        /// <summary>
        /// 存放配置的字典對(duì)象,KEY是接口類型,VALUE是實(shí)現(xiàn)接口的類型
        /// </summary>
        private Dictionary<Type, Type> _configDictionary=new Dictionary<Type, Type>();

        /// <summary>
        /// 添加配置
        /// </summary>
        /// <typeparam name="TInterface">接口</typeparam>
        /// <typeparam name="TType">實(shí)現(xiàn)接口的類型</typeparam>
        public void AddConfig<TInterface, TType>()
        {
            //判斷TType是否實(shí)現(xiàn)TInterface
            if (typeof(TInterface).IsAssignableFrom(typeof(TType)))
            {
                _configDictionary.Add(typeof(TInterface), typeof(TType));
            }
            else
            {
                throw  new Exception("類型未實(shí)現(xiàn)接口");
            }
        }

        public Dictionary<Type, Type> ConfigDictionary
        {
            get
            {
                return _configDictionary;
            }
        }
    }

使用一個(gè)字典來保存Interface跟Class的對(duì)應(yīng)關(guān)系。這里是仿造Ninject的配置方式,使用代碼來配置。這種配置方式有個(gè)好處就是不 會(huì)寫錯(cuò),因?yàn)橛蠭DE來給你檢查拼寫錯(cuò)誤。不要小看這個(gè)好處,當(dāng)你有上百個(gè)注入對(duì)象的時(shí)候,使用Unity的XML來配置對(duì)應(yīng)關(guān)系的時(shí)候很容易就會(huì)發(fā)生拼 寫錯(cuò)誤。這種錯(cuò)誤往往還很難發(fā)現(xiàn)。

當(dāng)然這里要實(shí)現(xiàn)一個(gè)按照XML配置文件來設(shè)置對(duì)應(yīng)關(guān)系的類也很容易,這里就不實(shí)現(xiàn)了。

 

3.定義IIoCContainer容器接口

public interface IIoCContainer
    {
        /// <summary>
        /// 根據(jù)接口返回對(duì)應(yīng)的實(shí)例
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <returns></returns>
        TInterface Get<TInterface>();
    }
 

4.使用反射實(shí)現(xiàn)IoC容器

public class ReflectionContainer:IIoCContainer
    {
        /// <summary>
        /// 配置實(shí)例
        /// </summary>
        private IIoCConfig _config;

        /// <summary>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="config">ioc配置</param>
        public ReflectionContainer(IIoCConfig config)
        {
            _config = config;
        }

        /// <summary>
        /// 根據(jù)接口獲取實(shí)例對(duì)象
        /// </summary>
        /// <typeparam name="TInterface">接口</typeparam>
        /// <returns></returns>
        public TInterface Get<TInterface>()
        {
            Type type;
            var can = _config.ConfigDictionary.TryGetValue(typeof(TInterface), out type);
            if (can)
            {
               //反射實(shí)例化對(duì)象
                return (TInterface)Activator.CreateInstance(type);
            }
            else
            {
                throw new Exception("未找到對(duì)應(yīng)的類型");
            }
        }
    }

反射這個(gè)代碼太簡(jiǎn)單了,大家都會(huì)用。

5.使用Emit實(shí)現(xiàn)IoC容器

 public class EmitContainer:IIoCContainer
    {
        /// <summary>
        /// 配置實(shí)例
        /// </summary>
        private IIoCConfig _config;

        public EmitContainer(IIoCConfig config)
        {
            _config = config;
        }

        /// <summary>
        /// 獲取實(shí)例
        /// </summary>
        /// <typeparam name="TInterface">接口</typeparam>
        /// <returns></returns>
        public TInterface Get<TInterface>()
        {
            Type type;
            var can = _config.ConfigDictionary.TryGetValue(typeof(TInterface), out type);
            if (can)
            {
                BindingFlags defaultFlags = BindingFlags.Public | BindingFlags.Instance;
                var constructors = type.GetConstructors(defaultFlags);//獲取默認(rèn)構(gòu)造函數(shù)
                var t = (TInterface)this.CreateInstanceByEmit(constructors[0]);
                return t;
            }
            else
            {
                throw new Exception("未找到對(duì)應(yīng)的類型");
            }
        }

        /// <summary>
        /// 實(shí)例化對(duì)象 用EMIT
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="constructor"></param>
        /// <returns></returns>
        private Object CreateInstanceByEmit(ConstructorInfo constructor)
        {
            //動(dòng)態(tài)方法
            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString("N"), typeof(Object), new[] { typeof(object[]) }, true);
            //方法IL
            ILGenerator il = dynamicMethod.GetILGenerator();
            //實(shí)例化命令
            il.Emit(OpCodes.Newobj, constructor);
            //如果是值類型裝箱
            if (constructor.ReflectedType.IsValueType)
                il.Emit(OpCodes.Box, constructor.ReflectedType);
            //返回
            il.Emit(OpCodes.Ret);
            //用FUNC去關(guān)聯(lián)方法
            var func = (Func<Object>)dynamicMethod.CreateDelegate(typeof(Func<Object>));
            //執(zhí)行方法
            return func.Invoke();
        }
    }

Emit的實(shí)現(xiàn)是抄自Ninject的實(shí)現(xiàn)方式。這里其實(shí)就是在手動(dòng)書寫IL。一個(gè)簡(jiǎn)單的書寫IL的辦法就是先用C#寫好代碼,然后用Reflector等反編譯工具查看生成的IL,然后改成Emit代碼。

6.實(shí)現(xiàn)IoCContainerManager

 public class IoCContainerManager
    {
        /// <summary>
        /// 容器
        /// </summary>
        private static IIoCContainer _container;

        /// <summary>
        /// 獲取IOC容器
        /// </summary>
        /// <param name="config">ioc配置</param>
        /// <returns></returns>
        public static IIoCContainer GetIoCContainer(IIoCConfig config)
        {
           
                if (_container==null)
                {
                    //反射方式
                    _container = new ReflectionContainer(config);
                    //EMIT方式
                   // _container=new EmitContainer(config);
                }
                return _container;
            
        }
    }
代碼太簡(jiǎn)單,不多說了。
 

7.使用

 
 public interface ITest
    {
        void DoWork();
    }

    public class Test:ITest
    {
        public void DoWork()
        {
           Console.WriteLine("do work!");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IIoCConfig config = new IoCConfig();
            config.AddConfig<ITest, Test>();//添加配置
            //獲取容器
            IIoCContainer container = IoCContainerManager.GetIoCContainer(config);
            //根據(jù)ITest接口去獲取對(duì)應(yīng)的實(shí)例
            ITest test = container.Get<ITest>();

            test.DoWork();

            Console.Read();
        }
    }

輸出:

image

這里手動(dòng)使用IoC容器去獲取對(duì)應(yīng)的實(shí)例對(duì)象,我們也可以配合特性來使代碼更加簡(jiǎn)單。這里就不實(shí)現(xiàn)了。

8.總結(jié)

通過這么短短的幾行代碼。我們實(shí)現(xiàn)了一個(gè)最最簡(jiǎn)單的IoC容器。它可以實(shí)現(xiàn)構(gòu)造函數(shù)注入(默認(rèn)無參)。但是這就已經(jīng)揭示了IoC框架最本質(zhì)的東西: 反射或者EMIT來實(shí)例化對(duì)象。然后我們可以加上緩存,或者一些策略來控制對(duì)象的生命周期,比如是否是單例對(duì)象還是每次都生成一個(gè)新的對(duì)象。

 源碼

BTW:求 蘇州,上海地區(qū)有激情,有意義的技術(shù)類工作?。?/font>

Email:kklldog@gmail.com
作者:Agile.Zhou(kklldog)
出處:http://www.cnblogs.com/kklldog/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    丝袜诱惑一区二区三区| 免费亚洲黄色在线观看| 亚洲精品一区二区三区日韩| 五月婷婷综合缴情六月| 久久综合日韩精品免费观看| 又黄又爽禁片视频在线观看| 日本在线 一区 二区| 免费大片黄在线观看日本| 久久偷拍视频免费观看| 亚洲国产中文字幕在线观看| 欧美日韩国内一区二区| 亚洲美女国产精品久久| 亚洲男人的天堂久久a| 日本av一区二区不卡| 国产传媒高清视频在线| 老熟妇2久久国内精品| 国产亚洲精品香蕉视频播放| 欧美不卡高清一区二区三区| 亚洲妇女黄色三级视频| 国产精品视频一区麻豆专区| 成人免费高清在线一区二区| 精品欧美一区二区三久久| 亚洲男人的天堂久久a| 日韩欧美国产高清在线| 日韩人妻有码一区二区| 男人操女人下面国产剧情| 日韩欧美中文字幕人妻| 日本高清视频在线观看不卡 | 免费在线成人激情视频| 国产亚洲精品岁国产微拍精品 | 麻豆亚州无矿码专区视频| 中文字幕亚洲视频一区二区| 九九九热视频免费观看| 欧美日韩综合在线精品| 日韩一区二区三区高清在| 九九热精彩视频在线播放| 欧洲日本亚洲一区二区| 在线免费看国产精品黄片| 冬爱琴音一区二区中文字幕| 99一级特黄色性生活片| 精品国产日韩一区三区|