C# 什么时候应该消除switch语句?

C# 什么时候应该消除switch语句?,c#,refactoring,switch-statement,C#,Refactoring,Switch Statement,在我正在处理的代码库中,我遇到了一个switch语句,我正试图找出如何用更好的语句替换它。然而,在阅读了stackoverflow上关于我的帖子之后,我似乎想不出一个有效的方法来取代这个特殊的switch语句 这让我想知道这个特殊的switch语句是否正确,以及是否有特殊情况下switch语句被认为是合适的 在我的例子中,我正在努力处理的代码(自然有些模糊)是这样的: private MyType DoSomething(IDataRecord reader) { var p = new

在我正在处理的代码库中,我遇到了一个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;
}
有人能建议一种消除这种切换的方法吗?或者这是开关的适当使用?如果是,switch语句还有其他合适的用途吗?我真的很想知道它们在哪里合适,这样我就不会浪费太多时间试图消除我遇到的每一个switch语句,因为它们在某些情况下被认为是一种气味


更新:在的建议下,我搜索了一下这个逻辑的副本,发现有人在另一个类中创建了逻辑,这使得整个switch语句变得多余。因此,在这个特定代码位的上下文中,switch语句是不必要的。然而,我的问题更多的是关于switch语句在代码中的适当性,以及我们是否应该在发现它们时总是尝试替换它们,因此在这种情况下,我倾向于接受这个switch语句是适当的答案。

这是switch语句的适当用法,因为它使选择可读,而且很容易加上或减去一个


如果,我不会使用
if
开关
更清晰。
开关
告诉我,您始终在比较相同的内容

为了吓唬人,这比你的代码还不清楚:

if (string) reader[discountTypeIndex]) == "A")
   p.DiscountType = DiscountType.Discountable;
else if (string) reader[discountTypeIndex]) == "B")
   p.DiscountType = DiscountType.Loss;
else if (string) reader[discountTypeIndex]) == "O")
   p.DiscountType = DiscountType.Other;

这个
开关可能没问题,您可能想看看@Talljoe建议。

这个开关语句很好。你们没有其他的虫子要处理吗?哈哈


然而,我注意到一件事。。。您不应该在IReader[]对象索引器上使用索引序号。。。。如果列顺序发生变化怎么办?尝试使用字段名,即读卡器[“id”]和读卡器[“name”]

折扣类型开关是否位于代码中?添加新的折扣类型是否需要您修改几个这样的开关?如果是这样的话,你应该考虑将开关分解。如果不是,在这里使用开关应该是安全的

如果在您的程序中存在大量特定于折扣的行为,您可能希望重构如下:

p.Discount = DiscountFactory.Create(reader[discountTypeIndex]);
然后折扣对象包含与计算折扣相关的所有属性和方法。

Switch语句(尤其是长语句)被认为是不好的,不是因为它们是Switch语句,而是因为它们的存在表明需要重构

switch语句的问题在于它们会在代码中产生分歧(就像if语句一样)。每个分支必须单独测试,每个分支内的每个分支和。。。好吧,你明白了

尽管如此,以下文章提供了一些使用switch语句的良好实践:

对于您的代码,上面链接中的文章建议,如果您正在执行从一个枚举到另一个枚举的这种类型的转换,您应该将开关放在它自己的方法中,并使用return语句而不是break语句。我以前做过,代码看起来更干净:

private DiscountType GetDiscountType(string discount)
{
    switch (discount)
    {
        case "A": return DiscountType.Discountable;
        case "B": return DiscountType.Loss;
        case "O": return DiscountType.Other;
    }
}

我认为为了改变代码而改变代码并不是最好地利用时间。更改代码以使其[更可读、更快、更高效等]是有意义的。不要仅仅因为有人说你在做“难闻”的事就改变它


-里克

在我看来,气味不在于开关语句,而在于它们里面的东西。在我看来,这个switch语句还可以,直到它开始添加更多的案例。那么创建一个查找表可能是值得的:

private static Dictionary<string, DiscountType> DiscountTypeLookup = 
  new Dictionary<string, DiscountType>(StringComparer.Ordinal)
    {
      {"A", DiscountType.Discountable},
      {"B", DiscountType.Loss},
      {"O", DiscountType.Other},
    };
私有静态字典折扣类型查找=
新字典(StringComparer.Ordinal)
{
{“A”,DiscountType.Discountable},
{“B”,折扣类型.损失},
{“O”,DiscountType.Other},
};
根据您的观点,这可能或多或少具有可读性


如果你的案件内容超过一两行,事情就会开始变得难闻

我认为这取决于您是创建MType添加许多不同的位置还是仅在此处添加。如果您在许多地方创建MType时总是需要切换为dicsount类型,并进行一些其他检查,那么这可能是一种代码味道

我会尝试在程序中的一个点上创建MType,可能是在MType本身的构造函数中,也可能是在某种工厂方法中,但是让程序的随机部分赋值可能会导致某些人不知道值应该是什么样子,并做了一些错误的事情


因此,开关很好,但可能需要在您的类型的创建部分内移动更多开关

是的,这看起来是开关语句的正确用法

不过,我还有一个问题要问你

为什么不包括默认标签?在默认标签中抛出异常将确保在添加新discountTypeIndex并忘记修改代码时程序将正常失败

此外,如果要将字符串值映射到枚举,可以使用属性和反射

比如:

public enum DiscountType
{
    None,

    [Description("A")]
    Discountable,

    [Description("B")]
    Loss,

    [Description("O")]
    Other
}

public GetDiscountType(string discountTypeIndex)
{
    foreach(DiscountType type in Enum.GetValues(typeof(DiscountType))
    {
        //Implementing GetDescription should be easy. Search on Google.
        if(string.compare(discountTypeIndex, GetDescription(type))==0)
            return type;
    }

    throw new ArgumentException("DiscountTypeIndex " + discountTypeIndex + " is not valid.");
}

当您设计一种语言,并最终有机会删除整个语言中最丑陋、最不直观、最容易出错的语法时

这就是您尝试删除switch语句的时候

我只是想说清楚,我指的是语法。这是取自C/C++的内容,应该对其进行更改,以符合C#中更现代的语法。我
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
}
public enum DiscountType : int
{
    Unknown = 0,
    Discountable = 1,
    Loss = 2,
    Other = 3
}
p.DiscountType = Enum.Parse(typeof(DiscountType), 
    (string)reader[discountTypeIndex]));