ASP.NET Core依賴注入系統學習教程:ServiceDescriptor(服務註冊描述類型)

依賴注入容器之所以能夠提供應用程序所需的服務對象,是因爲服務註冊爲容器提供了創建服務對象的描述信息,而這個服務註冊的描述信息是被封裝在一個由ServiceDescriptor類型表示的對象中,該對象主要存儲在IServiceCollection類型的集合中,其中每個ServiceDescriptor對象主要描述了:服務的類型、提供服務對象的方式以及服務對象的生命週期模式。

所以可以換句話說,我們進行服務註冊實際上就是創建一個ServiceDescriptor類型的對象,並添加到IServiceCollection類型的集合中。基於這種本質也代表了,實際上我們進行服務註冊並非要調用註冊方法來完成,我們還可以直接創建一個ServiceDescriptor的對象,將其添加到IServiceCollection集合中,用這樣的方式同樣可以實現服務註冊。通過運行下面的代碼示例就可以證明這一點。

 1 using Microsoft.Extensions.DependencyInjection;
 2 using System;
 3 using System.Diagnostics;
 4 
 5 namespace ConsoleApp1
 6 { 
 7     public interface IFooBar { void SayHi(); }
 8     public class FooBar : IFooBar
 9     {
10         public void SayHi() { Console.WriteLine("你好"); }
11     }
12 
13     internal class Program
14     {
15         static void Main(string[] args)
16         {
17             //創建服務註冊信息集合
18             var collection = new ServiceCollection();
19 
20             //創建服務註冊信息對象,並添加到集合
21             ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IFooBar), typeof(FooBar), ServiceLifetime.Singleton);
22             collection.Insert(collection.Count, descriptor);
23 
24             //構建容器對象
25             var  provider= collection.BuildServiceProvider();
26 
27             //獲取對象並調用方法
28             var fooBar =provider.GetService<IFooBar>();
29             fooBar.SayHi();
30         } // END Main()
31 
32     }
33 }

上面的示例中創建ServiceDescriptor對象其實就是通過構造函數傳入了幾個關鍵的屬性,下面通過代碼的形式羅列出ServiceDescriptor類型中的幾個關鍵屬性,其中對屬性的描述體現在註釋上:

 1  public class ServiceDescriptor
 2     {
 3         /// <summary>
 4         /// 服務的生命週期模式
 5         /// </summary>
 6         public ServiceLifetime Lifetime { get; }
 7 
 8         /// <summary>
 9         /// 服務的類型,通常會指定一個接口或者基類
10         /// </summary>
11         public Type ServiceType { get; }
12 
13         /// <summary>
14         /// 服務的實現
15         /// </summary>
16         public Type ImplementationType { get; }
17 
18         /// <summary>
19         /// 服務實例,直接提供一個實例對象,容器提供時就無需創建
20         /// </summary>
21         public object ImplementationInstance { get; }
22 
23         /// <summary>
24         /// 用於創建服務實例的工廠方法
25         /// </summary>
26         public Func<IServiceProvider, object> ImplementationFactory { get; }
27 
28     }

在以上的關鍵屬性中除了ServiceType(服務類型)是必須的,其他的幾個可以根據不同的創建形式使用的不同構造函數來決定。以下是創建ServiceDescriptor類型對象的3個構造函數:

1 public ServiceDescriptor(Type serviceType, object instance);
2 public ServiceDescriptor(Type serviceType, Type implementationType, ServiceLifetime lifetime);
3 public ServiceDescriptor(Type serviceType, Func<IServiceProvider, object> factory, ServiceLifetime lifetime)

ServiceDescriptor類型中的3個構造函數主要體現出了服務實例的3種提供方式,並且這3種提供方式和我們進行服務註冊時主要使用的幾種形式相得益彰。下面我對這3種服務實例的提供方式進行概況說明:

  1. 根據指定的服務類型,直接使用一個現成的對象進行提供;
  2. 根據指定的服務類型,使用對應的實現類型結合指定的生命週期模式進行提供;
  3. 根據指定的服務類型,使用一個委託對象作爲工廠方法,結合指定的生命週期模式進行提供;

第一種方式而言並沒有指定生命週期模式,是因爲它默認採用了Singleton的模式,所以無需指定生命週期。

除了上面介紹的3個構造函數來創建ServiceDescriptor對象,在ServiceDescriptor類型中還提供了一些列的靜態方法用來創建對象。如果想要更加詳細的瞭解ServiceDescriptor類型其中的每一項,可以訪問官方文檔進行查閱:https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.extensions.dependencyinjection.servicedescriptor?view=dotnet-plat-ext-6.0

總結

服務註冊的本質,實際上就是將創建服務對象所使用到的關鍵信息:服務類型、服務實現類型、提供方式、生命週期,封裝到ServiceDescriptor類型的對象中,並添加到IServiceCollection集合,以便作爲容器爲應用程序提供服務對象的根據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章