jdp*_*nix 8 c# constructor readonly switch-statement
我有一个构造函数,在这样的开关上执行初始化:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我仍然在实现这一点,但一旦完成它将很容易就是几百行.我不喜欢这么大的构造函数,但我不知道如何安全地绕过这个语言特性(并且完全绕过我不想做的事情.)也许应该是暗示我正在尝试做的事情存在根本性的错误,但我不确定.
基本上,我想在我自己的自定义不可变类型中执行复杂的初始化.最好的方法是什么?在这种情况下,无数行数构造函数是一件可怕的事情吗?
更新:为了澄清,我想要做的是在一个类中保持不变性,这个类将以尽可能最好的方式以复杂的方式初始化实例.我正在编写一个代表随机生成的标记的类,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".
Run Code Online (Sandbox Code Playgroud)
最终产生这个问题的类是代表每个标记的类.初始化问题来自能够支持各种格式(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.");
}
}
Run Code Online (Sandbox Code Playgroud)
我readonly最初用过,因为我误解了使用它的原因.简单地删除readonly和替换自动属性({ get; private set; }即将照顾我的不变性问题.
这个问题已成为一个关于初始化任务的问题,而不是关于不变性的问题FormatToken.也许'如何执行复杂的,可能未知的初始化'现在是一个更好的问题标题.我现在完全明白,拥有一个巨大的开关是一个坏主意.工厂模式对我正在做的事情肯定很有吸引力,我想我回答了我的问题.我只想再给它几天.
非常感谢你到目前为止的想法!我将离开最初的示例代码以保持答案有意义.
小智 7
您可以在Foo类上使用静态工厂方法并结合私有构造函数.工厂方法应负责执行大型开关,找出所需的Bar和Baz值,然后简单地将计算值传递给私有构造函数.
当然,这并没有摆脱巨型开关,但它完全将其移出构造函数,在构造函数中我们通常被告知进行大型计算是不好的.
这样你就会得到像这样的东西
class Foo {
public readonly int Bar;
public readonly object Baz;
private Foo(int bar, string baz) {
this.Bar = bar;
this.Bas = baz;
}
public static Foo CreateFoo(int bar, string baz)
{
int tbar;
string tbaz;
switch (bar) {
case 1:
// Boatload of initialization code
tbar = /* value based upon initialization code */
tbaz = /* different value based upon initialization code */
case 2:
// Different boatload of initialization code
tbar = /* value based upon initialization code */
tbaz = /* different value based upon initialization code */
//...
default:
// handle unexpected value
}
return new Foo(tbar, tbaz);
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用自动属性:
public int Bar { get; private set; }.你已经在资本化,Bar就像它是一个财产一样.其他类可以获得Bar,但只有你的类可以设置Bar由于它的private set;setter.
但是,您可以Bar为每个对象设置多次的值.
readonly如果你使用构造函数Micha的方式(/sf/answers/1350174801/),你可以在方法中设置自动属性(但不能使用).
Nah*_*hum -2
switch 语句根本上是错误的!
这是一种方法:(基类) http://simpleprogrammer.com/2012/02/21/refactoring-switches-to-classes/