2011-11-16 67 views
12

我有一個包含兩個列表一個struct有沒有一種方法來初始化一個struct的成員,而無需使用構造函數?

struct MonthData 
{ 
    public List<DataRow> Frontline; 
    public List<DataRow> Leadership; 
} 

不過,我要來初始化創建結構時。如果我嘗試:

struct MonthData 
{ 
    public List<DataRow> Frontline = new List<DataRow>(); 
    public List<DataRow> Leadership = new List<DataRow>(); 
} 

然後我得到:

Error 23 'MonthData.Frontline': cannot have instance field initializers in structs 
... 

由於結構不能有參數構造函數,我不能只設置這個在構造函數中無論是。到目前爲止,我只能看到如下選項:

  1. 當我創建MonthData的實例
  2. 使用類,而不是一個結構
  3. 帶參數創建一個構造函數和使用初始化兩個屬性
  4. 讓getter和setter方法是初始化它們懶洋洋地 的屬性。

,這是什麼建議的方法?現在,我想讓這個班是最好的主意。

+0

讓它成爲一個類。一旦將引用類型添加到結構中,它實際上不再是值類型。 – drdwilcox

+1

是否真的可以使它成爲引用類型(類)與值類型(結構)?如果是,請繼續並將其設爲一堂課。 – BoltClock

+0

是的,這種類型是一個結構是沒有意義的。 –

回答

7

你應該使用一個類來代替。從MSDN

一般來說,類用於建模更復雜的行爲,或者創建一個類對象之後被修改的意圖的數據。結構最適合小數據結構,主要包含在創建結構後不打算修改的數據。

1

沒有辦法用一個構造函數來做到這一點。 CLR可以並將創建結構實例,只需簡單地初始化內存並避免任何開銷。但是,您可以利用這些知識並創建具有相同可觀察效果的延遲初始化屬性。

例如:

struct MonthData { 
    private bool m_initialized; 
    private List<DataRow> m_frontLine; 
    private List<DataRow> m_leaderShip; 

    public List<DataRow> FrontLine { 
    get { 
     EnsureInitialized(); 
     return m_frontLine; 
    } 
    } 

    public List<DataRow> LeaderShip { 
    get { 
     EnsureInitialized(); 
     return m_leaderShip; 
    } 
    } 

    void EnsureInitialized() { 
    if (!m_initialized) { 
     m_initialized = true; 
     m_frontLine = new List<DataRow>(); 
     m_leaderShip = new List<DataRow>(); 
    } 
    } 
} 
+0

是的,我認爲做這樣的事情將是我的第二選擇。但它是一個如此簡單的對象,我傾向於同意這裏的其他人,並認爲這應該只是一個類 - 尤其是因爲它只包含兩個引用類型。 –

+1

@MikeChristensen是的,它應該可能是一個班。我的答案更多的是「如果你被困在一個角落,必須使用一個結構,然後做到這一點」 – JaredPar

+0

是的,我認爲工廠方法和懶惰初始化方法非常酷 - 我會記住這些以應對未來的設計挑戰。 –

6

如果你只是問語法...嘗試建立和使用靜態工廠,而不是...一般情況下,結構應使用的東西是不可改變的,並一個工廠,(它調用私有構造函數)是一個不變的類型比使用公共構造一個更好的辦法。

struct MonthData 
    {  
     public List<DataRow> Frontline; 
     public List<DataRow> Leadership; 
     private MonthData(List<DataRow> frontLine = null, 
         List<DataRow> leadership = null) 
     { 
     Frontline = frontLine?? new List<DataRow>(); 
     Leadership = leadership?? new List<DataRow>(); 
     } 
     public static MonthData Factory(
      List<DataRow> frontLine= null, 
      List<DataRow> leadership= null) 
     { return new MonthData(frontLine, leadership); } 
    } 
+0

這絕對是一個有趣的方法,正如你所提到的,我的對象並不是不可變的(它更像是一個集合,它的生活)所以也許一個班級是最好的。雖然這個想法+1。 –

+0

我喜歡靜態工廠方法的想法。但是,你可以結構中沒有實例字段初始值設定項。所以'公開名單 FrontLine =新名單()'不會編譯。 –

+0

@Jim Mis,是的,剪切和粘貼沒有編輯...修復它... –

6

你在你的結構使用引用類型(List<T>)反正,因此結構作爲值類型的使用就沒有任何意義了我。我只是去上課。

+0

另一種替代方法是使用'ImmutableArray '並使用@CharlesBretana提到的構建器方法。 – m93a

1

這本來是很好,如果CLR已經讓低保結構類型的東西可能會對他們進行一些初始化代碼運行它們變得可見,以這樣的代碼以外的任何東西之前的一種手段。這本來是能夠做到這一點,建立一個結構類型的數組即使當,通過向陣列本身的任何地方暴露的基準之前通過引用具有CLR通陣列的所有的單個元素。不幸的是,如果在創建數組期間拋出異常,它會導致一種尷尬的情況。如果構造函數沒有任何副作用,那麼就沒有問題 - 只需放棄數組並假裝即使成功創建的對象也不存在。但是,帶有副作用的建設者可能會造成一些困難。

但是,在構造時沒有辦法初始化結構,因此沒有很好的方法來實現需要初始化的對象的值類型語義。抱歉。即使值類型語義更適合您的類型(如果情況比某些人認爲的要多得多),如果需要初始化,您將不得不使用引用類型。對結構進行延遲初始化並不實際。例如,如果有一個字典<字符串,MonthData >調用MyDict,則重複訪問MyDict(「George」)。FrontLine會分別生成一個新的List。討厭。

可變的結構不是邪惡的;如果有的話,我是他們更強大的倡導者之一。儘管如此,.NET在處理可變結構方面存在一些限制,因此很多情況下值類型的語義都是合適的,但.net的限制使得不能正確地提供這樣的語義。

相關問題