一个"功能查找表"代替开关

Rol*_*oly 7 c# lambda switch-statement

我最近遇到了一些代码,通过硬编码替换了交换机的使用

Dictionary<string (or whatever we would've been switching on), Func<...>> 
Run Code Online (Sandbox Code Playgroud)

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

例:

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

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();
        ...
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

Fem*_*ref 6

好处:

  1. 您可以在运行时更改"switch"运行时的行为
  2. 它不会混淆使用它的方法
  3. 你可以拥有非文字案例(即case a + b == 3),而且麻烦少得多

缺点:

  1. 您的所有方法都必须具有相同的签名.
  2. 你有一个范围的变化,你不能使用在方法范围内定义的变量,除非你在lambda中捕获它们,如果你在某个点添加一个变量,你将不得不重新定义所有lambdas
  3. 你必须专门处理不存在的索引(类似于defaulta switch)
  4. 如果未处理的异常应该冒泡,则堆栈跟踪会更复杂,从而导致更难调试应用程序

你应该用吗?这真的取决于.你必须在某个地方定义字典,所以代码会在某处混乱.你必须自己决定.如果您需要在运行时切换行为,那么字典解决方案确实很突出,特别是,如果您使用的方法没有副作用(即不需要访问范围变量).


Jon*_*Jon 5

有几个原因:

  1. 因为这样做可以让您选择每个case分支在运行时将执行的操作.否则,你必须编译它.
  2. 而且,您还可以在运行时更改分支.
  3. 正如你所提到的,代码看起来更清晰,特别是对于大量的分支.

为什么这个解决方案对你不对?如果字典在编译时填充,那么你肯定不会失去任何安全性(进入的代理肯定必须编译而没有错误).你确实失去了一点表现,但是:

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