Замените операторы switch для дочернего класса - PullRequest
0 голосов
/ 09 ноября 2018

Существует метод, который принимает 2 параметра:

int selectedClass;
int selectedFunction;

Далее идут 2 оператора switch. Прежде всего, он определяет тип дочернего класса, используя enum:

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?

2-й: в js я бы сделал что-то подобное:

functionsArray[selectedClass][selectedFunction]();

Возможно ли реализовать подобный вид отображения в c #?

Обновление № 1: Я заменил 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]);

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Не могу сказать, что понимаю логику, которая заставляет вас выбирать этот странный дизайн, но я могу придумать, по крайней мере, два пути его улучшения, при условии, что все функции, которые вы вызываете, реализованы в базовом классе (и переопределяют конечно, при необходимости в производных классах).

Оба решения актуальны только в том случае, если все классы предоставляют конструктор без параметров и функции без параметров, а выполнение функций не требует дальнейшей инициализации:

Первое решение потребовало бы, чтобы вы изменили сигнатуру метода и заставили вызывающий метод знать типы классов, чтобы вы не смогли реализовать его, но в нем задействовано гораздо меньше кода.

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

Обратите внимание, что код написан прямо здесь и не проверен, поэтому я мог пропустить одну или две вещи, но это общая идея.

0 голосов
/ 09 ноября 2018

Я сделал некоторые изменения в вашем исходном коде, я изменил входные параметры на строки, предполагая, что вы можете напрямую принимать имена в качестве входных данных. И затем создание экземпляра с использованием первого метода и вызов с использованием второго. Я добавил перегрузку, если вы хотите продолжать использовать Enum.

string selectedClass;
string selectedFunction;

public object GetClassInstanceFromName(string name) 
{
    object type =  Type.GetType($"{this.GetType().Namespace}.{name}";
    return Activator.CreateInstance((Type)type);  
}

public string InVokefunctionByName(object instance,string methName)
{
    return instance.GetType().GetMethod(methName).Invoke(instance, null) as string;     
}

//Overload if you want to continue to use your enum
public object GetClassInstanceFromName(ClassTypes name)
{
    return 
     Activator.CreateInstance(Assembly.GetExecutingAssembly().FullName,
     "class" +name.ToString());
}

private void Test()
{
   object a = GetClassInstanceFromName(selectedClass);
   Console.WriteLine(InVokefunctionByName(a, selectedFunction));
   Console.ReadKey();
}

Также всегда будет рекомендовано перейти на лучший дизайн.

...