1. 程式人生 > 實用技巧 >IoC 容器

IoC 容器

先說一下兩個概念IOC和DI,我的理解:

  ① IOC:呼叫者不再建立(不自己new)被呼叫者的例項,而是交給容器去建立(AutoFac就充當這裡的容器),這就是控制反轉。

  ② DI:容器建立好的例項再注入呼叫者的過程,就是依賴注入(比如:屬性注入、建構函式注入等)。

1.C# Autofac

using Autofac;
using System;

namespace ConsoleApplication1
{
    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. using (var scope = Container.BeginLifetimeScope()) { var writer = scope.Resolve<IDateWriter>(); writer.WriteDate(); } Console.ReadLine(); } }
// This interface helps decouple the concept of // "writing output" from the Console class. We // don't really "care" how the Write operation // happens, just that we can write. public interface IOutput { void Write(string content); } // This implementation of the IOutput interface // is actually how we write to the Console. Technically // we could also implement IOutput to write to Debug // or Trace... or anywhere else. public class ConsoleOutput : IOutput { public void Write(string content) { Console.WriteLine(content); } } // This interface decouples the notion of writing // a date from the actual mechanism that performs // the writing. Like with IOutput, the process // is abstracted behind an interface. public interface IDateWriter { void WriteDate(); } // This TodayWriter is where it all comes together. // Notice it takes a constructor parameter of type // IOutput - that lets the writer write to anywhere // based on the implementation. Further, it implements // WriteDate such that today's date is written out; // you could have one that writes in a different format // or a different date. public class TodayWriter : IDateWriter { private IOutput _output; public TodayWriter(IOutput output) { this._output = output; } public void WriteDate() { this._output.Write(DateTime.Today.ToShortDateString()); } } }

現在當執行程式時...

  • WriteDate方法建立了一個生命週期, 從中可以解析依賴. 這麼做可以避免記憶體洩漏 - 如果IDateWriter或者它的依賴是可被釋放的(disposable)的, 那麼當生命週期被釋放時他們也將被自動釋放.
  • WriteDate方法手動地從生命週期中解析IDateWriter. (這就是 "服務定位.") 在內部地...
    • Autofac發現IDateWriter對應TodayWriter因此開始建立TodayWriter.
    • Autofac發現TodayWriter在它構造方法中需要一個IOutput. (這就是 "構造方法注入.")
    • Autofac發現IOutput對應ConsoleOutput因此開始建立新的ConsoleOutput例項.
    • Autofac使用新的ConsoleOutput例項完成TodayWriter的建立.
    • Autofac返回完整構建的TodayWriter給"WriteDate"使用.
  • 呼叫writer.WriteDate()就是一個全新的TodayWriter.WriteDate()因為這就是它所解析出的.
  • Autofac生命週期被釋放. 任何從生命週期解析出的可釋放物件也都被同時釋放.

之後,如果你希望你的應用輸出一個不同的日期, 你可以實現另外一個IDateWriter然後在應用啟動時改變一下注冊過程. 你不需要修改任何其他的類. 耶, 這就是控制反轉!

注意: 通常來說, 服務定位模式大多情況應被看作是一種反模式(閱讀文章). 也就是說, 在程式碼中四處人為地建立生命週期而少量地使用容器並不是最佳的方式. 使用Autofac 整合類庫時你通常不必做在示例應用中的這些事. 這些東西都會在應用的中心,"頂層"的位置得到解決, 人為的處理是極少存在的. 當然, 如何構建你的應用取決於你自身.

參考:

Autofac官網

Autofac學習系列之-入門