<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      白話系列之IOC,三個類實現簡單的Ioc

      前言:博客園上已經有很多IOC的博客.而且很多寫的很好,達到開源的水平,但是對于很多新人來說,只了解ioc的概念,以及怎么去使用ioc.然后想更進一步去看源碼,但是大部分源碼都比較困難,當不知道一個框架整體時候,從每一個片段去推理,其實很耗費時間,所以這篇博客,從autofac及.netcore自帶的ioc的源碼中抽象出最核心代碼,先了解整個ioc的實現方式,其他的所有好的ioc,只是在這個框架上面進行縫縫補補.

      友情提示下,這個ioc雖然能夠使用,但是只是為了做例子,所以只保留最核心代碼,要使用還是使用autofac或成熟的ioc框架.

      一:老生常談

      問:什么是ioc?

      答:依賴注入,是一種思想,由于過分模糊,所以提出DI的觀點:被注入對象依賴IOC容器配置依賴對象

      問:有什么用?

      答:解決高耦合問題,以前沒有ioc的時候,每次都執行的是new操作,這沒什么不好,但是假設,本來使用sqlserver,通過IConnection  conn = new Sqlserver();方式初始化所有的連接操作,但是現在老板要求改成mysql當做數據庫,如果按照new的方式,得一個個去改,全局搜索,全局替換,其實也是可以的,無非是人累點,還需要一遍遍去檢查,看哪里漏了,這時候就懷念Ioc的好處了,只需在容器內改變一處,便全局改變.當然,這里并不是少寫了幾行new代碼,代碼還是一樣的多,只不過new的操作讓容器去處理了.擬人化的方式就是,new的方式就相當于以前沒群的時候,你本來是密令是10, 你一個個去通知你所想要通知的人即new,但是現在呢,密令被敵人偷聽去了,你需要更改,這次改成20,你就得一個個通知,但是現在你每次聯系別人都是通過手機去聯系,你不需要管手機是怎么發送給對方的,只需要知道你給手機一個通知,其他人都可以立馬收到,那么手機在這里扮演的就是容器的概念,一次更改,全部獲悉

      二:理論結束,開始思考準備ioc之前需要準備的東西

      1.首先建立一個收集器,收集可能需要new的對象,那么會有幾種生命周期去new一個對象?

      常用的就是單例模式(singleton), 每次直接new對象,即用即拋(Transient),還有當前請求的主線程中只會創建一個對象(Scope,注意,單例是所有請求都會公用一個對象),所以,先定義接口,如下,命名即功能

          public interface IServiceCollection
          {
              IServiceCollection AddTransient<T1, T2>() where T2 : T1;
              IServiceCollection AddTransient<T1>(T1 t2);
              IServiceCollection AddSingleton<T1, T2>() where T2 : T1;
              IServiceCollection AddSingleton<T1>(T1 t2);
              IServiceCollection AddScoped<T1, T2>() where T2 : T1;
              IServiceCollection AddScoped<T1>(T1 t2);
              IServiceProvider BuildServiceProvider();
          }

       2.其次,建立一個對象提供器,獲取容器內的可以獲取的對象

          越簡單越好,直接通過類型獲取對應的對象,同樣,接口定義如下:

          public interface IServiceProvider
          {
              T GetRequiredService<T>();
              Object GetRequiredService(Type type);
          }

      3.Collection對收集的對象進行保存,并且需要對每個對象進行區分是Singleton,scoped,還是transient的

      注意:我覺得在設計一個好的代碼時候,得弄清楚當前類型具體的作用,然后如果作用不一樣,那么得重新創建一個類型,當然如果后期發現沒必要,可以合并,但是前期還是得分清楚點,就如sql中的范式及反范式.

       3.1:首先定義枚舉,區分當前的類型需要new的類型,與上文中的一致

       

          public enum ServiceLifetime
          {
              Singleton = 0,
              Transient = 1,
              Scoped = 2
          }

       

        3.2:其次需要保存注入進去的類型及周期,因為不去考慮架構,只考慮那ioc的意思,就盡量簡化代碼

       

      三:直接開始擼代碼

       

      1.通過Type創建對象,先默認只創建當前無參構造器,代碼很簡單

       

              public Object GetCache(IDictionary<Type, IServiceCache> typePairs)
              {
                  if (_obj == null)
                  {
                      _obj = Activator.CreateInstance(_type);
                  }
                  switch (_typeEnum)
                  {
                      case ServiceLifetime.Transient:
                          return Activator.CreateInstance(_type);
                      case ServiceLifetime.Singleton:
                          return _obj;
                      case ServiceLifetime.Scoped:
                          throw new Exception("目前不支持scoped");
                      default:
                          throw new Exception("請傳遞正確生命周期");
                  }
              }

       

       

       

      DeepClone的寫法就是通過序列化的方式實現的,JsonConvert

            public static Object DeepClone(this Object obj, Type type)
              {
                  return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj), type);
              }

      2.collection保存對應的對象,繼承IServiceCollection接口

       

          public class ServiceCollection : IServiceCollection
          {
              private ConcurrentDictionary<Type, IServiceCache> _typePairs;
              public ServiceCollection()
              {
                  _typePairs = new ConcurrentDictionary<Type, IServiceCache>();
              }
              public IServiceCollection AddScoped<T1, T2>() where T2 : T1{}
              public IServiceCollection AddScoped<T1>(T1 t2){}
              public IServiceCollection AddSingleton<T1, T2>() where T2 : T1{}
              public IServiceCollection AddTransient<T1, T2>() where T2 : T1{}
              public IServiceCollection AddSingleton<T>(T t2){}
              public IServiceProvider BuildServiceProvider(){}
          }

       實現Singleton及Transient,此處Scoped有些額外的語法糖,等后期會猜想實現

             public IServiceCollection AddSingleton<T1, T2>() where T2 : T1
              {
                  Type t1 = typeof(T1);
                  Type t2 = typeof(T2);
                  ServiceTypeCache service = new ServiceTypeCache(t2, ServiceLifetime.Singleton);
                  if (!_typePairs.TryAdd(t1, service))
                  {
                      throw new Exception("在注入對象時,有相同對象存在");
                  }
                  return this;
              }
              public IServiceCollection AddTransient<T1, T2>() where T2 : T1
              {
                  Type t1 = typeof(T1);
                  Type t2 = typeof(T2);
                  ServiceTypeCache service = new ServiceTypeCache(t2, ServiceLifetime.Transient);
                  if (!_typePairs.TryAdd(t1, service))
                  {
                      throw new Exception("在注入對象時,有相同對象存在");
                  }
                  return this;
              }

       3:實現IServiceProvider接口,就是從Cache中獲取對應的對象

          public class ServiceProvider : IServiceProvider
          {
              private IDictionary<Type, IServiceCache> _cache;
              public ServiceProvider(IDictionary<Type, IServiceCache> valuePairs)
              {
                  _cache = valuePairs;
              }
              public T GetRequiredService<T>()
              {
                  Type t = typeof(T);
                  return (T)GetRequiredService(t);
              }
              public object GetRequiredService(Type type)
              {
                  IServiceCache service = null;
                  if (!_cache.TryGetValue(type, out service))
                  {
                      throw new Exception("獲取參數對象沒有注入");
                  }
                  return service.GetCache();
              }
          }

       

       4:將Collection轉變為ServiceProvider

              public IServiceProvider BuildServiceProvider()
              {
                  return new ServiceProvider(_typePairs);
              }

      5:OK,現在來試試這種簡單注入

          public interface ITestTransient
          {
              void Write();
          }
          public class TestATransient : ITestTransient
          {
              public void Write()
              {
                  Console.WriteLine("----------------A----------------");
              }
          }
          public class TestBTransient : ITestTransient
          {
              public void Write()
              {
                  Console.WriteLine("----------------B----------------");
              }
          }

       

      class Program
          {
              static void Main(string[] args)
              {
                  InitA();
                  InitB();
                  Console.Read();
              }
              public static void InitA()
              {
                  IServiceCollection collection = new ServiceCollection();
                  collection.AddTransient<ITestTransient, TestATransient>();
                  IServiceProvider provider =  collection.BuildServiceProvider();
                  provider.GetRequiredService<ITestTransient>().Write();
              }
              public static void InitB()
              {
                  IServiceCollection collection = new ServiceCollection();
                  collection.AddTransient<ITestTransient, TestBTransient>();
                  IServiceProvider provider = collection.BuildServiceProvider();
                  provider.GetRequiredService<ITestTransient>().Write();
              }
          }

       

      測試OK,只要在后面的代碼中使用同一個provider,那么從IOC容器中獲取的實例都是相同,改一處便全部都能修改

      6.延伸,現在通過構造器注入其他代碼,比如 

      class A{}
      class B
      {
         public B(A a) { }
      }

      猜想下,遇到這種構造器注入時候,怎么去處理,其實和創建Type對象一直,通過CreateInstance(Type, Object[] param);去創建,param是每個需要注入的類型對象

      OK,那我們來改下代碼,將獲取Object對象的方法添加參數,因為構造器里面注入的參數都是從IOC里面獲取

          public interface IServiceCache
          {
              Object GetCache(IDictionary<Type, IServiceCache> typePairs);
          }

      獲取當前Type類型的構造器,默認獲取參數最多的,參數一樣多的,獲取最后一個,注:這里可以添加一個特性,標明優先構造這個構造器,自己添加就好,寫法盡量簡單

              private List<Type> GetConstructor()
              {
                  ConstructorInfo[] a = _type.GetConstructors();
                  ConstructorInfo b = null;
                  Int32 length = 0;
                  foreach (ConstructorInfo info in a)
                  {
                      if (info.GetParameters().Length >= length)
                      {
                          b = info;
                      }
                  }
                  ParameterInfo[] pa = b.GetParameters();
                  List<Type> list = new List<Type>();
                  foreach (var p in pa)
                  {
                      list.Add(p.ParameterType);
                  }
                  return list;
              }

      構造器參數,就需要從typePairs里面獲取,注意,這里的所有參數都必須從IOC容器中獲取,當然這里會有一個問題就是相互引用,這時候就需要注意下

              public Object GetCache(IDictionary<Type, IServiceCache> typePairs)
              {
                  if (_obj == null)
                  {
                //這里實際是構建一個表達式樹,這樣就不需要每次去通過反射創建對象了 List
      <Type> types = GetConstructor(); Object[] paramters = types.ConvertAll(item => typePairs[item].GetCache(typePairs)).ToArray(); _obj = Activator.CreateInstance(_type, paramters); } switch (_typeEnum){...} }

      7.測試

          public class ConstructorIOCTest
          {
              private readonly ITestTransient m_test;
              public ConstructorIOCTest(ITestTransient test)
              {
                  m_test = test;
              }
              public void WriteTestTransient()
              {
                  m_test.Write();
                  Console.WriteLine("--------------ConstructorIOCTest-----------");
              }
          }
          class Program
          {
              static void Main(string[] args)
              {
                  InitA();
                  InitB();
                  Console.Read();
              }
              public static void InitA()
              {
                  IServiceCollection collection = new ServiceCollection();
                  collection.AddTransient<ITestTransient, TestATransient>();
                  collection.AddTransient<ConstructorIOCTest, ConstructorIOCTest>();
                  IServiceProvider provider =  collection.BuildServiceProvider();
                  provider.GetRequiredService<ConstructorIOCTest>().WriteTestTransient();
              }
              public static void InitB()
              {
                  IServiceCollection collection = new ServiceCollection();
                  collection.AddTransient<ITestTransient, TestBTransient>();
                  collection.AddTransient<ConstructorIOCTest, ConstructorIOCTest>();
                  IServiceProvider provider = collection.BuildServiceProvider();
                  provider.GetRequiredService<ConstructorIOCTest>().WriteTestTransient();
              }
          }

       

       可以看出來,所有的IOC都是從構造器出發,這樣就避免到處修改的尷尬了

      總結:

      1.這是一個簡單的IOC代碼,里面我盡量采用最簡單的小白的方式去實現,沒有使用設計模式(本身最多有個工廠模式),沒有表達式樹,沒有鎖(鎖是非常重要的,后期我會花幾個章節去介紹各種鎖)

      2.IOC其實就是一個概念,理解之后,在構造的時候添加幾個特性,比如屬性注入,方法注入,其實無非就是在ServiceTypeCache類中添加構造器,方法,屬性篩選之類的語法糖而已

      3.這里沒有時間Scopd的生命周期,因為我并不是很確定.net core中這個的寫法,對我來說有2種,一種是在GetService時候,HttpContext注入,一種是將ServiceProvider里面進行包裝一層Guid,相同的Guid的Scopd相同

      4.希望大家可以去看看源碼,尤其是推薦微軟開源的幾個框架,代碼之精華,越看越覺得代碼之美,雖然里面很多代碼就是在打補丁,坑死人

      5.https://github.com/BestHYC/IOCSolution.git,源碼,代碼的話我就不加工了,因為沒什么好加工的,畢竟IOC實在太成熟了

       

      posted @ 2019-09-20 18:19  Best_Hong  閱讀(902)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 玩弄丰满少妇人妻视频| 精品国产中文字幕在线| 亚洲中文久久久精品无码| 久久精品国产亚洲不AV麻豆| 国产成人综合久久亚洲精品| 亚洲日韩一区二区| 亚洲区一区二区激情文学| 国产日韩av一区二区在线| 国产360激情盗摄全集| 秋霞人妻无码中文字幕| 疯狂做受XXXX高潮国产| 日本熟妇浓毛| 蜜桃在线一区二区三区| 国产一区二区日韩在线| 国产精品美女一区二区三| 国产美女被遭强高潮免费一视频| 久久亚洲精品中文字幕波多野结衣| 国产一区二区不卡精品视频| 玩弄放荡人妻少妇系列| 人妻系列中文字幕精品| 习水县| 午夜福利国产区在线观看| 高清自拍亚洲精品二区| 一本色道久久88精品综合| 熟女亚洲综合精品伊人久久| 99久久99久久精品国产片| 风韵丰满妇啪啪区老老熟女杏吧| 国产最大的福利精品自拍| av无码av无码专区| 国产亚洲精品综合一区二区| 91福利一区二区三区| 亚洲欧美综合中文| 国产激情一区二区三区午夜 | 亚洲国产精品日韩在线| 性高湖久久久久久久久| 天堂在线最新版在线天堂| 精品人妻日韩中文字幕| 欧美丰满熟妇xxxx性| 乱人伦中文字幕成人网站在线| 日韩亚洲国产综合高清| 国产一区国产精品自拍|