Unity使用繼承於 LifetimeManager 基類的類去控制怎樣存放到對象實例的引用和容器怎樣銷毀這些實例,也就是說Unity基於具體的Lifetime Manager 類去管理對象的創建和銷毀。
目前Unity中提供兩個Lifetime Manager類可供我們直接使用,當然你也可以實現自己的Lifetime Manager類。
1. ContainerControlledLifetimeManager
Unity保存一個指向對象實例的引用。通過Unity容器為同一個類型或對象獲取對象實例時,每次獲取到的都是同一個實例。也就是說實現了對象單例模式。默認情況下,RegisterInstance方法使用該Lifetime Manager。
2. ExternallyControlledLifetimeManager
Unity僅保存一個指向對象實例的弱引用。通過Unity容器為同一個類型或對象獲取對象實例時,每次獲取到的都是同一個實例。但是由於當對象創建完之後,容器沒有對該對象的強引用,所以就可能出現當其他地方沒有去強引用它時候,會被GC回收掉。
先看看一個接口和類,下面會用到
public interface IPlayer
{
void Play();
}
public class Mp3Player : IPlayer
{
public void Play()
{
Console.WriteLine("Playing Mp3");
}
}
接下來通過在RegisterType和RegisterInstance時指定相應的Lifetime Manager來介紹Lifetime Manager的應用場景。
1. RegisterType
當用RegisterType注冊映射關系時,如果沒有指定LifetimeManager,默認是使用一個瞬態的Lifetime Manager。即每次通過Unity容器獲取對象的實例時都會重新創建一個該實例,也就是說Unity容器不存在一個到該對象的引用。
看一個例子:
IUnityContainer container = new UnityContainer();
container.RegisterType<IPlayer, Mp3Player>();
IPlayer player1 = container.Resolve<IPlayer>();
Console.WriteLine(string.Format("Player1 HashCode: {0}",player1.GetHashCode()));
IPlayer player2 = container.Resolve<IPlayer>();
Console.WriteLine(string.Format("Player2 HashCode: {0}",player2.GetHashCode()));
輸出結果:
通過輸出的player1和player2對象的HashCode值可以看出,player1和player2分別是Mp3Player類的不同實例。
那怎樣實現單例模式呢?
要實現單例模式,容器需要保存一個指向對象實例的引用。通過在RegisterType時為它指定相應的Lifetime Manager可以實現單例模式,從上面對ContainerControlledLifetimeManager和ExternallyControlledLifetimeManager的介紹可以知道,這兩個Lifetime Manager都可以支持單例模式。
修改上面的代碼為:
IUnityContainer container = new UnityContainer();
//這裡指定使用ContainerControlledLifetimeManager對象
container.RegisterType<IPlayer, Mp3Player>(new ContainerControlledLifetimeManager());
IPlayer player1 = container.Resolve<IPlayer>();
Console.WriteLine(string.Format("Player1 HashCode: {0}",player1.GetHashCode()));
IPlayer player2 = container.Resolve<IPlayer>();
Console.WriteLine(string.Format("Player2 HashCode: {0}",player2.GetHashCode()));
看看輸出:
通過輸出結果可以看出,player1和player2對象為Mp3Player類的同一實例,指向同一內存地址。
2. RegisterInstance
當用RegisterInstance注冊映射關系時,如果沒有指定Lifetime Manager,默認是使用ContainerControlledLifetimeManager,即支持單例模式。
看個例子:
IUnityContainer container = new UnityContainer();
IPlayer mp3Player = new Mp3Player();
container.RegisterInstance<IPlayer>(mp3Player);
IPlayer player1 = container.Resolve<IPlayer>();
Console.WriteLine(string.Format("Player1 HashCode: {0}", player1.GetHashCode()));
IPlayer player2 = container.Resolve<IPlayer>();
Console.WriteLine(string.Format("Player2 HashCode: {0}", player2.GetHashCode()));
看看輸出:
通過輸出結果可以看出,player1和player2對象為Mp3Player類的同一實例,指向同一內存地址。