有没有办法简化这种开关案例?

时间:2016-01-03 19:30:16

标签: c# switch-statement refactoring

就像标题所说,我想简化一个switch-case语句。我目前在我的switch-case声明中有这个:

switch(someEnum) {
case EnumType.A:
    SomeMethodSpecificToA();
    AMethodIShouldCallOnAllVowels();
    break;
case EnumType.B:
case EnumType.C:
case EnumType.D:
    SomeMethodSpecificToTheseThreeLetters();
    AMethodIShouldCallOnAllConsonants();
    break;
case EnumType.E:
    SomeMethodSpecificToE();
    AMethodIShouldCallOnAllVowels();
    break;
// All other letters, also containing the vowels & consonants methods
}

所以我知道我可以链接多个case语句以使它们做同样的事情,但我不知道我怎么能这样做,以便2个字母做2个单独的事情然后落到第二个声明,适用于所有元音(或所有辅音)。在Swift我会做这样的事情:

func test(someEnum: EnumType) {
    switch someEnum {
    case .A:
        someMethodSpecificToA()
        fallthrough
    case .B, .C, .D:
        someMethodSpecificToTheseThreeLetters()
        fallthrough
    case .E:
        someMethodSpecificToE()
        fallthrough
    case .A, .E:
        aMethodIShouldCallOnVowels()
    case .B, .C, .D:
        aMethodIShouldCallOnAllConsonants()
    }
}

有没有办法在不使用2个switch语句的情况下执行此操作?这似乎是多余的,因为我已经打开了那个变量。

4 个答案:

答案 0 :(得分:4)

我只是将all限制为cases,并在Specific()'s之后放置一个简单的if-else:

switch block

同时查看default:(但在这种情况下可能没有用)。

答案 1 :(得分:1)

转到下一个案例是"转到案例2;"。 我也相信这是一个相关的问题: [Using `continue` keywoard in a switch nest inside a foreach loop

答案 2 :(得分:1)

  

有没有办法在不使用2个switch语句的情况下执行此操作?

是。使用if语句。

EnumType[] Vowels = new [] {EnumType.A, EnumType.E, EnumType.I, EnumType.O, EnumType.U};

if (someEnum == EnumType.A)
    SomeMethodSpecificToA();

if (new [] {EnumType.B, EnumType.C, EnumType.D}.Contains(someEnum))
    SomeMethodSpecificToTheseThreeLetters();

if (someEnum == EnumType.E)
    SomeMethodSpecificToE();

if (Vowels.Contains(someEnum))
    AMethodIShouldCallOnAllVowels();

根据实际代码中“字母”的复杂程度,您可能会发现类而不是枚举更适合。这样做,您可以替换所有条件逻辑(if和switch语句)。一个重构选项可能如下所示:

abstract class Letter
{
    public char Value { get; private set; }
    protected abstract void FrobInternal();
    public void Frob()
    {
        FrobInternal();
        // optionally code to be called for all letters
    }

    // private constructor limits inheritance to nested classes
    private Letter(char value) { Value = value; }

    class Vowel : Letter
    {
        public Vowel(char letter) : base(letter) { }
        sealed protected override void FrobInternal()
        {
            FrobVowel();
            AMethodIShouldCallOnAllVowels();
        }
        protected virtual void FrobVowel() { }
        private void AMethodIShouldCallOnAllVowels()
        {
            // Implementation...
        }
    }
    class Consonant : Letter
    {
        public Consonant(char letter) : base(letter) { }
        sealed protected override void FrobInternal()
        {
            FrobConsonant();
            AMethodIShouldCallOnAllConsanants();
        }
        protected virtual void FrobConsonant() { }
        private void AMethodIShouldCallOnAllConsanants()
        {
            // Implementation...
        }
    }

    class ConsonantBCD : Consonant
    {
        public ConsonantBCD(char letter) : base(letter) { }
        protected override void FrobConsonant()
        {
            // Special implemenation for B, C, D
        }
    }

    class LetterA : Vowel
    {
        public LetterA() : base('A') { }
        protected override void FrobVowel()
        {
            // Special implementation for A
        }
    }
    class LetterE : Vowel
    {
        public LetterE() : base('E') { }
        protected override void FrobVowel()
        {
            // Special implementation for E
        }
    }

    // use public readonly fields to replicate Enum functionality
    public static readonly Letter A = new LetterA();
    public static readonly Letter B = new ConsonantBCD('B');
    public static readonly Letter C = new ConsonantBCD('C');
    public static readonly Letter D = new ConsonantBCD('D');
    public static readonly Letter E = new LetterE();
    public static readonly Letter F = new Consonant('F');
    // ...   
    public static readonly Letter Z = new Consonant('Z');
}

然后您可以简单地替换上面的原型函数:

void Test(Letter l) {
    l.Frob();
}

上述重构只是一组封闭的值来模拟枚举的一个选项。策略或访客模式也可能有用。

答案 3 :(得分:0)

当我必须了解执行案例Arith时会发生什么情况时,我不想向下滚动整个开关以查明A是否多次出现。

在重构之后,你真的在​​一个更好的可维护程序中结束了吗? KISS解决方案不是仅仅在A标签之后将“所有内容”组合在一起吗?