關于為什麼需要建立單例?這裡不過多介紹,具體百度知。
關于C# 建立單例步驟或條件吧
1、聲明靜态變量;2、私有構造函數(無法執行個體化)3、靜态建立執行個體的方法;至于我這裡的Singleton是sealed ,隻是為了防止被繼承,其實有私有構造函數足夠了,這裡隻是為了代碼可讀性。
第一種常見的方式建立單例:
/// 不安全的單例
/// </summary>
public sealed class Singleton
{
private static Singleton _Singleton;
private Singleton() { }
public static Singleton GetSingleton()
{
if (_Singleton == null)
{
_Singleton = new Singleton();
}
return _Singleton;
}
}
注:為什麼說是不安全的單例,多線程通路時可能會new多個對象...
第二種方式建立單例:
/// (多線程)安全單例
/// </summary>
public sealed class Singleton
{
private static Singleton _Singleton;
private static readonly object obj = new object();
private Singleton() { }
public static Singleton GetSingleton()
{
if (_Singleton == null)
{
//加鎖保護,在多線程下可以確定執行個體值被建立一次。缺點是每 次擷取單例,都要進行判斷,涉及到的鎖和解鎖比較耗資源。
lock (obj)
{
if (_Singleton == null)
{
_Singleton = new Singleton();
}
}
}
return _Singleton;
}
}
注:為了解決上面第一種方式建立的不安全執行個體問題應用而生。
第三種方式建立單例:
/// 隻讀單例
/// </summary>
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton() { }
public static Singleton Instance
{
get
{
return instance;
}
}
}
/// 基于上面的隻讀單例=自動屬性隻讀單例(文法糖)
/// </summary>
public sealed class Singleton
{
private Singleton() { }
public static Singleton Instance { get; } = new Singleton();
}
注:隻讀屬性式=>借助readonly屬性,instance隻被初始化一次,同樣達到了單例的效果。在引用函數執行第一句話之前,instance其實已經被指派了,并不是預期的 隻有到通路Instance變量時才建立對象。
第四種方式建立單例:
/// Singleton中加上靜态構造函數。
/// </summary>
public sealed class Singleton
{
public static readonly Singleton instance = new Singleton();
private Singleton()
{
Console.WriteLine("初始化1!");
}
static Singleton()
{
}
public static Singleton Instance
{
get { return instance; }
}
}
注:為了解決(第三種隻讀屬性執行個體)在執行第一句代碼之前,執行個體已經被初始化問題。
第五種方式建立單例:
/// 使用Lazy建立單例,預設是線程安全的
/// </summary>
public sealed class Singleton
{
private static readonly Lazy<Singleton> instance = new Lazy<Singleton>(() => new Singleton());//
private Singleton() { }
public static Singleton Instance
{
get
{
return instance.Value;
}
}
}
// 摘要:
// 初始化System.Lazy`1類的新執行個體。 懶惰初始化時
// 發生時,使用指定的初始化函數和初始化模式。
// 參數:
// valueFactory:
// 被調用以生成延遲初始化值的委托是必需的參數
//
// isThreadSafe:
// 如果要使此執行個體可由多個線程同時使用,則為true; false
//使此執行個體一次隻能由一個線程使用。
public Lazy(Func<T> valueFactory, bool isThreadSafe);