天天看點

IoC之AutoFac(二)——解析服務

閱讀目錄

  • ​​一 Resolve方法​​
  • ​​二 TryResolve和ResolveOptional方法​​
  • ​​三 解析服務時傳參​​
  • 3.1 可用參數類型
  • 3.2 帶反射元件的參數
  • 3.3 具有Lambda表達式元件的參數

一 Resolve方法

在您的元件注冊了适當的服務後,您可以從内置的容器和子生命周期範圍中解析服務。 您可以使用Resolve()方法,還是使用上篇的例子:

1     private static IContainer Container { get; set; }
 2         static void Main(string[] args)
 3         {
 4             var builder = new ContainerBuilder();
 5             //注冊服務
 6             builder.RegisterType<ConsoleOutput>().As<IOutput>();
 7             Container = builder.Build();
 8             //解析服務
 9             using (var scope=Container.BeginLifetimeScope())
10             {
11                var output= scope.Resolve<IOutput>();
12                output.Write("outputsomething");
13                Console.ReadKey();
14             }  
15         }      

  解析服務時,Autofac将自動連結服務的整個依賴關系層次,并解析完全建構服務所需的任何依賴關系。 如果您的循環依賴關系被錯誤地處理,或者缺少必需的依賴關系,那麼您将得到一個DependencyResolutionException。

二 TryResolve和ResolveOptional方法

如果您有可能注冊或可能不被注冊的服務,您可以使用ResolveOptional()或TryResolve()來嘗試對服務進行有條件解決:

1                 //解析服務
 2                 using (var scope = Container.BeginLifetimeScope())
 3                 {
 4                     //1.ResolveOptional:IOutput注冊的話解析,未被注冊傳回null
 5                     var service = scope.ResolveOptional<IOutput>();
 6 
 7                     //2.TryResolve:IOutput注冊的話解析擷取一個類型執行個體,未注冊傳回null
 8                     IOutput output = null;
 9                     //如果有IOutPut服務,執行輸出
10                     if (scope.TryResolve<IOutput>(out output))
11                     {
12                         output.Write("outputsomething");
13                     }
14                     Console.ReadKey();
15                 }      

三 解析服務時傳參

  解析服務的時候,您可能會發現需要将參數傳遞給Autofac。 (如果您在注冊時知道值,則可以在注冊中提供它們,詳細見上篇。)Resolve()方法使用可變長度的參數清單在注冊時接受相同的參數類型。

Autofac提供了幾種不同的參數比對政策:

  • NamedParameter - 按名稱比對目标參數
  • TypedParameter - 按類型比對目标參數(需要精确類型比對)
  • ResolvedParameter - 靈活的參數比對

NamedParameter和TypedParameter隻能提供常量值。

ResolvedParameter可以用作提供從容器動态檢索的值的方法,例如。 通過名稱解析服務。

      當您解析基于反射的元件時,類型的構造函數可能需要您需要根據運作時值指定的參數,這在注冊時不可用。 您可以在Resolve()方法調用中使用一個參數來提供該值。

  假設您有一個配置讀取器,需要傳遞一個配置部分名稱:

1  public class ConfigReader : IConfigReader
2     {
3         public ConfigReader(string configSectionName)
4         {
5             // 存儲配置的節點名稱
6         }
7 
8         // 讀取基于節點名稱的配置
9     }      

  您可以将參數傳遞給Resolve()調用,如下所示:

//注冊
 builder.RegisterType<ConfigReader>().As<IConfigReader>();
//解析
 var reader = scope.Resolve<IConfigReader>(new NamedParameter("configSectionName", "mySectionName"));      

  如果您有多個參數,隻需通過Resolve()方法将它們全部傳遞:

var service = scope.Resolve<AnotherService>(
                new NamedParameter("id", "service-identifier"),
                new TypedParameter(typeof(Guid), Guid.NewGuid()),
                new ResolvedParameter(
                  (pi, ctx) => pi.ParameterType == typeof(ILog) && pi.Name == "logger",
                  (pi, ctx) => LogManager.GetLogger("service")));      

  使用lambda表達式元件注冊,您需要在lambda表達式中添加參數處理,是以當Resolve()調用傳入時,可以利用它們。

在元件系統資料庫達式中,您可以通過更改用于注冊的代理簽名來使用傳入參數。 而不是僅僅使用IComponentContext參數,而是接收一個IComponentContext和一個IEnumerable <Parameter>:

相關執行個體:

// c 是目前元件上下文
   // p 是IEnumerable<Parameter>參數集合
   builder.Register((c, p) =>new ConfigReader(p.Named<string>("configSectionName")))
          .As<IConfigReader>();      

現在,當您解析IConfigReader時,您的lambda将使用傳遞的參數:

//解析時傳參
var reader = scope.Resolve<IConfigReader>(new NamedParameter("configSectionName", "sectionName"));