[翻譯] Autofac 入門文檔

jopen 8年前發布 | 9K 次閱讀 .NET開發 IoC

原文鏈接: http://docs.autofac.org/en/latest/getting-started/index.html

在程序中使用Autofac的基本模式是:

  • 用控制反轉(IoC)的思想組織程序。
  • 添加對 Autofac 的引用。
  • 程序啟動階段
    • 創建 ContainerBuilder
    • 注冊組件。
    • 生成容器。
  • 程序執行階段
    • 從容器創建生命周期范圍對象( ILifetimeScope 接口)。
    • 使用生命周期范圍對象解析組件實例。

本文通過一個簡單的控制臺程序演示這些步驟。

組織程序

控制反轉的基本思路是,不讓類創建它的依賴項,而是將依賴項通過構造函數傳遞給它。請參閱 Martin Fowler 這篇解釋依賴注入/控制反轉的文章。

在本示例中,我們定義一個輸出“今天”的日期的類。但是,我們不想讓它和 Console 類捆綁在一起。這有兩個原因:1,方便測試,2,在沒有Console的環境中也能使用。

我們還對輸出日期的方式進行抽象,這樣就可以隨時切換到另一個版本,比如輸出“明天”的日期。

代碼:

using System;

namespace DemoApp
{

  // 此接口將“輸出”概念從Console類解耦。
  // 我們只管“輸出”,而不關心操作是怎么進行的。
  public interface IOutput
  {
    void Write(string content);
  }

  // 這里的實現方式是向Console輸出內容。
  // 也可以用其他方式,比如輸出到 Debug 和 Trace。
  public class ConsoleOutput : IOutput
  {
    public void Write(string content)
    {
      Console.WriteLine(content);
    }
  }

  // 這個接口將“輸出日期”的概念從具體的輸出方法中解耦。
  public interface IDateWriter
  {
    void WriteDate();
  }

  // TodayWriter 是這些元素匯合在一起的地方。
  // 它的構造函數有一個 IOutput 參數,通過提供不同的實現類,
  // TodayWriter可以將日期寫到不同的地方。
  // 進一步的,在這里WriteDate的實現方式是輸出“今天的日期”,
  // 我們可以用另一個類輸出其他格式,或者其他日期。
  public class TodayWriter : IDateWriter
  {
    private IOutput _output;

    public TodayWriter(IOutput output)
    {
      this._output = output;
    }

    public void WriteDate()
    {
      this._output.Write(DateTime.Today.ToShortDateString());
    }
  }
}

現在我們有了組織良好的依賴關系,接下來引入 Autofac。

添加對 Autofac 的引用

首先向項目添加對Autofac的引用。這個示例中,我們只使用 Autofac 的核心部分。其他類型的應用程序可能需要Autofac 集成庫。

最簡單的方式是使用 NuGet。“Autofac” 程序包包含所有核心功能。

程序啟動階段

我們在程序啟動時創建 ContainerBuilder 對象,然后向它注冊組件。組件可以是表達式,.NET 類型, 或者其他暴露服務的代碼。組件可以接受其他依賴項。

假設有下面的.net類型:

public class SomeType : IService
{
}

我們有兩種使用它的方式:

- 作為這個類型本身, SomeType

- 作為接口, IService

因此, 這里的組件是 SomeType,它暴露的服務是 SomeType 和 IService。

在 Autofac 中,使用 ContainerBuilder 注冊組件:

// 創建builder
var builder = new ContainerBuilder(); 

// 通常僅通過接口暴露服務
builder.RegisterType<SomeType>().As<IService>(); 

// 但是, 如果同時需要兩種服務(不常見),可以用這種方式:
builder.RegisterType<SomeType>().AsSelf().As<IService>();

在示例程序中,我們要注冊全部組件(類)并暴露他們的服務 (接口),以便他們能連接起來。

我們還需要把容器保存起來,以便稍后使用它解析類型。

using System;
using Autofac; 

namespace DemoApp
{

  public class Program
  {
    private static IContainer Container { get; set; } 

    static void Main(string[] args)
    {
      var builder = new ContainerBuilder();
      builder.RegisterType<ConsoleOutput>().As<IOutput>();
      builder.RegisterType<TodayWriter>().As<IDateWriter>();
      Container = builder.Build(); 

      // The WriteDate method is where we'll make use
      // of our dependency injection. We'll define that
      // in a bit.
      WriteDate();
    }
  }
}

現在,容器里注冊了全部所需的組件和服務,接下來我們來使用它進行解析。

程序執行階段

程序執行時,通過從 生存范圍 對象解析并使用組件。

容器本身即是一個 生存范圍 對象,因此可以從容器直接解析類型,但是并 不推薦這么做

解析組件時,根據定義的 實例范圍 創建一個新的實例。(解析組件類似于使用new操作符) 有些組件需要清理 (比如實現IDisposable接口) -當 生存范圍 對象被清理時,Autofac 可以同時清理它解析的組件。

由于容器對象的生命周期與應用程序相同,如果從容器直接解析了大量內容, 未處理的組件就會越積越多,從而造成資源泄露。

相反,我們從容器創建一個 生存范圍 對象,然后通過 生存范圍 來解析對象,清理生存范圍對象時,從中解析的組件也一同被清理。

(使用 Autofac 集成庫時,子范圍通常會自動創建。)

對于本示例,“WriteDate” 方法從范圍對象獲取對象,使用結束時只要清理范圍對象。

namespace DemoApp
{
  public class Program
  {
    private static IContainer Container { get; set; } 

    static void Main(string[] args)
    {
      // ...the stuff you saw earlier...
    } 

    public static void WriteDate()
    {
      // Create the scope, resolve your IDateWriter,
      // use it, then dispose of the scope.
      using (var scope = Container.BeginLifetimeScope())
      {
        var writer = scope.Resolve<IDateWriter>();
        writer.WriteDate();
      }
    }
  }
}

程序的執行過程如下:

  • “WriteDate” 方法向 Autofac 請求 IDateWriter 實例。
  • Autofac 發現 IDateWriter 映射到 TodayWriter ,于是準備創建一個 TodayWriter 實例。
  • Autofac 發現 TodayWriter 的構造函數需要一個IOutput 實例。
  • Autofac 發現 IOutput 映射到 ConsoleOutput,于是創建一個ConsoleOutput實例。
  • Autofac 使用 ConsoleOutput 實例完成 TodayWriter 的創建。
  • Autofac 返回 TodayWriter。

想輸出另一個日期時,可以實現另一個 IDateWriter,然后更改啟動階段的注冊內容,而不需要更改其他類。這就是控制反轉。

注意: 一般而言,普遍認為服務定位是反模式。 (see article) 換言之,隨處手工創建范圍對象,在代碼中零散的使用容器對象是不好的方式。通過使用Autofac 集成庫 ,可以避免示例代碼中的使用方式。相反,內容在一個位置集中解析,也就是在程序的 “最頂層”位置,極少需要進行手工解析。

更進一步

示例演示了如何使用 Autofac, 您可以繼續了解:

來自: http://www.cnblogs.com/dongbeifeng/p/autofac-getting-started.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!