手把手教你寫DI_2_小白徒手擼建構函式注入
小白徒手擼建構函式注入
在上一節:
我們已經知道我們要擼哪些東西了
那麼我們開始動工吧,這裡呢,我們找小白同學來表演下
小白同學 :我們先定義一下我們的廣告招聘紙有什麼:
public abstract class ServiceDefintion // 小白同學 :我們換個名字,不叫 ServiceDescriptor ,擼也要擼出自己的標誌嘛{ public abstract Type ServiceType { get; } public abstract Type ImplementationType { get; } public abstract Lifetime Lifetime { get; } }public enum Lifetime // 小白同學 :定義一下要支援的三種生命週期{ Singleton, Scoped, Transient }// 小白同學 :搞個集合存放他們public interface IServiceDefintions : IEnumerable<ServiceDefintion> { void Add(ServiceDefintion serviceDefintion); }public class ServiceDefintions : IServiceDefintions{ private readonly List<ServiceDefintion> services = new List<ServiceDefintion>(); public void Add(ServiceDefintion serviceDefintion) { if (serviceDefintion == null) { throw new ArgumentNullException(nameof(serviceDefintion)); } services.Add(serviceDefintion); } }
好,我們實現兩種不同的廣告型別
public class TypeServiceDefintion : ServiceDefintion // 小白同學 :這種是隻提供型別的,怎麼建立例項需要我們解析生成,但是對使用DI的人來說,很方便,不用管怎麼去new{ public override Type ServiceType { get; } public override Type ImplementationType { get; } public override Lifetime Lifetime { get; } public TypeServiceDefintion(Type serviceType, Type implementationType, Lifetime lifetime) { ServiceType = serviceType; ImplementationType = implementationType; Lifetime = lifetime; } }public interface IImplementationFactory{ Func<INamedServiceProvider, object> ImplementationFactory { get; } }public class DelegateServiceDefintion : ServiceDefintion, IImplementationFactory // 小白同學 :這種是使用者自己new物件,少數特殊情況,使用者會自己寫特殊邏輯,所以我們需要提供支援{ public DelegateServiceDefintion(Type serviceType, Type implementationType, Lifetime lifetime, Func<IServiceProvider, object> implementationFactory) { ServiceType = serviceType; ImplementationType = implementationType; Lifetime = lifetime; ImplementationFactory = implementationFactory; } public override Type ServiceType { get; } public override Type ImplementationType { get; } public override Lifetime Lifetime { get; } public Func<IServiceProvider, object> ImplementationFactory { get; } }
小白同學 :好了,我們有服務定義描述了,來建立IServiceProvider
吧
public class ServiceProvider : IServiceProvider{ private readonly IServiceDefintions services; public ServiceProvider(IServiceDefintions services) { this.services = services; } public object GetService(Type serviceType) { var defintion = TryGetDefintion(serviceType); // 小白同學 :查詢一下服務定義 if (defintion != null) { switch (defintion.Lifetime) { case Lifetime.Singleton: return null; // 小白同學 :啥?怎麼處理?emm 後面說吧,腦容量不夠啦 case Lifetime.Scoped: return null; // 小白同學 :啥?怎麼處理?emm 後面說吧,腦容量不夠啦 case Lifetime.Transient: if(defintion is DelegateServiceDefintion defi) { return defi.ImplementationFactory(this); // 小白同學 :haha, 不用我們做,真簡單 } else // 小白同學 :TypeServiceDefintion { // 小白同學 :啥?怎麼處理?emm 後面說吧,腦容量不夠啦 } default: return null; } } else { return null; } } private ServiceDefintion TryGetDefintion(Type serviceType) { return services.FirstOrDefault(i => i.ServiceType == serviceType); //大神: what ? 每次都遍歷一下?太low了吧? } }
小白同學 :捂臉.gif 我們居然每次都遍歷,簡直太笨了,趕緊改下,免得大神吐槽
public class ServiceProvider : IServiceProvider{ private readonly Dictionary<Type, ServiceDefintion> services; public ServiceProvider(IServiceDefintions services) { this.services = services.ToDictionary(i => i.ServiceType); //大神: what 1 ? 有相同的 ServiceType 怎麼辦? } private ServiceDefintion TryGetDefintion(Type serviceType) //大神: what 2 ? 這個方法怎麼這麼怪 { services.TryGetValue(serviceType, out var defintion); return defintion; } ... }
小白同學 :又被吐槽了,再改下
public class ServiceProvider : IServiceProvider{ private readonly Dictionary<Type, ServiceDefintion[]> services; //大神: 呵呵,你就這樣寫吧,我打賭100塊你後面肯定要改 //小白同學: ...... public ServiceProvider(IServiceDefintions services) { this.services = services.GroupBy(i => i.ServiceType).ToDictionary(i => i.Key, i => i.ToArray()); } private ServiceDefintion TryGetDefintion(Type serviceType) { return services.TryGetValue(serviceType, out var defintion) ? defintion.LastOrDefault() : null; } ... }
小白同學: 好了,我們簡單測試一下
[Fact]public void Test(){ var a = new ServiceDefintions(); a.Add(new DelegateServiceDefintion(typeof(TransientTest),typeof(TransientTest),Lifetime.Transient,i => this)); var service = new ServiceProvider(a); var result0 = service.GetService(typeof(TransientTest)); Assert.Same(this, result0); }// 大神: 你用this 去測瞬態?你確定this是瞬態的func 每次都會呼叫?// 小白同學: 我。。。。。。我改
[Fact]public void Test(){ var a = new ServiceDefintions(); a.Add(new DelegateServiceDefintion(typeof(TransientTest),typeof(TransientTest),Lifetime.Transient,i => new TransientTest())); var service = new ServiceProvider(a); var result0 = service.GetService(typeof(TransientTest)); var result1 = service.GetService(typeof(TransientTest)); Assert.NotNull(result0); Assert.NotNull(result1); Assert.NotSame(result0, result1); }
小白同學: 我們來做TypeServiceDefintion 解析支援
public class ServiceProvider : IServiceProvider{ public object GetService(Type serviceType) { ... case Lifetime.Transient: if(defintion is DelegateServiceDefintion defi) { return defi.ImplementationFactory(this); } else { var d = defintion as TypeServiceDefintion; var constructor = d.ImplementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); // 小白同學: 反射獲取建構函式 var ps = constructor.GetParameters(); var args = new object[ps.Length]; for (int j = 0; j < ps.Length; j++) { var p = ps[j]; args[j] = i.GetService(p.ParameterType); // 小白同學: 獲取引數值 } return constructor.Invoke(args); // 小白同學: 建立; } .... } }
小白同學: 你看我寫的不錯吧
大神:呵呵,這樣反射效能你考慮了嗎? 泛型你考慮了嗎? 還有你每次都重新生成DelegateServiceDefintion?
小白同學: 我知道反射該用IL或者表示式樹處理,但觀眾不好看嘛
大神:呵呵,你不會寫吧,你看看人家lemon大神怎麼寫的 -
小白同學: 好,我下來學習。 泛型不過是再動態生成一下型別嘛,這樣就行啦
public class ServiceProvider : IServiceProvider{ public object GetService(Type serviceType) { ... case Lifetime.Transient: if(defintion is DelegateServiceDefintion defi) { return defi.ImplementationFactory(this); } else { var d = defintion as TypeServiceDefintion; var implementationType = serviceType.IsConstructedGenericType ? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments) : d.ImplementationType; var constructor = implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); // 小白同學: 反射獲取建構函式 ..... } .... } }
小白同學: 哦,還有快取:
public class ServiceProvider : IServiceProvider{ private readonly Dictionary<Type, ConstructorInfo> cache = new Dictionary<Type, ConstructorInfo>(); public object GetService(Type serviceType) { ... case Lifetime.Transient: if(defintion is DelegateServiceDefintion defi) { return defi.ImplementationFactory(this); } else { ConstructorInfo constructor = null; if(cache.ContainsKey(serviceType)) { constructor = cache[serviceType]; } else { var d = defintion as TypeServiceDefintion; var implementationType = serviceType.IsConstructedGenericType ? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments) : d.ImplementationType; constructor = cache[serviceType] = implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); // 小白同學: 反射獲取建構函式 } .... } .... } }
大神: .......我想自閉..... 你都不考慮多執行緒嗎?
小白同學: !!! 我,我,我,我換成它 ConcurrentDictionary<Type, ConstructorInfo> cache
大神:算你NB,Singleton
和 Scoped
你打算怎麼做?
小白同學: 簡單, copy 一下
public class ServiceProvider : IServiceProvider{ private readonly ConcurrentDictionary<Type, ConstructorInfo> cache = new ConcurrentDictionary<Type, ConstructorInfo>(); public object GetService(Type serviceType) { case Lifetime.Singleton: if(defintion is DelegateServiceDefintion defi) { return defi.ImplementationFactory(this); } else { ConstructorInfo constructor = cache.GetOrAdd(serviceType, i => { var d = defintion as TypeServiceDefintion; var implementationType = serviceType.IsConstructedGenericType ? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments) : d.ImplementationType; return implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); }); ar ps = constructor.GetParameters(); var args = new object[ps.Length]; for (int j = 0; j < ps.Length; j++) { var p = ps[j]; args[j] = i.GetService(p.ParameterType); // 小白同學: 獲取引數值 } return constructor.Invoke(args); // 小白同學: 建立; } case Lifetime.Scoped: if(defintion is DelegateServiceDefintion defi) { return defi.ImplementationFactory(this); } else { ConstructorInfo constructor = cache.GetOrAdd(serviceType, i => { var d = defintion as TypeServiceDefintion; var implementationType = serviceType.IsConstructedGenericType ? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments) : d.ImplementationType; return implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); }); ar ps = constructor.GetParameters(); var args = new object[ps.Length]; for (int j = 0; j < ps.Length; j++) { var p = ps[j]; args[j] = i.GetService(p.ParameterType); // 小白同學: 獲取引數值 } return constructor.Invoke(args); // 小白同學: 建立; } case Lifetime.Transient: if(defintion is DelegateServiceDefintion defi) { return defi.ImplementationFactory(this); } else { ConstructorInfo constructor = cache.GetOrAdd(serviceType, i => { var d = defintion as TypeServiceDefintion; var implementationType = serviceType.IsConstructedGenericType ? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments) : d.ImplementationType; return implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); }); ar ps = constructor.GetParameters(); var args = new object[ps.Length]; for (int j = 0; j < ps.Length; j++) { var p = ps[j]; args[j] = i.GetService(p.ParameterType); // 小白同學: 獲取引數值 } return constructor.Invoke(args); // 小白同學: 建立; } .... } }
大神:我!!!!!!!!!! 我給你一刀!!!!!!!
小白同學: 啊!!!!!!!!!
由於小白同學受傷,本次節目中斷,等小白同學養好傷,我們再繼續
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/818/viewspace-2816770/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 手把手教你寫DI_3_小白徒手支援 `Singleton` 和 `Sc
- 教你如何使用Springboot注入帶引數的建構函式Spring Boot函式
- 手把手教你構建開放式文化
- 預設建構函式、引數化建構函式、複製建構函式、解構函式函式
- Spring基於建構函式和設值函式的依賴注入Spring函式依賴注入
- 徒手擼框架--實現Aop框架
- 徒手擼UI之DatePickerUI
- 徒手擼框架--實現IoC框架
- 手把手教你擼vue全域性元件Vue元件
- 建構函式與解構函式函式
- ## 建構函式函式
- 建構函式函式
- [譯] 建構函式已死,建構函式萬歲!函式
- 請Spring如何注入帶有建構函式的物件呢?Spring函式物件
- C++ 建構函式和解構函式C++函式
- 類的建構函式和解構函式函式
- 手把手教你擼一個 Webpack LoaderWeb
- Swift4.0 便利建構函式的寫法Swift函式
- c# tcbs之建構函式呼叫建構函式示例C#函式
- C++ 類建構函式和解構函式C++函式
- JavaScript 建構函式JavaScript函式
- 建構函式、this、static函式
- 手把手教你擼一個簡易的 webpackWeb
- 手把手教你寫VueRouterVue
- 虛解構函式(√)、純虛解構函式(√)、虛建構函式(X)函式
- 徒手擼設計模式-觀察者模式設計模式
- 徒手擼設計模式-組合模式設計模式
- 如何寫一個作用域安全的建構函式函式
- java中寫建構函式的另外一種方式Java函式
- C/C++——建構函式、複製建構函式和解構函式的執行時刻C++函式
- 手把手教你快速構建自定義分類器
- PHP筆記:建構函式與解構函式PHP筆記函式
- 手把手教你Node使用Promise替代回撥函式Promise函式
- 【C++】初始化列表建構函式VS普通建構函式C++函式
- C++語言之結構體、類、建構函式、拷貝建構函式C++結構體函式
- C++中建構函式,拷貝建構函式和賦值函式的詳解C++函式賦值
- 建構函式建立物件函式物件
- JavaScript Date()建構函式JavaScript函式