c# - 在构造函数之外设置只读字段的可接受方法

标签 c# constructor switch-statement readonly

我有一个构造函数可以像这样在开关上执行初始化:

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 
        } 
    }
}

我仍在实现这个,但一旦完成,它很容易就会有几百行。我不喜欢这么大的构造函数,但我不知道如何安全地绕过这个语言特性(我根本不想绕过)。也许应该是暗示我正在尝试做的事情存在根本性错误,但我不确定。

基本上,我想在我自己的自定义不可变类型中执行复杂的初始化。最好的方法是什么?在这种情况下,大量行数构造函数是一件可怕的事情吗?

更新: 只是为了澄清,我想要做的是在一个类中保持不变性,该类将以尽可能最好的方式以复杂的方式初始化实例。我正在编写一个代表随机生成的标记 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 的不变性的问题。也许“如何执行复杂的、可能未知的初始化”现在是一个更好的问题标题。现在对我来说很明显,拥有一个巨大的开关是一个坏主意。工厂模式对于我正在做的事情来说肯定很有趣,我认为它回答了我的问题。我只想再给它几天时间。

非常感谢您到目前为止的想法!我将初始示例代码留在此处以使答案有意义。

最佳答案

您可以将 Foo 类的静态工厂方法与私有(private)构造函数结合使用。工厂方法应该负责进行大型切换,找出 Bar 和 Baz 的所需值,然后简单地将计算值传递给私有(private)构造函数。

当然,这并没有摆脱巨大的开关,但它把它完全移出构造函数,我们通常被告知在构造函数中进行大量计算是不好的。

这样你最终会得到类似的东西

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);
    }
}

关于c# - 在构造函数之外设置只读字段的可接受方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19288131/

相关文章:

javascript - 创建一个非常长的字符串比这更有效

c# - GTK# Treeview - 如何对子节点进行排序

c# - 将参数分配给sql数据源

c# - CSV 导入(可变字段)

c++ - 以自定义类作为参数的构造函数,抛出 'No matching function for call to...'

c# - C# 中的 Switch 语句

c# - 如何设计应从 C++ 和 C# 访问的组件

c++ - 我对这个 C++ 构造函数感到困惑

java - 创建对象时的尴尬

c++ - 在 switch 条件中从类到枚举类型的隐式转换