2015-07-21 70 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

相关问题