一个“功能查找表”代替开关

时间:2011-03-10 15:27:09

标签: c# lambda switch-statement

我最近遇到了一些代码,通过硬编码

取代了交换机的使用
Dictionary<string (or whatever we would've been switching on), Func<...>> 

并且切换到哪里,它改为dict [“value”]。调用(...)。 代码在某种程度上感觉不对,但与此同时,这些方法确实看起来更清晰一些,特别是在有很多可能的情况下。我不能给出任何关于为什么这是好的或坏的设计的理由,所以我希望有人可以给出一些支持/谴责这种代码的理由。性能有提升吗?失去清晰度?

示例:

public class A {
    ...
    public int SomeMethod(string arg){
        ...
        switch(arg) {
            case "a": do stuff; break;
            case "b": do other stuff; break;
            etc.
        }
        ...
    }
    ...
}

变为

public class A {

    Dictionary<string, Func<int>> funcs = new Dictionary<string, Func<int>> {
        { "a", () => 0; },
        { "b", () => DoOtherStuff(); }
        ... etc.
    };

    public int SomeMethod(string arg){
        ...
        funcs[arg].Invoke();
        ...
    }
    ...
}

6 个答案:

答案 0 :(得分:6)

优点:

  1. 您可以在运行时更改“switch”运行时的行为
  2. 它不会混淆使用它的方法
  3. 你可以轻松获得非文字案例(即case a + b == 3
  4. 缺点:

    1. 您的所有方法都必须具有相同的签名。
    2. 你有一个范围的变化,你不能使用在方法范围内定义的变量,除非你在lambda中捕获它们,如果你在某个时候添加一个变量,你将不得不重新定义所有的lambdas
    3. 您必须专门处理不存在的索引(类似于default中的switch
    4. 如果未处理的异常应该冒出来,堆栈跟踪会更复杂,导致更难调试应用程序
    5. 你应该用吗?这真的取决于。你必须在某个地方定义字典,所以代码会在某处混乱。你必须自己决定。如果你需要在运行时切换行为,字典解决方案确实很突出,特别是,如果你使用的方法没有副作用(即不需要访问范围变量)。

答案 1 :(得分:5)

有几个原因:

  1. 因为这样做可以让您选择每个case分支在运行时运行的内容。否则,你必须编译它。
  2. 此外,您还可以在运行时更改分支的 number
  3. 如你所说,代码看起来更清晰,特别是有大量分支。
  4. 为什么这个解决方案对你有误?如果字典在编译时填充,那么你肯定不会失去任何安全性(进入的代理肯定必须编译而没有错误)。你会失去一点性能,但是:

    1. 在大多数情况下,性能损失不是问题
    2. 你获得的灵活性是巨大的

答案 2 :(得分:2)

Jon有几个很好的答案。还有一些:

  • 每当您需要在交换机中使用新案例时,您必须将其编码到该switch语句中。这需要打开该类(以前工作得很好),添加新代码,并重新编译和重新测试该类以及使用它的任何类。这违反了SOLID开发规则,即开放 - 封闭原则(类应该关闭以进行修改,但是对扩展开放)。相比之下,委托词典允许随意添加,删除和交换代表,而无需更改执行选择的代码。
  • 使用委托词典允许代码在条件中执行,位于任何地方,从而可以从任何地方赋予字典。鉴于这种自由,很容易将设计转变为策略模式,其中每个委托由一个执行该案例逻辑的唯一类提供。这支持封装代码和单一责任原则(一个类应该做一件事,并且应该是唯一负责该事务的类)。

答案 3 :(得分:2)

没有人说过我认为这种方法的最大缺点。

它的可维护性较差。

我说这有两个原因。

  1. 语法上更复杂。
  2. 需要更多理由来理解。
  3. 大多数程序员都知道switch语句的工作原理。许多程序员从未见过函数词典。

    虽然这看起来像是switch语句的一个有趣且新颖的替代方案,并且很可能是解决某些问题的唯一方法,但它要复杂得多。如果您不需要增加灵活性,则不应使用它。

答案 4 :(得分:1)

如果有更多可能的案例,那么最好将Switch语句替换为strategy patternSee this

Applying Strategy Pattern Instead of Using Switch Statements

答案 5 :(得分:0)

将您的A类转换为分部类,并在其中仅使用委托字典的另一个文件中创建第二个分部类。

现在,您可以更改分支数量,并为switch语句添加逻辑,而无需触及其余类的源代码。