2015-07-21 66 views
0

我有一個類,FooBarSet與一個「核心」塊的初始化邏輯。如何與只讀類成員共享構造函數代碼?

A FooBarFooBar組成。類別FooBarSet初始化爲FooBar的列表。 FooBarSet可以也可以被分開的並行FooBar列表初始化。

理想情況下,我可以像這樣運行:

public class FooBarSet 
{ 
    private readonly List<FooBar> _list; 

    // Primary constructor. 
    public FooBarSet(List<FooBar> foobarList) 
    { 
     // Contracts and initialization... 
     _list = foobarList; 
    } 

    // Secondary constructor. 
    public FooBarSet(List<Foo> fooList, List<Bar> barList) 
    { 
     // Zip a new list of new FooBars 
     var zipped = fooList.Zip(barList, 
           (foo, bar) => new FooBar(foo, bar)); 

     // Call primary constructor with zipped list. 
     this(zipped); 
    } 
} 

這是C#,而不是Java,所以this(zipped)是非法的。常見的解決辦法,as in this answer,就是拉核心初始化成一個共同的私有方法:

public class FooBarSet 
{ 
    private readonly List<FooBar> _list; 

    // Common "constructor" called from actual constructors. 
    private Init(List<FooBar> foobarList) 
    { 
     // Contracts and initialization... 
     _list = foobarList; 
    } 

    public FooBarSet(List<FooBar> foobarList) 
    { 
     Init(foobarList); 
    } 

    public FooBarSet(List<Foo> fooList, List<Bar> barList) 
    { 
     var zipped = fooList.Zip(barList, 
           (foo, bar) => new FooBar(foo, bar)); 

     Init(zipped); 
    } 

} 

然而,這也不行,因爲readonly _list領域。

假設_list必須是readonly,我怎樣才能讓這些構造函數共享初始化代碼?

+0

'_list = Init(foobarList)'在構造函數中?使'Init'返回'List '而不是。 –

+0

@RonBeyer,我非常喜歡。它適用於我的實際實施,而不僅僅是我使用的[MWE](https://en.wikipedia.org/wiki/Minimal_Working_Example)。拋棄它作爲答案,只要某些瘋狂的美麗不會彈出,它就是你的。 – kdbanman

+0

注意:只有列表的_reference_是隻讀的,您可以隨時更改**內容**。顯而易見的解決方案,然後.... –

回答

2

簡單的答案是讓Init方法返回值在構造函數中進行設置:

public class FooBarSet 
{ 
    private readonly List<FooBar> _list; 

    // Common "constructor" called from actual constructors. 
    private List<FooBar> Init(List<FooBar> foobarList) 
    { 
     // Contracts and initialization... 
     return whateverList; 
    } 

    public FooBarSet(List<FooBar> foobarList) 
    { 
     _list = Init(foobarList); 
    } 

    public FooBarSet(List<Foo> fooList, List<Bar> barList) 
    { 
     var zipped = fooList.Zip(barList, 
           (foo, bar) => new FooBar(foo, bar)); 

     _list = Init(zipped); 
    } 

} 
+0

如果你碰巧擁有多個'readonly'成員,那麼這個擴展就是有一個' Init()'方法d爲他們每個人。 (希望「只讀」成員的數量不大或增加。) – kdbanman

3

可以「拉鍊」的代碼移動到一個靜態的功能和使用:

public class FooBarSet 
{ 
    private readonly List<FooBar> _list; 

    private static List<FooBar> Prepare(List<Foo> fooList, List<Bar> barList) 
    { 
     return fooList.Zip(barList, (foo, bar) => new FooBar(foo, bar)); 
    } 

    public FooBarSet(List<Foo> fooList, List<Bar> barList) : 
     this(Prepare(fooList, barList)) 
    { 
    } 

    public FooBarSet(List<FooBar> zippedList) 
    { 
     _list = zippedList; 
    } 
} 
+0

我認爲每次我使用過「基本」構造函數語法':this(StaticMethod(bla,bloo)'或':base(OtherStatic(bloo,blee)')時,使用它的構造函數都是完全空的。這種情況總是如此嗎? – kdbanman

+0

@kdbanman不,你可以通過調用具有默認值的其他構造函數來鏈接構造函數,並將初始化保存在一個構造函數中 –

+0

@RonBeyer,對不起,我不認爲這就是我的意思。注意雙參數構造函數的主體是空的嗎?每當我設置一個像這樣的替代構造函數時(使用':this()'語法),它的body總是空的,因此,對於每個空構造函數,我最終得到一個靜態方法,該方法包含我將*放在Java風格的另一個構造函數中的代碼。 – kdbanman

相關問題