一、Ioc
IoC全稱Inverse of Control,控制反轉。
類庫和框架的不同之處在於,類庫是實現某種單一功能的API,框架是針對一個任務把這些單一功能串聯起來形成一個完整的流程,這個流程在一個引擎驅動下被執行。
IoC的總體設計是要把在應用程序的流程控制轉移到框架中,實現對流程的復用,這 符合軟件設計的基本原則-重用性。
IoC不是一種設計模式,它是一種設計原則。並且很多設計模式都遵循了這種原則。比如:模板模式、工廠模式、抽象工廠模式。
二、DI
DI全稱Dependency Indection,依賴注入。它是IoC模式的一種。
我們寫的對象要完成某個功能可能要依賴於另外一個對象,比如我們要添加一個人員,往往會在邏輯層調用數據操作層來實現添加到數據庫的操作。DI會在程序初始化的時候,把數據操作層的接口和實現接口的類關聯起來,那么在邏輯層我們只要聲明要調用的具體數據操作層的接口,調用接口的方法,這樣就實現了邏輯層和數據操作層的解耦。
所謂依賴注入可以理解為一種針對依賴的字段或者屬性的一種自動初始化方式。
舉例說明,當我們通過VS2015創建了一個.Net Core項目,並且帶有個人身份驗證Identity,具體如何創建在此不再細說。
我們看到在Startup中,有個方法

// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddMvc(); // Add application services. services.AddTransient<IEmailSender, AuthMessageSender>(); services.AddTransient<ISmsSender, AuthMessageSender>(); }
Controller中:

[Authorize] public class AccountController : Controller { private readonly UserManager<ApplicationUser> _userManager; private readonly SignInManager<ApplicationUser> _signInManager; private readonly IEmailSender _emailSender; private readonly ISmsSender _smsSender; private readonly ILogger _logger; public AccountController( UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IEmailSender emailSender, ISmsSender smsSender, ILoggerFactory loggerFactory) { _userManager = userManager; _signInManager = signInManager; _emailSender = emailSender; _smsSender = smsSender; _logger = loggerFactory.CreateLogger<AccountController>(); } }
我們看到,我們並沒有實例化AccountController中的字段,只是在構造函數把相關聯的字段當做參數傳進來,系統自動就會實例化。這個實例化的過程就是DI幫助我們完成的。
DI注入方式有3種:構造器注入、屬性注入、方法注入。
DI容器就是一個服務的提供者。當需要某個服務的時候,只要從DI容器中獲取就可以。
三、.NET 中的DI
ServiceProvider對象是DI容器的核心對象,他在Microsoft.Extensions.DependencyInjection.dll程序集的同名命名空間下。是一個程序集內部類。這個類的主要任務就是根據服務類型提供服務對象。
與這個類相關聯的類有:ServiceCallSite、Service、ServiceEntry和ServiceTable。他們都有相應的接口。
1.ServiceCallSite
服務的最終提供者就是這個對象,這個對象繼承自接口IServiceCallSite。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { using Microsoft.Extensions.DependencyInjection; using System; using System.Linq.Expressions; internal interface IServiceCallSite { Expression Build(Expression provider); object Invoke(ServiceProvider provider); } }
當需要一個服務實例的時候,會去對應的ServiceCallSite中調用Invoke方法,返回需要的實例。同時,還會調用Invoke方法返回表達式,並會緩存起來,等到下次獲取相同實例的時候直接獲取。
2.Service
當我們獲取服務對象實例的時候是根據ServiceCollection提供的。ServiceCollection和我們連接非常緊密,就是我們在Startup中添加的服務於實現的關聯。
ServiceCollection中保存的就是ServiceDescriptor,每個ServiceDescriptor都會被轉化成Service,繼承自接口IService。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; internal interface IService { IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain); ServiceLifetime Lifetime { get; } IService Next { get; set; } } }
我們看到,這個接口中有CreateCallSite得到一個ServiceCallSite實例。每個Service都是以鏈表的形式存在,Next表示鏈表的下一個節點,這個鏈表就是具有相同的服務類型組成。
3.ServiceEntry
表示上面說的鏈表。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { using System; using System.Runtime.CompilerServices; internal class ServiceEntry { private object _sync = new object(); public ServiceEntry(IService service) { this.First = service; this.Last = service; } public void Add(IService service) { object obj2 = this._sync; lock (obj2) { this.Last.Next = service; this.Last = service; } } public IService First { get; private set; } public IService Last { get; private set; } } }
4.ServiceTable
多個ServiceEntry組成一個ServiceTable。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; internal class ServiceTable { private readonly Dictionary<Type, List<IGenericService>> _genericServices = new Dictionary<Type, List<IGenericService>>(); private readonly ConcurrentDictionary<Type, Func<ServiceProvider, object>> _realizedServices = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>(); private readonly Dictionary<Type, ServiceEntry> _services = new Dictionary<Type, ServiceEntry>(); private readonly object _sync = new object(); public ServiceTable(IEnumerable<ServiceDescriptor> descriptors) { foreach (ServiceDescriptor descriptor in descriptors) { if (IntrospectionExtensions.GetTypeInfo(descriptor.ServiceType).IsGenericTypeDefinition) { TypeInfo info = (descriptor.ImplementationType == null) ? null : IntrospectionExtensions.GetTypeInfo(descriptor.ImplementationType); if ((info == null) || !info.IsGenericTypeDefinition) { throw new ArgumentException(Resources.FormatOpenGenericServiceRequiresOpenGenericImplementation(descriptor.ServiceType), "descriptors"); } if (info.IsAbstract || info.IsInterface) { throw new ArgumentException(Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType)); } this.Add(descriptor.ServiceType, new GenericService(descriptor)); } else if (descriptor.ImplementationInstance != null) { this.Add(descriptor.ServiceType, new InstanceService(descriptor)); } else if (descriptor.ImplementationFactory != null) { this.Add(descriptor.ServiceType, new FactoryService(descriptor)); } else { TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(descriptor.ImplementationType); if ((typeInfo.IsGenericTypeDefinition || typeInfo.IsAbstract) || typeInfo.IsInterface) { throw new ArgumentException(Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType)); } this.Add(descriptor.ServiceType, new Service(descriptor)); } } } public void Add(Type serviceType, IGenericService genericService) { object obj2 = this._sync; lock (obj2) { List<IGenericService> list; if (!this._genericServices.TryGetValue(serviceType, ref list)) { list = new List<IGenericService>(); this._genericServices.set_Item(serviceType, list); } list.Add(genericService); } } public void Add(Type serviceType, IService service) { object obj2 = this._sync; lock (obj2) { ServiceEntry entry; if (this._services.TryGetValue(serviceType, ref entry)) { entry.Add(service); } else { this._services.set_Item(serviceType, new ServiceEntry(service)); } } } public bool TryGetEntry(Type serviceType, out ServiceEntry entry) { object obj2 = this._sync; lock (obj2) { if (this._services.TryGetValue(serviceType, ref entry)) { return true; } if (IntrospectionExtensions.GetTypeInfo(serviceType).IsGenericType) { List<IGenericService> list; Type genericTypeDefinition = serviceType.GetGenericTypeDefinition(); if (this._genericServices.TryGetValue(genericTypeDefinition, ref list)) { using (List<IGenericService>.Enumerator enumerator = list.GetEnumerator()) { while (enumerator.MoveNext()) { IService service = enumerator.get_Current().GetService(serviceType); if (service != null) { this.Add(serviceType, service); } } } return this._services.TryGetValue(serviceType, ref entry); } } } return false; } public ConcurrentDictionary<Type, Func<ServiceProvider, object>> RealizedServices { get { return this._realizedServices; } } } }
主要的方法就是在ServiceTable構造函數中,根據傳過來的ServiceDescriptor列表,其實就是我們在Startup中注冊的服務與具體實現轉換過來的。
在這個構造函數中會先根據ServiceType轉換成ServiceEntry列表,再添加到Dictionary<Type, ServiceEntry> _services 中,也就是最終得到的是_services類型。
5.ServiceProvider

1: internal class ServiceProvider : IServiceProvider, IDisposable 2: { 3: public ServiceProvider Root { get; private set; } 4: public ServiceTable ServiceTable { get; private set; } 5: public ConcurrentDictionary<Type, Func<ServiceProvider, object>> RealizedServices { get; private set; } = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>(); 6: public IList<IDisposable> TransientDisposableServices { get; private set; } = new List<IDisposable>(); 7: public ConcurrentDictionary<IService, object> ResolvedServices { get; private set; } = new ConcurrentDictionary<IService, object>(); 8: 9: public ServiceProvider(IServiceCollection services) 10: { 11: this.Root = this; 12: this.ServiceTable = new ServiceTable(services); 13: } 14: 15: public object GetService(Type serviceType) 16: { 17: Func<ServiceProvider, object> serviceAccessor; 18: if (this.RealizedServices.TryGetValue(serviceType, out serviceAccessor)) 19: { 20: return serviceAccessor(this); 21: } 22: 23: IServiceCallSite serviceCallSite = this.GetServiceCallSite(serviceType, new HashSet<Type>()); 24: if (null != serviceCallSite) 25: { 26: var providerExpression = Expression.Parameter(typeof(ServiceProvider), "provider"); 27: this.RealizedServices[serviceType] = Expression.Lambda<Func<ServiceProvider, object>>(serviceCallSite.Build(providerExpression), providerExpression).Compile(); 28: return serviceCallSite.Invoke(this); 29: } 30: 31: this.RealizedServices[serviceType] = _ => null; 32: return null; 33: } 34: 35: public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain) 36: { 37: try 38: { 39: if (callSiteChain.Contains(serviceType)) 40: { 41: throw new InvalidOperationException(string.Format("A circular dependency was detected for the service of type '{0}'", serviceType.FullName); 42: } 43: callSiteChain.Add(serviceType); 44: 45: ServiceEntry serviceEntry; 46: if (this.ServiceTable.ServieEntries.TryGetValue(serviceType, 47: out serviceEntry)) 48: { 49: return serviceEntry.Last.CreateCallSite(this, callSiteChain); 50: } 51: 52: //省略其他代碼 53: 54: return null; 55: } 56: finally 57: { 58: callSiteChain.Remove(serviceType); 59: } 60: } 61: 62: public void Dispose() 63: { 64: Array.ForEach(this.TransientDisposableServices.ToArray(), _ => _.Dispose()); 65: Array.ForEach(this.ResolvedServices.Values.ToArray(), _ => (_ as IDisposable)?.Dispose()); 66: this.TransientDisposableServices.Clear(); 67: this.ResolvedServices.Clear(); 68: } 69: //其他成員 70: }
以上借助他人的代碼片段,ServiceProvider中主要有幾個屬性,root指向自己;RealizedServices 就是在我們講解ServiceCallSite時說道,最后得到的Service會被生成委托以便下次調用,這個委托就存在這個屬性中。
這個類最主要的方法就是GetService,主要邏輯就是從RealizedServices 獲取當前服務的實例,如果有,直接返回,如果沒有,會從ServiceTable中找到對應的ServiceEntry,如果沒有返回null,如果有,調用ServiceEntry所在列表最后一個Service的CreateServiceCallSite方法創建一個ServiceCallSite對象(這一點說明了如果針對同一個服務類型注冊了多個ServiceDescriptor,在提供單個服務的時候總是使用最后一個 ServiceDescriptor)。
綜上,.net core中的DI容器的主要對象就是ServiceProvider、ServiceCallSite、Service、ServiceEntry和ServiceTable。主要的流程控制都放在ServiceProvider類中,這個類有一個ServiceTable(就是ServiceType和ServiceEntry的對應列表)。ServiceEntry就是一個鏈表,鏈接了當前ServiceType的所有的實例(不過得到的實例總是以最后一個為准),實例的類型都是Service類型。Service主要就是獲取ServiceCallSite對象,這個對象就是封裝了所有的獲取具體服務實例的邏輯,主要通過Invoke得到實例,再調用Build生成表達式委托,存在ServiceProvider中。
ServiceProvider主要有一個方法GetService獲取服務實例。主要邏輯就是從RealizedServices 獲取當前服務的實例,如果有,直接返回,如果沒有,會從ServiceTable中找到對應的ServiceEntry,如果沒有返回null,如果有,調用ServiceEntry所在列表最后一個Service的CreateServiceCallSite方法創建一個ServiceCallSite對象(這一點說明了如果針對同一個服務類型注冊了多個ServiceDescriptor,在提供單個服務的時候總是使用最后一個 ServiceDescriptor)。
過后思考:
1. ServiceCallSite:獲取我們要的最終的服務實例並緩存起來以備下次調用。
2.Service:獲取ServiceCallSite,由我們注冊的服務轉換而來,鏈表形式存在,整個鏈表表示相同實例類型的實例。
3.ServiceEntry:對鏈表Service的封裝,有First、Last表示鏈表的第一個和最后一個,還有個Add方法。
4.ServiceTable:主要對象就是Dictionary<Type,ServiceEntry> _service,表示服務類型和服務實例鏈表的對應關系。
5.ServiceProvider:整個DI功能的控制者,主要方法就是GetService,根據類型獲取實例。