何时应该尝试消除 switch 语句?

8
我在正在处理的代码库中遇到了一个switch语句,并尝试着找出如何用更好的方式替换它,因为 switch语句被认为是一种代码异味。然而,我阅读了几篇关于替换 switch 语句的stackoverflow帖子,似乎想不出一种有效的方法来替换这个特定的switch语句。
这让我想知道这个特定的switch语句是否可以接受,以及是否有特定情况下switch语句被认为是合适的。
在我的情况下,我正在处理的代码(自然地略作混淆)如下:
private MyType DoSomething(IDataRecord reader)
{
    var p = new MyType
                {
                   Id = (int)reader[idIndex],
                   Name = (string)reader[nameIndex]
                }

    switch ((string) reader[discountTypeIndex])
    {
        case "A":
            p.DiscountType = DiscountType.Discountable;
            break;
        case "B":
            p.DiscountType = DiscountType.Loss;
            break;
        case "O":
            p.DiscountType = DiscountType.Other;
            break;
    }

    return p;
}

有人能建议一种消除这个开关的方法吗?或者这是使用开关的适当方式吗?如果是,还有其他适当使用开关语句的方法吗?我真的很想知道它们何时适用,以便我不会因为在某些情况下被认为是一种味道而试图消除我遇到的每一个开关声明。

更新: Michael的建议下,我搜索了一下这个逻辑的重复,并发现其他类中的某个人已经创建了逻辑,有效地使整个开关语句变得多余。因此,在这个特定代码的上下文中,开关语句是不必要的。然而,我的问题更多地涉及到开关语句在代码中的适当性以及我们是否应该总是尝试替换它们,无论何时发现它们,所以在这种情况下,我倾向于接受这个开关语句是适当的答案。


1
你能添加一个标签来包含这个代码所写的编程语言吗?虽然代码在做什么方面很清楚,但我认为区分它是有帮助的。显然这不是Java,因为Java中没有“string”类。 - Amir Afghani
@Amir 我已经在标签中确认了代码是C#。我之前没有这样做的原因是因为我不想特别针对C#提出问题,因为我的问题更多地涉及使用switch语句的适当性问题... - mezoid
1
我猜你的经验证实了你对switch语句的怀疑。这个代码块本身还好,但你四处看了看,发现了其他的问题。所以值得进一步调查。 - jrcs3
13个回答

0

我并不完全反对使用switch语句,但在你所提出的情况下,我至少会消除分配DiscountType的重复;我可能会编写一个函数,根据字符串返回DiscountType。该函数可以为每个case简单地设置返回语句,从而消除了需要break的必要性。我发现在switch case之间需要break很容易出错。

private MyType DoSomething(IDataRecord reader)
{
    var p = new MyType
                {
                   Id = (int)reader[idIndex],
                   Name = (string)reader[nameIndex]
                }

    p.DiscountType = FindDiscountType(reader[discountTypeIndex]);

    return p;
}

private DiscountType FindDiscountType (string key) {
    switch ((string) reader[discountTypeIndex])
    {
        case "A":
            return DiscountType.Discountable;
        case "B":
            return DiscountType.Loss;
        case "O":
            return DiscountType.Other;
    }
    // handle the default case as appropriate
}

很快,我会注意到FindDiscountType()实际上属于DiscountType类,并将该函数移动。

0

我认为这取决于您是在许多不同的地方创建MType还是仅在此处创建。如果您在许多地方创建MType并且总是需要切换折扣类型或进行其他检查,那么这可能是一种代码异味。

我建议尝试在程序中的一个单一位置创建MTypes,可能是在MType本身的构造函数中或在某种工厂方法中,但是随机部分的程序分配值可能会导致某人不知道值应该是什么,从而做错事情。

因此,开关很好,但是也许需要将其移动到Type创建部分的更深处。


-1

当你设计一门语言,最终有机会去除整个语言中最丑陋、最不直观、最容易出错的语法时。

那就是你尝试去除 switch 语句的时候。

只是为了明确,我指的是语法。这是从 C/C++ 中采用的东西,本应该改为符合 C# 中更现代的语法。我完全赞同提供 switch 的概念,以便编译器可以优化跳转。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接