如何用 Dictionary<string, Func<>> 替换这个 switch - case?

How to replace this switch - case with a Dictionary<string, Func<>>?

我讨厌开关盒。我正在尝试在我的代码中重构一个 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
}

我想将 MyIntArgsFunction 和 MyStringArgsFunction 这两个函数添加到 Dictionary> 结构中,然后根据用户选择的颜色调用适当的函数。但是由于他们的论据不同,我无法为 Func 委托得出合适的签名。

有人可以帮忙吗?

尼哈尔

看起来很糟糕,但它确实有效:)

    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);
        }
    }

学者会建议 "Object Oriented" 方法。 可悲的是,工厂模式需要一个开关盒,你说你 "Hate switch cases" 尽管最好也说明具体原因。 我想这一切都与代码清晰度和 "Case" 插件可用性有关 这是我避免 switch case 的方法。

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;


    }
}

您也可以更改结构以支持批处理。 Handlers 是值的默认初始化。 如果您想覆盖这些值,InitHandler 是一个函数。

https://elegantcode.com/2009/01/10/refactoring-a-switch-statement/

作者 Chris Brandsma 提供了另一种使用基于字典的工厂的有用方法。另请注意 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