2012-02-15 136 views
2

我有一個類,DataAdapter,它被我的站點實例化爲單例對象。這個類有我想成爲一個懶惰的單身一個人屬性,代碼來實現:.Net Singleton屬性的延遲初始化

private readonly object _personLock = new object(); 
private volatile IPersonManager _person; 
public IPersonManager Person 
{ 
    get 
    { 
     if (_person == null) 
     { 
      lock (_personLock) 
      { 
       if (_person == null) 
       { 
        _person = new PersonManager(_adUserName, _adPassword, client); 
       } 
      } 
     } 
     return _person; 
    } 
} 

(這三個參數的構造函數的PersonManager的性能/當前對象的字段。) 這代碼完美工作(這是一個double-lock check模式)。

但是,這是很多代碼,我想利用.Net 4.0中的新Lazy<> type使其更簡單。所以我改變了代碼:

private static readonly Lazy<IPersonManager> _person = new Lazy<IPersonManager>(() => new PersonManager(_adUserName, _adPassword, client)); 
    public static IPersonManager Person { get { return _person.Value; } } 

但是,這並不工作,因爲這三個參數是不是靜態的(他們是在當前的方法實例對象)。 writeupsI've found沒有解決這個問題。我需要一些方法將這些值傳遞給該lambda表達式?懶惰<>類看起來像期待一個空的簽名。

回答

0

(這三個參數傳遞給的PersonManager構造是對當前對象 屬性/字段。)

構造函數被用於初始化對象。您嘗試通過的參數目前沒有賦值給它們的值。如果你的對象需要這些值被正確初始化,那麼當你初始化時它們需要被傳入。

雖然您可以將您的屬性轉換爲方法並將這些值傳遞給靜態GetInstance方法,但您只會在第一次調用GetInstance時設置一次。這可能不是一個好主意,但它可以完成。我會將你的Person屬性轉換爲Method,並接受這些參數並使用它們初始化構造函數。這確實意味着你不會使用Lazy<T>,你的代碼行會增加,但你會有更多可預測的行爲。

+0

你不正確有關不具有價值,他們的對象的構造函數中賦值的對象。我沒有得到一個空引用異常,我得到一個編譯錯誤,因爲這些字段找不到。 我不確定你的建議比我開始使用的(工作)雙重檢查鎖解決方案要好。 – Arbiter 2012-02-15 18:17:21

+0

@Arbiter從初始化它們的代碼中不清楚。 KeithS建議應該爲你工作。我的第二個建議是不混合模式。 – sarvesh 2012-02-15 19:12:40

3

那麼,如果Lazy使用Instance屬性與單例的一個實例一起工作來爲自己提供屬性呢?這些字段仍然可以是私有的,因爲我們正在從類內部使用它們(聰明),整個事情仍然是懶惰的,直到Singleton.Instance在執行過程中第一次被引用。但是,在代碼嘗試獲取Person屬性之前,私有字段必須具有適當的值。如果他們在Singleton實例化時急於加載,那很好。

C# In Depth借用,這是一個準懶惰的Singleton,帶有一個完全惰性的Person成員,它使用一個引用Singleton的lambda進行初始化。

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    // Explicit static constructor to tell C# compiler 
    // not to mark type as beforefieldinit 
    static Singleton() 
    { 
    } 

    private Singleton() 
    { 
     //I HIGHLY recommend you initialize _adusername, 
     //_adpassword and client here. 
    } 

    public static Singleton Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 

    private static readonly Lazy<IPersonManager> _person = 
     new Lazy<IPersonManager>(() => new PersonManager(Instance._adUserName, Instance._adPassword, Instance.client)); 
    public static IPersonManager Person { get { return _person.Value; } } 

    private object _adUserName; 
    private object _adPassword; 
    private object client; 
} 

public class PersonManager:IPersonManager {} 

public interface IPersonManager{} 

編輯:如果你有國際奧委會,一個使用IoC。您目前正在嘗試混合模式;您正在使用IoC使用運行時規則將「實例類」提升爲單例,但隨後嘗試基於此單元的實例範圍數據字段實例化編譯器實施的惰性靜態屬性。這根本不起作用

一旦你去了IoC,每一個依賴應該被註冊和注入。使用Ninject註冊PersonManager作爲IPersonManager實現,然後爲您的主單例DataAdapter創建一個構造函數,該函數可以被賦予一個生成IPersonManager的Func。通常可以爲此定義一個自定義函數,在您的情況下,它將利用IoC從保存在容器中的單個DataAdapter實例提供所需的實例數據。

警告:這些數據字段現在必須公開可讀,以避免一些嚴重的醜陋反映;您可以將這些字段定義爲只讀字段或只讀屬性,以防止人們篡改它們,但消費者將能夠看到它們。

編輯2:這是我腦子裏想的:

//in your Ninject bindings: 
kernel.Bind<DataAdapter>().ToSelf().InSingletonScope(); 
kernel.Bind<PersonManager>().ToSelf().InSingletonScope(); 
//to bind the interface 
kernel.Bind<IPersonManager>() 
    .ToMethod(c =>{ 
     var adapter = kernel.Get<DataAdapter>(); 
     //this is why these fields would have to be public 
     var arg1 = new ConstructorArgument("adUserName", adapter._adUserName) 
     var arg2 = new ConstructorArgument("adPassword", adapter._adPassword) 
     var arg3 = new ConstructorArgument("client", adapter.client) 
     //the names of the arguments must match PersonManager's constructor 
     c.Kernel.Get<PersonManager>(arg1, arg2, arg3); 
    }); 

//now in your DataAdapter, specify a constructor like this, and Ninject will provide: 

public DataAdapter(Func<IPersonManager> personFunc) 
{ 
    //_person should obviously not be instantiated where it's defined in this case 
    _person = new Lazy<IPersonManager>(personFunc); 
} 
+0

一個好主意,但它不適合我。我沒有使用像這樣的靜態屬性來實現'Singleton',它被ninject注入爲單例。如果'Singleton'在這種情況下不是單身人士,而是普通實例成員,你會怎麼做? – Arbiter 2012-02-15 18:23:19

+0

@Arbiter:請參閱編輯。 – KeithS 2012-02-15 18:55:36

+0

'Singleton'目前有一個構造函數('client'對象不能在沒有連接字符串的情況下被初始化)。如果我擺脫了構造函數,我需要修改我的注入以使用屬性注入而不是構造函數注入,但是隻是爲了使用Lazy <>類而跳過了很多箍環。我認爲這不是正確的工具。 – Arbiter 2012-02-15 19:11:50