“函数查找表”代替开关
我最近遇到了一些代码,通过硬编码 a 来替换开关的使用
Dictionary<string (or whatever we would've been switching on), Func<...>>
,并且无论开关在哪里,它都会改为 dict["value"].Invoke(...)。 代码在某种程度上感觉是错误的,但同时,这些方法看起来确实有点干净,特别是当有很多可能的情况时。我无法给出任何理由来解释为什么这是好的或坏的设计,所以我希望有人能给出一些理由来支持/谴责这种代码。性能上有提升吗?失去清晰度?
示例:
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();
...
}
...
}
I came across some code recently that replaces the use of switches by hard-coding a
Dictionary<string (or whatever we would've been switching on), Func<...>>
and where ever the switch would've been, it instead does dict["value"].Invoke(...).
The code feels wrong in some way, but at the same time, the methods do look a bit cleaner, especially when there's many possible cases. I can't give any rationale as to why this is good or bad design so I was hoping someone could give some reasons to support/condemn this kind of code. Is there a gain in performance? Loss of clarity?
Example:
public class A {
...
public int SomeMethod(string arg){
...
switch(arg) {
case "a": do stuff; break;
case "b": do other stuff; break;
etc.
}
...
}
...
}
becomes
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();
...
}
...
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
优点:
case a + b == 3
)麻烦少得多缺点:
switch
中的default
),你应该使用它吗?这确实取决于。您必须在某个地方定义字典,因此代码会在某个地方被它弄乱。你必须自己决定。如果您需要在运行时切换行为,那么字典解决方案确实很突出,特别是如果您使用的方法没有副作用(即不需要访问作用域变量)。
Advantages:
case a + b == 3
) with much less hassleDisadvantages:
default
in aswitch
)Should you use it? It really depends. You'll have to define the dictionary at some place, so the code will be cluttered by it somewhere. You'll have to decide for yourself. If you need to switch behaviour at runtime, the dictionary solution really sticks out, especially, if the methods you use don't have sideeffects (ie. don't need access to scoped variables).
有几个原因:
case
分支在运行时执行的操作。否则,您必须编译它。为什么您觉得这个解决方案不对?如果字典是在编译时填充的,那么您当然不会失去任何安全性(进入的委托肯定必须编译而不会出现错误)。您确实会损失一点性能,但是:
For several reasons:
case
branch will do at runtime. Otherwise, you have to compile it in.Why does this solution feel wrong to you? If the dictionary is populated at compile time, then you certainly don't lose any safety (the delegates that go in certainly have to compile without error). You do lose a little performance, but:
乔恩有几个很好的答案。以下是更多内容:
Jon has a couple good answers. Here are some more:
如果可能的情况较多,那么最好将
Switch
语句替换为策略模式
,查看此内容。应用策略模式而不是使用 Switch 语句
If there are more number of possible cases then it is good idea to replace
Switch
Statement with thestrategy pattern
, See this.Applying Strategy Pattern Instead of Using Switch Statements
目前还没有人对我认为这种方法的最大缺点发表任何言论。
它的可维护性较差。
我这么说有两个原因。
大多数程序员都知道 switch 语句是如何工作的。许多程序员从未见过函数字典。
虽然这看起来像是 switch 语句的一个有趣且新颖的替代方案,并且很可能是解决某些问题的唯一方法,但它要复杂得多。如果您不需要增加灵活性,则不应使用它。
No one has said anything yet about what I believe to be the single biggest drawback of this approach.
It's less maintainable.
I say this for two reasons.
Most programmers know how a switch statement works. Many programmers have never seen a Dictionary of functions.
While this might seem like an interesting and novel alternative to the switch statement and may very well be the only way to solve some problems, it is considerably more complex. If you don't need the added flexibility you shouldn't use it.
将您的
A
类转换为分部类,并在另一个文件中创建第二个分部类,其中仅包含委托字典。现在,您可以更改分支数量,并向 switch 语句添加逻辑,而无需触及类其余部分的源代码。
Convert your
A
class to a partial class, and create a second partial class in another file with just the delegate dictionary in it.Now you can change the number of branches, and add logic to your switch statement without touching the source for the rest of your class.
(无论语言如何)从性能角度来看,如果此类代码存在于关键部分,那么使用函数查找表几乎肯定会更好。
原因是您消除了多个运行时条件(切换时间越长,比较就越多),有利于简单的数组索引和函数调用。
唯一的性能缺点是您引入了函数调用的成本。这通常比所述条件更好。描述差异; YMMV。
(Regardless of language) Performance-wise, where such code exists in a critical section, you are almost certainly better off with a function look-up table.
The reason is that you eliminate multiple runtime conditionals (the longer your switch, the more comparisons there will be) in favour of simple array indexing and function call.
The only performance downside is you've introduced the cost of a function call. This will typically be preferable to said conditionals. Profile the difference; YMMV.