Могу ли я использовать очень большой блок "switch" для доступа к 400 блокам программного кода?

Я написал приложение на С#, которое в настоящее время включает почти 400 математических функций, каждый со своим собственным идентификатором целого числа. Чтобы получить доступ к функциональному коду, мое приложение в настоящее время передает идентификатор функции в огромный блок "switch", который имеет один блок "case" для каждой функции: всего, почти 400 "case" блоков. Это, похоже, работает плавно и довольно быстро, но есть ли более эффективный способ сопоставления кодовых блоков с идентификаторами функций?

5 ответов

Похоже, вы хотите Dictionary<string, func<******,="" ******="">></string,> или что-то подобное...

// Better, use an *enum* of function IDs...
private static readonly Dictionary<int, func<******,="" ******="">> Functions =
 new Dictionary<int, func<******,="" ******="">>
{
 { 0, Math.Sqrt },
 { 100, x => x * 2 },
 ...
};
</int,></int,>

Обратите внимание, что так же, как это относится к Math.Sqrt, оно также может ссылаться на ваши собственные методы - вам не нужно вставлять всю логику в инициализатор коллекции. Я бы, вероятно, сломал любую функцию, которая была не просто одним выражением в методе.

Затем вы применяете его следующим образом:

public void Apply(int functionId, ****** value)
{
 Func<******, ******=""> function;
 if (!Functions.TryGetValue(functionId, out function))
 {
 // Throw an exception or whatever
 }
 return function(value);
}
</******,>

Обратите внимание, что я использовал словарь здесь для общего назначения; если идентификаторы функций равны 0... n, вы можете использовать массив.

Как отмечено в комментарии в начале, было бы более удобно использовать перечисление идентификаторов функций, а не только целых чисел.


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

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

Это также означало бы, что добавление функций в будущем может быть более гибким, поскольку у вас будет возможность добавлять функции из внешних источников без необходимости перекомпиляции.

Другим преимуществом такого подхода может быть то, что, поскольку все функции будут реализовывать интерфейс, вы могли бы сканировать свои сборки для этих реализаций во время загрузки и, таким образом, автоматически добавлять новые функции в список доступных функций без каких-либо дополнительных усилий.


Насколько я знаю, операторы switch, содержащие более нескольких элементов, уже оптимизированы компилятором для внутреннего использования таблицы поиска, поэтому прирост производительности путем переключения на, например, Dictionary должен быть минимальным. Как всегда, вы должны измерить оба подхода, чтобы принять решение.


Похоже, вы пишете свой код наподобие этого (psudocode):

function doMath(a,b, functionID) {

 switch (functionID) {
 case 1: 
 // addition function
 return a + b;
 break;
 case 2:
 // subtraction function
 return a - b;
 break;
 }

}

когда вы хотите написать его вот так:

function add(a,b) {
 return a + b;
}

function subtract(a,b) {
 return a - b;
}

или я не понимаю ваши требования?


Кроме того, потенциал для использования Dictionary, этот парень отмечает, что наличие шести или более строковых случаев и случай по умолчанию привели к созданию компилятора, создающего Dictionary. Итак, почему бы просто не пропустить это преобразование во время компиляции?

licensed under cc by-sa 3.0 with attribution.