2015-07-21 3 views
0

У меня есть класс, FooBarSet с одним «ядром» блока логики инициализации.Как я могу поделиться кодом конструктора с членами класса readonly?

A FooBar изготовлен из Foo и Bar. Класс FooBarSet инициализируется списком FooBar. FooBarSet может также быть инициализирован отдельными параллельными Foo и Bar списками.

В идеале, я мог бы работать так:

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() 'metho d для каждого из них. (Надеемся, что количество членов 'readonly' невелико или растет.) – 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

Я думаю, что каждый раз, когда я когда-либо использовал синтаксис конструктора «base», ': this (StaticMethod (bla, bloo)' или ': base (OtherStatic (bloo, blee)'), используемый им конструктор был полностью пуст. Это всегда так: – kdbanman

+0

@kdbanman no, вы можете цепью конструкторов довольно глубоко, как это, вызывая другие конструкторы со значениями по умолчанию и сохраняя инициализацию в одном конструкторе. –

+0

@RonBeyer, извините, я не думаю, что это то, что я имел в виду. Обратите внимание, что тело двухпараметрического конструктора пуст? Всякий раз, когда я настраивал альтернативный конструктор, подобный этому (используя синтаксис ': this()'), его тело всегда заканчивается пустым. Следовательно, для каждого из этих пустых конструкторов , Я получаю статический метод, который содержит код I *, который бы * помещал в альтернативный конструктор в стиле Java. – kdbanman

Смежные вопросы