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();
...
}
...
}
Function lookup table. A switch statement can run a block of code when a value equals a specific string. But an object with function values can do the same thing. In this benchmark, we test an object with function values.
Thus it appears in JavaScript a switch is the best option for max performance. Switch Some considerations. A lookup table may lead to clearer code, and often lookup time is not an important part of web application performance. But on a low level, the switch appears superior.
Lookup table example. A lookup table of functions lets us encode branches in memory. We put a function object in each index of an array. Array Then: We invoke functions based on an array element access. We simply call the array element as a function.
Lookup-table: Reading the function address is a data-access. With all implications mentioned above. A switch otoh uses a special "table-lookup" instruction which uses code-space data right behind the instruction. So the first entries are possibly already prefetched. Other entries don't break the prefetch.
Advantages:
case a + b == 3
) with much less hassleDisadvantages:
default
in a switch
)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).
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With