不少 Ioc 框架在建立對象的過程當中,都會採起某種方式來緩存/複用/釋放已構建的對象。在 My.Ioc 中,這個目的是經過 Lifetime/ILifetimeScope 來實現的。其中,Lifetime 實現了緩存/複用對象的功能,ILifetimeScope 則實現了複用/釋放對象的功能。緩存
My.Ioc 默認提供了三種 Lifetime:ContainerLifetime、TransientLifetime 和 ScopeLifetime。這裏簡單解釋一下它們的含義:ContainerLifetime 繼承自 SingletonLifetime,它其實是一種單例模式的實現。TransientLifetime 顧名思義,即每次請求都新建一個對象返回給調用者。ScopeLifetime 則代表在某個 scope 及其父 scope 中建立的對象將在該 scope 內複用。框架
上面這樣解釋也許你們不是很容易明白,下面咱們結合示例代碼來講明:ide
using System; using System.Diagnostics; using My.Ioc; using My.Ioc.Exceptions; namespace LifetimeAndLifetimeScope { #region Test Types public class SingletonDisposableClass : IDisposable { public void Dispose() { Console.WriteLine("Disposing SingletonDisposableClass..."); } } public class SingletonNonDisposableClass { } public class TransientNonDisposableClass { } public class TransientDisposableClass : IDisposable { public void Dispose() { Console.WriteLine("Disposing TransientDisposableClass..."); } } public class ScopedDisposableClass : IDisposable { public void Dispose() { Console.WriteLine("Disposing ScopedDisposableClass..."); } } public class ScopedNonDisposableClass { } #endregion class Program { static void Main(string[] args) { var container = new ObjectContainer(false); Register(container); ResolveTransient(container); ResolveScope(container); ResolveSingleton(container); // Dispose the container // The disposable singleton instances should be disposed here. container.Dispose(); Console.ReadLine(); } static void Register(IObjectContainer container) { container.Register<TransientDisposableClass>() .In(Lifetime.Transient()); // This line can be omitted container.Register<TransientNonDisposableClass>() .In(Lifetime.Transient()); // This line can be omitted container.Register<ScopedDisposableClass>() .In(Lifetime.Scope()); container.Register<ScopedNonDisposableClass>() .In(Lifetime.Scope()); container.Register<SingletonDisposableClass>() .In(Lifetime.Container()); //Singleton container.Register<SingletonNonDisposableClass>() .In(Lifetime.Container()); //Singleton container.CommitRegistrations(); } static void ResolveTransient(IObjectContainer container) { var nonDisposable1 = container.Resolve<TransientNonDisposableClass>(); var nonDisposable2 = container.Resolve<TransientNonDisposableClass>(); Debug.Assert(nonDisposable1 != nonDisposable2, "nonDisposable1 == nonDisposable2"); try { var disposable_Error = container.Resolve<TransientDisposableClass>(); } catch (Exception ex) { Debug.Assert(ex is InvalidLifetimeScopeException); } using (var scope = container.BeginLifetimeScope()) { var disposable1 = container.Resolve<TransientDisposableClass>(); var disposable2 = container.Resolve<TransientDisposableClass>(); Debug.Assert(disposable1 != disposable2, "disposable1 == disposable2"); } } static void ResolveScope(IObjectContainer container) { try { var nondisposable_Error = container.Resolve<ScopedNonDisposableClass>(); } catch (Exception ex) { Debug.Assert(ex is InvalidLifetimeScopeException); } string nested_scope_should_share_instance = "{0} should be the same to {1}, because the {0} is resolved in the outer scope, " + "which is shared with the scope where {1} is resolved, so they must be a same instance."; string same_scope_should_share_instance = "{0} should be the same to {1}, because they are resolved in the same scope."; using (var scope1 = container.BeginLifetimeScope()) { var disposable1 = scope1.Resolve<ScopedDisposableClass>(); var nonDisposable1 = scope1.Resolve<ScopedNonDisposableClass>(); using (var scope2 = scope1.BeginLifetimeScope()) { var disposable2 = scope2.Resolve<ScopedDisposableClass>(); var disposable3 = scope2.Resolve<ScopedDisposableClass>(); Debug.Assert(disposable1 == disposable2, string.Format(nested_scope_should_share_instance, "disposable1", "disposable2")); Debug.Assert(disposable1 == disposable3, string.Format(nested_scope_should_share_instance, "disposable1", "disposable3")); Debug.Assert(disposable2 == disposable3, string.Format(same_scope_should_share_instance, "disposable2", "disposable3")); var nonDisposable2 = scope1.Resolve<ScopedNonDisposableClass>(); var nonDisposable3 = scope1.Resolve<ScopedNonDisposableClass>(); Debug.Assert(nonDisposable1 == nonDisposable2, string.Format(nested_scope_should_share_instance, "nonDisposable1", "nonDisposable2")); Debug.Assert(nonDisposable1 == nonDisposable3, string.Format(nested_scope_should_share_instance, "nonDisposable1", "nonDisposable3")); Debug.Assert(nonDisposable2 == nonDisposable3, string.Format(same_scope_should_share_instance, "nonDisposable2", "nonDisposable3")); } } } static void ResolveSingleton(IObjectContainer container) { var disposable1 = container.Resolve<SingletonDisposableClass>(); var disposable2 = container.Resolve<SingletonDisposableClass>(); Debug.Assert(disposable1 == disposable2, "disposable1 != disposable2"); var nonDisposable1 = container.Resolve<SingletonDisposableClass>(); var nonDisposable2 = container.Resolve<SingletonDisposableClass>(); Debug.Assert(nonDisposable1 == nonDisposable2, "disposable1 != nonDisposable2"); } } }
在示例中,咱們設計了這麼三對類型:SingletonDisposableClass/SingletonNonDisposableClass、ScopedDisposableClass/ScopedNonDisposableClass 以及 TransientNonDisposableClass/TransientDisposableClass。用意很簡單,分別註冊到上面三種類型的 Lifetime 中。而每一類對象之因此有 Disposable 和 NonDisposable 兩個類型,是由於咱們要展現這三類 Lifetime 中對象清理的策略。spa
咱們首先在 Register 方法中將 SingletonDisposableClass/SingletonNonDisposableClass 註冊爲 Container 生命週期,將 ScopedDisposableClass/ScopedNonDisposableClass 註冊爲 Scope 生命週期,並將 TransientNonDisposableClass/TransientDisposableClass 註冊爲 Transient 生命週期。設計
作好了準備工做以後,下面咱們要讓容器來爲咱們建立上述對象。首先,咱們看 ResolveTransient 這個方法。這個方法旨在告訴咱們:code
接着,咱們來看一下 ResolveScope 這個方法。這個方法是咱們用來演示 ScopeLifetime 的運行方式的。它告訴咱們:orm
最後咱們來看 ResolveSingleton 這個方法。咱們使用這個方法來觀察 ContainerLifetime 的運行方式。這個方法的運行結果告訴咱們:對象
本文源碼可在此處下載,壓縮包中包含了 My.Ioc 框架的源碼和本示例以及其餘一些示例的源碼。blog