У меня есть конструктор, который выполняет инициализацию на переключателе, как это:Приемлемый способ установить только для чтения поле вне конструктора
class Foo {
public readonly int Bar;
public readonly object Baz;
public Foo(int bar, string baz) {
this.Bar = bar;
switch (bar) {
case 1:
// Boatload of initialization code
this.Bar = /* value based upon initialization code */
this.Baz = /* different value based upon initialization code */
case 2:
// Different boatload of initialization code
this.Bar = /* value based upon initialization code */
this.Baz = /* different value based upon initialization code */
case 3:
// Yet another...
this.Bar = /* value based upon initialization code */
this.Baz = /* different value based upon initialization code */
default:
// handle unexpected value
}
}
}
Я до сих пор осуществляет это, но когда-то сделали это легко будет несколько сотен линий. Я не поклонник создания такого конструктора, но я не понимаю, как либо безопасно обойти эту языковую функцию (и обходить вообще - это то, что я не хочу делать). Может быть, должно быть намек на то, что есть что-то принципиально неправильное с тем, что я пытаюсь сделать, но я не уверен.
В принципе, я хочу выполнить сложную инициализацию в своем собственном неизменяемом типе. Каков наилучший способ сделать это? Является ли gazillion конструктором строк ужасным в этом случае?
Обновление: Просто для уточнения, я хочу сохранить неизменность в классе, который бы инициализировал экземпляры сложным образом наилучшим образом Я пишу класс, который представляет случайное сгенерированное ken, FormatToken
, который обычно был бы персонажем.
Комплекса инициализации разбор формат строка (обратите внимание, я не пытается разобрать регулярное выражение для генерации случайной строки, я не чувствую, как тратить мои следующие 20 жизней делать это :)). Я был изначально писать что-то, что будет принимать входной сигнал с помощью параметра конструктора, такого, как
+ /// Format tokens
+ /// c{l} Lowercase Roman character in the ASCII range.
+ /// v{L} Uppercase Roman character in the ASCII range.
+ /// c Roman character in the ASCII range.
+ /// d Decimal.
+ /// d{0-9} Decimal with optional range, both minimum and maximum inclusive.
var rand = new RandomString("c{l}C{L}ddd{0-4}d{5-9}");
rand.Value == /* could equal "fz8318" or "dP8945", but not "f92781".
Класса, который в конечном счете породил этот вопрос был то, что представляет собой каждый из этих маркеров. Вопрос инициализации приходит от того, чтобы поддерживать различные форматы (ASCII символы, буквы латинского алфавита, десятичные, символы и т.д.)
Это фактический код в вопросе:
internal class FormatToken {
public TokenType Specifier { get; private set; }
public object Parameter { get; private set; }
public FormatToken(TokenType _specifier, string _parameter) {
// discussion of this constructor at
// http://stackoverflow.com/questions/19288131/acceptable-way-to-set-readonly-field-outside-of-a-constructor/
Specifier = _specifier;
_init(_specifier, _parameter);
}
private void _init(TokenType _specifier, string _parameter) {
switch (_specifier) {
case TokenType.Decimal:
_initDecimalToken(_parameter);
break;
case TokenType.Literal:
Parameter = _parameter;
break;
case TokenType.Roman:
case TokenType.LowerRoman:
case TokenType.UpperRoman:
_initRomanToken(_specifier, _parameter);
break;
default:
throw new ArgumentOutOfRangeException("Unexpected value of TokenType.");
}
}
Я использовал readonly
первоначально, потому что я неправильно поняли причину его использования. Простое удаление readonly
и замена с автоматической собственностью (т.е. { get; private set; }
будет заботиться о моей неизменности беспокойства.
Этот вопрос стал еще вопросом о задачах инициализации и меньше о неизменности FormatToken
. Может быть, «Как выполнить комплекс , возможно, неизвестная инициализация »- теперь это лучший вопрос. Теперь мне совершенно очевидно, что наличие гигантского переключателя - плохая идея. Заводская модель, безусловно, интригует за то, что я делаю, и я думаю, что отвечает на вопрос, который у меня есть. Я просто хочу дать ему еще пару дней.
Огромное вам спасибо за ваши мысли до сих пор! Я оставляю здесь исходный пример кода, чтобы дать ответы на вопросы.
Readonly означает ТОЛЬКО для чтения ... вы не сможете его установить. Но почему бы не использовать публичный геттер и частный сеттер для вашей собственности? Вы также можете использовать метод с параметром out-parameter для вашего свойства: Init (out this.bar) – HimBromBeere
Это не строго верно, значения readonly могут быть инициализированы в конструкторе. – codemonkeh
Какую инициализацию мы говорим здесь? Просто установка значений по умолчанию может быть выставлена со свойствами. – codemonkeh