先说一下两个概念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"使用.
- Autofac发现
- 调用
writer.WriteDate()
就是一个全新的TodayWriter.WriteDate()
因为这就是它所解析出的. - Autofac生命周期被释放. 任何从生命周期解析出的可释放对象也都被同时释放.
之后,如果你希望你的应用输出一个不同的日期, 你可以实现另外一个 IDateWriter
然后在应用启动时改变一下注册过程. 你不需要修改任何其他的类. 耶, 这就是控制反转!
注意: 通常来说, 服务定位模式大多情况应被看作是一种反模式 (阅读文章). 也就是说, 在代码中四处人为地创建生命周期而少量地使用容器并不是最佳的方式. 使用 Autofac 集成类库 时你通常不必做在示例应用中的这些事. 这些东西都会在应用的中心,"顶层"的位置得到解决, 人为的处理是极少存在的. 当然, 如何构建你的应用取决于你自身.
参考: