2016-11-25 40 views
0

我想知道在某個對象中創建列表的最佳方法是什麼。C#創建列表<T>在初始化vs得到

1)DefA「always」事先佔用內存,即使它永遠不會被調用,對嗎?

2)DefB將「總是」必須檢查空條件還是編譯器優化?

3)有沒有更好的實現方法?

感謝

private List<A> _defA = new List<A>(); 
public List<A> DefA 
{ 
    get { return _defA; } 
} 

private List<B> _defB; 
public List<B> DefB 
{ 
    get 
    { 
     if (_defB == null) 
      _defB = new List<B>(); 

     return _defB; 
    } 
} 
+1

您如何期望編譯器優化第二種情況下的檢查?至於「更好」 - 這取決於你是否在意懶惰。你有沒有具體的證據表明* *不必要的清單*或*空檢查實際上對你的應用程序有重大影響? –

+2

認爲在多線程訪問財產的情況下,A和B的行爲可能會有所不同。 – tym32167

+0

這對於[CodeReview](http://codereview.stackexchange.com/)是一個很好的問題。 –

回答

1

在這個具體的例子,延遲(懶)實例可能會節省啓動幾毫秒;但面臨多線程場景中的問題。

說兩個線程幾乎同時調用DefB(Get) - 它們最終可能會設置_defB兩次,而不是您打算的一次。

_defA總是會記住一個空列表,據我所知,是的 - 所以如果沒有調用它,第二種方式會節省一些內存 - 但它確實使代碼很難理解。另外,如果一個本地代碼段不調用訪問器方法,但只是執行_defB.Add()或其他什麼? (現在可能並不是故意的,但因爲它更復雜,將來很容易忘記/錯過)

+1

詞綴:對於第二個,在使用List實例之前,您總是需要檢查'null'。這使得代碼不易讀。 –

2

因爲我認爲這兩個選項都不會影響應用程序的性能,所以我建議選擇一個保持代碼清潔的選項

使用延遲型 - Lazy on MSDN

從MSDN關於延遲初始化:

默認情況下,懶惰的對象是線程安全的。也就是說,如果 構造函數沒有指定線程安全類型,則它創建的Lazy 對象是線程安全的。在多線程場景中,訪問線程安全的Lazy 對象的Value屬性的第一個線程會對所有線程上的所有後續訪問進行初始化,並且所有線程共享相同的數據。因此,線程初始化哪個對象並不重要,競態條件是良性的。

所以你的情況

private Lazy<List<A>> _defA = new Lazy<List<A>>(() => new List<A>()); 

public List<A> DefA 
{ 
    get 
    { 
     return _defA.Value; 
    } 
} 

另外這種方法會告訴你的意圖給其他開發者誰可能與您的代碼工作。

0

首先,不要優化不需要優化的東西。

如果您要創建數千或數百萬個包含該屬性的對象,並且此屬性很少使用,因此很少需要,那麼是的,添加懶惰的按需初始化可能是一個好主意。我說可能是因爲可能還有其他與表現相關的問題。

然而,回答您的具體問題,不是「什麼是最好的辦法」等:

  1. _defA初始化將構建即使是從未使用過的屬性List<A>對象,這是正確的。
  2. DefB的getter方法將始終執行空檢查,這也是正確的。編譯器無法優化這一點。

至於「更好的辦法」?問題的這一部分屬於Stack Overflow的「主要基於觀點的」關閉選項。這在很大程度上取決於你確定是什麼更好:

  1. 更具表現力的語法(短碼)
  2. 更少的內存花(選項B)的吸氣劑(選項A)
  3. 更少的代碼

我可以給你一個替代在選擇A的語法:

public List<A> DefA 
{ 
    get; 
} = new List<A>(); 

此語法在C#6的Visual Studio 2015中可用(即使您編譯器適用於較舊的.NET運行時版本)也稱爲自動屬性初始值設定項。

編譯器它將自動爲您創建支持字段(相當於_defA),並標記爲只讀,所以功能方面這是100%相同的選項A,它只是一個不同的語法。