首页 > 解决方案 > 替换子类类型的 switch 语句

问题描述

有一个方法接受 2 个参数:

int selectedClass;
int selectedFunction;

接下来,有 2 个 switch 语句。首先,它使用枚举确定子类类型:

ParentClass p;
switch(selectedClass){
    case (int)ClassTypes.A:
        p = new classA();
        break;
    case (int)ClassTypes.B:
        p = new classB();
        break;
    case (int)ClassTypes.C:
        p = new classC();
        break;
}

它继续进行了大约 50 条语句。此外,还有另一个决定函数的 switch 语句:

string result;
switch(selectedFunction){
    case (int)FunctionTypes.Func1:
        result = p.function1();
        break;
    case (int)FunctionTypes.Func2:
        result = p.function2();
        break;
    case (int)FunctionTypes.Func3:
        result = p.function3();
        break;
}

我确实使用了搜索,有很多改进第二个 switch 语句的例子,但不是第一个。第一个问题是:我们如何在没有 switch 语句的情况下确定子类和函数?

第二:在js中我会做这样的事情:

functionsArray[selectedClass][selectedFunction]();

是否可以在 c# 中实现类似的映射?

更新#1:我用以下代码替换了第一个开关:

public static Dictionary<ClassTypes, Type> typeDict = new Dictionary<ClassTypes, Type>()
{
    { ClassTypes.A   , typeof(classA) },
    { ClassTypes.B   , typeof(classB) },
    { ClassTypes.C   , typeof(classC) }
};

ParentClass p = (ParentClass)Activator.CreateInstance(typeDict[selectedClass]);

标签: c#.netswitch-statementmapping

解决方案


我不能说我理解导致你选择这种奇怪设计的逻辑,但我可以想到至少两种改进它的方法,前提是你调用的所有函数都在基类中实现(并在需要时重写当然是派生类)。

这两种解决方案仅在所有类都提供无参数构造函数和无参数函数并且执行这些函数不需要进一步初始化的情况下才相关:

第一个解决方案需要您更改方法签名,并强制调用方法知道类的类型,因此您可能无法实现它,但它涉及的代码要少得多。

ExecuteMethod<TClass>(Func<TClass, string> func) where T: BaseClass, new()
(
    return func(new T());
)

你这样称呼它:

var result = ExecuteMethod<ClassA>(a => a.Function1);

第二种解决方案
这可能更适合您的需求:您需要创建两个字典并填充它们,如下所示:

private Dictionary<int, Func<ParentClass>> constructors = new Dictionary<int, Func<ParentClass>>()
{
    {1, () => new ClassA()},
    {2, () => new ClassB()}
    // more of the same
};

private Dictionary<int, Func<ParentClass, string>> methods = new Dictionary<int, Func<ParentClass, string>>()
{
    {1, i => i.function1},
    {2, i => i.function2}
    // more of the same
};

然后您的方法仍然可以采用两个整数并返回一个字符串:

string DoSomething(int classType, int function)
{
    var instance = constructors[classType].Invoke();
    return methods[function].Invoke(instance);
}

请注意,代码是直接写在这里的,没有经过测试,所以我可能漏掉了一两件事,但这是大体思路。


推荐阅读