我讨厌开关 - 案件。我试图在我的代码中重构一个switch - case,如下所示:
int i = 0;
string str = string.empty;
switch (color)
{
case "red":
i = MyIntArgsFunction(1, 2);
case "blue":
str = MyStringArgsFunction("cat", "dog");
}
private int MyIntArgsFunction(int x, int y)
{
// Implementation
}
private string MyStringArgsFunction(string s, string t)
{
// Implementation
}
我想将2个函数MyIntArgsFunction和MyStringArgsFunction添加到Dictionary>结构,然后根据用户选择的颜色调用适当的函数。但由于参数不同,我无法为Func代表找到合适的签名。
有人可以帮忙吗?
尼哈尔
答案 0 :(得分:1)
它看起来像地狱,但它有效:)
private static void Main(string[] args)
{
var blueHandler = new Action<string, string>((x, y) => { });
var redHandler = new Action<int, int>((x, y) => { Console.WriteLine(x);});
var redStr = "Red";
var blueStr = "Blue";
var colorSelector = new Dictionary<string, Invoker>();
var a = 10;
var b = 20;
colorSelector.Add(redStr, new Invoker(redHandler, a, b));
colorSelector.Add(blueStr, new Invoker(blueHandler, a, b));
colorSelector["Red"].Invoke();
}
public class Invoker
{
private Delegate _handler;
public object[] _param;
public Invoker(Delegate handler, params object[] param)
{
_param = param;
_handler = handler;
}
public void Invoke()
{
_handler.DynamicInvoke(_param);
}
}
答案 1 :(得分:1)
学者会建议&#34;面向对象&#34;方法。 可悲的是,工厂模式需要一个开关盒,你声称你是“讨厌开关盒”#34;虽然说明具体原因也是明智之举。 我想这完全是关于代码清晰度和&#34; Case&#34;插上可用性 这是我避免切换案例的方法。
public abstract class ColorHandler
{
public String str { get; set; }
public int i { get; set; }
public abstract void Handle();
public static ColorHandler ColorHandlerFactory(String color,ref int i, ref string str)
{
ColorHandler handler = Handlers[color];
handler.i = i;
handler.str = str;
handler.Handle();
return handler;
}
public static Dictionary<String, ColorHandler> Handlers = new Dictionary<string, ColorHandler> ()
{
{"red",new RedHandler{myInt1 = 1,myInt2 =2,}},
{"blue",new BlueHandler{MyStr1="str1",MyStr2="str2"} }
};
public Dictionary<String, ColorHandler> InitHandlers(int myNum1,int myNum2,string myStr1,string myStr2){
return new Dictionary<string, ColorHandler>()
{
{"red",new RedHandler{myInt1 = myNum1,myInt2 =myNum2}},
{"blue",new BlueHandler{MyStr1=myStr1,MyStr2=myStr2} }
};
}
}
public class RedHandler : ColorHandler
{
public int myInt1 { get; set; }
public int myInt2 { get; set; }
public override void Handle()
{
this.i = myInt1+myInt2;
// OR alternatively
//this.myInt1 = AnExternalFunction(myInt1, myInt2);
}
}
public class BlueHandler : ColorHandler
{
public String MyStr1 { get; set; }
public String MyStr2 { get; set; }
public override void Handle()
{
this.str = MyStr1 + MyStr2;
// OR alternatively
//this.myInt1 = AnExternalFunction(MyStr1, MyStr2);
}
}
public class Doer
{
public void DoThings()
{
int i = 0;
string str = string.Empty;
var handler =ColorHandler.ColorHandlerFactory("red",ref i,ref str);
handler.InitHandlers(1, 2, "Cat", "Dog");
//Read Results.
var result=handler.i;
}
}
您也可以更改结构以支持批处理。 处理程序是值的默认初始化。 并且InitHandler是一个函数,以防您想要覆盖这些值。
答案 2 :(得分:1)
https://elegantcode.com/2009/01/10/refactoring-a-switch-statement/
作者Chris Brandsma提供了另一种使用基于字典的Factory的有用方法。另请注意,Henrik Gustafsson的评论为工厂实现提供了一种多态方法。
根据亨里克·古斯塔夫森(Henrik Gustafsson):
“通常可以通过小心地使用多态来替换switch语句。如果重构时将switch语句作为方法中的唯一内容,并且switch语句中的每个条目仅调用另一个方法,则状态为每种情况和每种方法通常都可以分为自己的子类。此外,您可以降低循环复杂度
转向
class X {
void m() {
switch(…) {
case A:
m_A();
break;
…
}
}
}
进入
class X {
IM _m;
void m() {
_m.dostuff();
}
}
interface IM {
void dostuff();
}
class MA extends IM {
public void dostuff() {
…
}
}
这当然很冗长,所以我以前发现自己使用了dict技巧的变体。
Misko Hevery在此Google技术讲座中对此有一些有趣的见解:http://www.youtube.com/watch?v=4F72VULWFvc“