Заменить переключатель / чехол с рисунком - PullRequest
8 голосов
/ 02 декабря 2009

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

string option = dropDownList.SelectedValue.ToString();
switch (option.ToUpper())
{
    case "ALPHA":
        // do repeative code method here; only change is a parameter
        break;
    case "BRAVO":
        // do repeative code method here; only change is a parameter
        break;
    case "CHARLIE":
        // do repeative code method here; only change is a parameter
        break;
    case "DELTA":
        // do repeative code method here; only change is a parameter
        break;
    default:
        break;
}

Ответы [ 7 ]

11 голосов
/ 02 декабря 2009

Компиляторы очень хороши в оптимизации конструкций switch / case; CLR, скорее всего, превратит его в справочную таблицу или что-то аналогичное быстрое, поэтому ручная прокрутка вашей собственной версии, такой, как предлагает Хенк Холтерман, - не то, что я бы порекомендовал. CLR может выполнять лучшую работу, чем вы, при выборе лучшего алгоритма.

Если это проблема элегантности или ремонтопригодности, и у вас есть несколько переключателей / вариантов, связанных с одним и тем же классом, выполняющим аналогичные функции, то один из способов улучшить его - это инкапсулировать всю функциональность, связанную с одним «случаем», в его собственный экземпляр класса, например так:

class MyOption
{
    public static readonly MyOption Alpha = new MyOption(1, 10, "Alpha Text");
    public static readonly MyOption Bravo = new MyOption(2, 100, "Bravo Text");
    public static readonly MyOption Charlie = new MyOption(3, 1000, "Charlie Text");
    // ... Other options ...
    public static readonly MyOption Default = new MyOption(0, 0, null);

    public MyOption(int id, int value, string text)
    {
        this.ID = id;
        this.Value = value;
        this.Text = text;
    }

    public int ID { get; private set; }
    public int Value { get; private set; }
    public string Text { get; private set; }
}

Тогда в вашем классе / контроле / странице:

static MyOption GetOption(string optionName)
{
    switch (optionName)
    {
        case "ALPHA":
            return MyOption.Alpha;
        case "BRAVO":
            return MyOption.Bravo;
        case "CHARLIE":
            return MyOption.Charlie;
        // ... Other options ...
        default:
            return MyOption.Default;
    }
}

private MyOption GetOptionFromDropDown()
{
    string optionName = GetOptionNameFromDropDown();
    return GetOption(optionName);
}

private string GetOptionNameFromDropDown()
{
    // ... Your code ...
}

После этого вы можете начать производить события и другие методы:

private void control1_SomeEvent(object sender, EventArgs e)
{
    MyOption option = GetOptionFromDropDown();
    DoSomething(option.ID);
}

private void control2_SomeEvent(object sender, EventArgs e)
{
    MyOption option = GetOptionFromDropDown();
    DoSomethingElse(option.Value);
}

Конечно, это полезный шаблон, если у вас есть несколько этих переключателей / вариантов, которые вы хотите преобразовать в один. Если у вас есть только один переключатель / кейс, вы просто получите код больше , поэтому оставьте его в покое!

Другие возможности улучшения обслуживания включают в себя:

  • Изменение строки на тип Enum (преобразование optionName с использованием Enum.Parse);
  • Перемещение всего материала MyOption / GetOption в его собственный класс (если у вас есть несколько классов / элементов управления / страниц, которые должны работать с одним и тем же набором вариантов выбора);
  • Добавьте делегат метода в класс MyOption, если вам действительно нужно вызывать разные методы для каждого;
  • Пусть ваш DropDownList или другой элемент управления хранят прямую ссылку на экземпляр MyOption, если это возможно.

Вот и все. Его легко написать, легко понять, его легко обслуживать, он сэкономит ваше время, если у вас много конструкций switch / case, и все же позволяет CLR выполнять наилучшую возможную оптимизацию. Единственной стоимостью является небольшой объем памяти, необходимый для хранения этих полей только для чтения.

11 голосов
/ 02 декабря 2009

Вы можете построить таблицу для преобразования string в parameter value.

var lookup = new Dictionary<string, ParaType> ()  
{
    { "ALPHA", a  },
    { "BETA", b },
    ....
};

ParaType para;
if (lookup.TryGetValue(option, out para))   // TryGetValue, on popular request
{       
   // do repeative code method here; with para
}
3 голосов
/ 02 декабря 2009

Я думаю, что я бы переместил оператор switch в отдельную функцию и вернул бы значение параметра для каждого случая:

    private static string GetParameterForAllCases(string option)
    {
        switch (option.ToUpper())
        {
            case "ALPHA":
                return "ALPHA Parameter";
            case "BRAVO":
                return "BRAVO Parameter";
            case "CHARLIE":
                return "CHARLIE Parameter";
            case "DELTA":
                return "DELTA Parameter";
            default:
                return "Default Parameter";
        }
    }

Тогда вы можете просто вызвать метод работы один раз:

        string option = dropDownList.SelectedValue.ToString();

        WorkMethod(GetParameterForAllCases(option);

Если вы не хотите выполнять свой метод работы по причине по умолчанию или если у вас более одного значения параметра, вы можете изменить метод GetParameter для использования выходных параметров:

    private static bool GetParameter(string option, out string value)
    {
        switch (option.ToUpper())
        {
            case "ALPHA":
                value = "ALPHA Parameter";
                return true;
            case "BRAVO":
                value = "BRAVO Parameter";
                return true;
            case "CHARLIE":
                value = "CHARLIE Parameter";
                return true;
            case "DELTA":
                value = "DELTA Parameter";
                return true;
            default:
                value = null;
                return false;
        }
    }

И назовите это так:

        string option = dropDownList.SelectedValue.ToString();

        string value;
        if (GetParameter(option, out value))
            WorkMethod(value);
2 голосов
/ 02 декабря 2009

Ключом к этой проблеме является то, что объекты, хранящиеся в dropDownList, предоставляют параметр (либо напрямую, либо путем индексации в массиве). Тогда оператор switch может быть полностью удален.

Если параметр является свойством объекта, который появляется в раскрывающемся списке, то это даст значение очень эффективно.

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

Любой из этих параметров чище, короче и проще в обслуживании, чем переключение на строку.

1 голос
/ 02 декабря 2009

Возможно преобразование из опции в параметр метода?

Это позволит вам удалить оператор switch и просто передать методу преобразованный параметр.

0 голосов
/ 23 декабря 2016

Хм, я думаю, что очень быстрое решение - использование словаря. Словарь очень быстрая структура, когда вы используете ключ -> значение логики. Итак, в вашем случае вы можете использовать это:

var processingValues = new Dictionary<string, Func<string, string>>() {
     {"ALPHA", yourProcessor.Alpha},
     {"BRAVO", yourProcessor.Bravo},
      ...
}

после этого вы можете создавать свои функции для ALPHA, BRAVA, ...

public class Processor
{
   public string Alpha(string data)
   {
        return "do something";
   }

   public string Bravo(string data)
   {
        return "do something";
   }
...
}

и, наконец, вернуть что-то функцию:

public string SomethingToReturn(string key, string value)
  {
       if (proccessValues.ContainsKey(name))
       {
           return proccessValues[name].Invoke(value);
       }
       return string.Empty;
   }

Надеюсь, это поможет.

0 голосов
/ 02 декабря 2009

Это, вероятно, излишне для того, что вы делаете, но код может закончить чище.

class AlphabetChar
{
    public virtual void DoSomething(){}
}

class Alpha : AlphabetChar {}
class Bravo : AlphabetChar {}
...

class AlphabetCharFactory
{
    public static AlphabetChar GetByName(string name)
    {
         switch (name.ToUpper())
         {
             case "ALPHA":
                   return new Alpha();

             ...

             default:
                  //google for "wiki null object"
                  return new NullAlphabetChar();
         }
    }
}

Тогда код вызова становится ...

string option = dropDownList.SelectedValue.ToString();

AlphabetChar alphabetChar = AlphabetCharFactory.GetByName(option);

alphabetChar.DoSomething();

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...