【问题标题】:When to use FOR-CASE (Foreach/switch in C#)?何时使用 FOR-CASE(C# 中的 Foreach/switch)?
【发布时间】:2008-12-02 20:55:54
【问题描述】:

在我正在处理的项目中,我发现了与 FOR-CASE 结构类似的 C# 结构:

foreach (string param in params.Split(';'))
{
    string[] parts = param.Split('=');
    string key = parts[0].Trim().ToLower();
    string value = parts[1].Trim();
    switch (key)
    {
        case "param1": this.param1 = value; break;
        case "param2": this.param2 = value; break;
        case "param3": this.param3 = value; break;
        case "param4": this.param4 = value; break;
        default: break;
    }
}

(更改了变量名称以保护有罪者。)

您将如何实现此代码?

【问题讨论】:

  • 我不确定我是否明白您所说的“您将如何实现此代码?”是什么意思
  • 不,这不是同一个范例——它很丑,需要改进,但它(相当)没有那么糟糕。至少这些案例中的一些可能不存在,或者无关紧要的案例会存在。
  • 哈哈。我很混乱。我不知道文章中的代码试图完成什么。您在问题中的内容看起来对于解析某种参数很有用,但链接文章中的内容看起来完全没有意义。
  • 这并没有wtf文章中的代码那么糟糕,因为在你的例子中,你不知道顺序参数会进来。对于快速和肮脏的命令或属性是可以的解析,尽管有更漂亮和更灵活的方法。
  • 我认为 TDWTF 中代码背后的想法很好,因为它为程序员留下了执行错误检查的空间。但是,它可以使用一些代码重构来提高优雅度。

标签: c# foreach switch-statement


【解决方案1】:

我认为您问题中的代码与您链接到的代码不同......

如果我编写了一个命令行工具,问题中的代码看起来像是我可能会做的事情。

我没有看到问题中的代码有什么问题吗?

另一种方法是使用反射来填充参数值变量。我有时也这样做。

顺便说一句:我曾经用一种脚本语言编写了一个程序,该程序将 switch 作为唯一的流控制机制,并且没有 gosub/return。我程序中的代码的结构有点像你链接的那个。一种指令指针变量的大规模开关,在每种情况下都会重新分配,并且在开关周围几乎是无限循环。它完成了工作。

【讨论】:

  • 如果我这样做,我可能会根据输入字符串创建一个字典,并从字典中分配参数: param1 = input_map["param1"];当然,您必须捕获 KeyNotFoundException,但恕我直言,代码看起来更干净。
  • " 我曾经用一种脚本语言编写了一个程序,该程序将 switch 作为唯一的流控制机制......" 听起来像一个'C' Windows 消息泵。
  • @Harper - 我尽量不使用可以使用类的字典。我在 switch 中的默认设置可以告诉用户密钥是未知的,我可以使用反射解决方案。此外,您必须用来从 Dictionary 中获取的 " 会使编译器蒙蔽。
  • @John - 该语言被称为“BRS MNS”。这是一个文本数据库的菜单系统。我在 20 岁时做到了。我仍然为此感到自豪。
【解决方案2】:

我看到您的类中已经有多个用于保存变量的字段。在这种情况下,你正在做的很好。

否则,您可以使用 1 个 HashTable(也许添加 C# indexor 作为一个转折点)来保存所有这些,并且您的循环将像这样结束:

foreach (string param in params.Split(';'))
{
    string[] parts = param.Split('=');
    string key = parts[0].Trim().ToLower();
    string value = parts[1].Trim();
    MyHashTable[key] = value;
}

这种方法的问题是您应该只有一种类型的值。例如,如果您的参数列表可以同时包含 string 和 int 类型,它会使代码更加混乱,尤其是您需要执行错误检查和验证等。

我个人会坚持你已经拥有的。

【讨论】:

    【解决方案3】:

    您可以为此使用反射:

    Type t = this.GetType();
    foreach (string param in params.Split(';'))
    {    
        string[] parts = param.Split('=');    
        string key = parts[0].Trim().ToLower();    
        string value = parts[1].Trim();    
    
        t.GetProperty(key).SetValue(this, value, null);
    }
    

    【讨论】:

    • 我已经这样做了几次,但我总是使用指定的类,或者用自定义属性标记可用的属性。
    • 这里也一样。我更喜欢使用属性和任意键名或枚举,因此我可以随意重命名我的属性。但是,我认为这个示例最适合提供的代码示例。
    • 如果传递的值之一不是有效的属性名称会怎样? OP 的代码安全地忽略了错误的参数...
    • @Coderer - 您可能希望在尝试设置之前添加错误处理或检查该属性是否存在。我的示例只是为了启动 OP,而不是完整的生产代码。
    【解决方案4】:

    就其价值而言,WTF 文章是 WTF,因为它的外部循环完全没有用,正如文章中所指出的那样 - 直接设置索引变量比循环和测试更简单,更直接它。

    【讨论】:

      【解决方案5】:

      我也不确定我是否理解,但听起来你让自己复杂化了。不要重新发明轮子,尽可能多地使用 BCL 类,这些类被证明可以有效地工作并为您节省大量时间。听起来您可以使用某种 Dictionary 以及 Guge 建议的 Reflection 来实现它。

      【讨论】:

      • 这样我也觉得很自然。
      【解决方案6】:

      我实际上认为 OP 的代码很好。它并不完美——可能有更简单或更简洁的方法来做到这一点,但它有效地允许成员/属性名称和输入参数名称之间的可读映射。它使您的属性成为强类型(与 hashmap/dictionary 解决方案不同,除非您的类的所有属性只有一种类型......)并为您提供一个相当明显的位置来修复或添加映射。

      【讨论】:

        【解决方案7】:

        或正则表达式:

        string parms = "param1=1;param2=2;param3=3";
        string[] parmArr = parms.Split(';');        
        
        string parm1 = Regex.Replace(parmArr[0], "param1=", "");
        string parm2 = Regex.Replace(parmArr[1], "param2=", "");
        string parm3 = Regex.Replace(parmArr[2], "param3=", "");
        

        【讨论】:

        • 仅当参数按该顺序时才有效。 "param2=2;param3=3;param1=1" 将失败,而 OP 将处理它。并且“正则表达式”部分是多余的,因为您只是在进行直接字符串替换。
        猜你喜欢
        • 2014-06-13
        • 1970-01-01
        • 1970-01-01
        • 2020-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-26
        • 1970-01-01
        相关资源
        最近更新 更多