Как выполнить два фрагмента кода в разной последовательности? - PullRequest
2 голосов
/ 25 ноября 2011

У меня есть код со следующей логикой: если какой-то логический флаг имеет значение true, один из двух фрагментов кода должен выполняться первым и наоборот. Но оба они должны быть выполнены всегда. К сожалению, C # не имеет инструкций по семантике для этого, например:

if (condition) first
{
//Some code to execute first if condition is true
}
second
{
//Some code to execute first if condition is false
}

Теперь я сделаю так:

if (condition)
{
//Code 1
//Code 2
}
else
{
//Code 2
//Code 1
}

Таких необходимости много, и это создает много дублирования кода. Может быть, есть лучшее решение?

Ответы [ 7 ]

3 голосов
/ 25 ноября 2011

Поместите код в отдельные методы

public void MyMethod1
{
   //first code goes here
}

public void MyMethod2
{
   //second code goes here
}


if (condition)
{
  MyMethod1();
  MyMethod2();
}
else
{
  MyMethod2();
  MyMethod1();
}

Таким образом, вам не нужно дублировать код внутри методов.

2 голосов
/ 25 ноября 2011

Вы можете написать такой метод, как:

public static void DoBoth(Action first, Action second, bool keepOrder)
    {
        if (keepOrder)
        {
            first();
            second();
        }
        else
        {
            second();
            first();
        }
    }
1 голос
/ 25 ноября 2011

Вы должны стараться избегать дублирования кода, когда можете. Основная идея в вашем случае состоит в том, чтобы попытаться извлечь все, что кажется выполненным более одного раза, и попытаться «положить» его где-то, где вам нужно написать это только один раз.

В вашем случае, скажем, у нас есть следующее:

 public void Bar()
 {
     ...
     if (condition)
     {
         //code for action 1
         //code for action 2
     }
     else
     {
         //code for action 2
         //code for action 1
     }
     ...
 }

 public void Foo()
 {
     ...
     if (condition)
     {
         //code for action 1
         //code for action 2
     }
     else
     {
         //code for action 2
         //code for action 1
     }
     ...
 }

Теперь мы, очевидно, можем видеть, что у вас есть некоторое дублирование кода здесь. Мы можем улучшить это следующим образом:

 public void Bar()
 {
     ...
     if (condition)
     {
         Action1();
         Action2();
     }
     else
     {
         Action2();
         Action1();
     }
     ...
 }

 public void Foo()
 {
     ...
     if (condition)
     {
         Action1();
         Action2();
     }
     else
     {
         Action2();
         Action1();
     }
     ...
 }

 private void Action1()
 {
     //code for action 1
 }

 private void Action2()
 {
     //code for action 1
 }

Это выглядит намного лучше (особенно если код Action1 и код Action2 длинны). Теперь нам удалось написать код для Action1 и Action2 только один раз, независимо от того, сколько методов стиля Foo или Bar есть в нашем коде. Но мы все еще можем сделать больше. Вы можете видеть, что мы все еще дублируем некоторый неприятный подробный код. Таким образом, мы можем сделать еще один шаг и сделать следующее:

 public void Bar()
 {
     ...
     DoAction(condition);
     ...
 }

 public void Foo()
 {
     ...
     DoAction(condition);
     ...
 }

 private void Action1()
 {
     //code for action 1
 }

 private void Action2()
 {
     //code for action 1
 }

 private void DoAction(bool condition)
 {
      if (condition)
      {
           Action1();
           Action2();
      }
      else
      {
           Action2();
           Action1();
      }
 }

Теперь это ИМХО выглядит намного лучше. Мало того, что нам удалось написать Action1 и Action2 определенный код только один раз, мы теперь также смогли написать эту логику упорядочивания методов только один раз.

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

Кроме того, представьте, что порядок заказов зависит от бизнес-правил, и ваш клиент (о мой сюрприз!) Решает их изменить. В последней версии вам нужно всего лишь изменить код в одном месте.

Правило большого пальца. Избегайте дублирования кода, когда это возможно, это резко сократит код, который вы набираете, и головную боль, которую вы или какая-то бедная душа испытаете в ближайшем будущем.

1 голос
/ 25 ноября 2011

Я согласен с комментарием @Steven Jeuris о том, что предпочитаю знать основную причину, поскольку это может указывать на проектное решение, требующее улучшения. Однако, если вам нужно придерживаться того, что у вас есть, я бы предложил очередь делегатов, поскольку вы подразумеваете, что ваш пример очень прост по сравнению с фактической кодовой базой. Если нет, то один из других ответов был бы в порядке, но приведенный ниже, возможно, более удобен в обслуживании по мере роста сложности.

Примечание: я привожу это в качестве примера - параметры для GetQueue и логика внутри него могут быть улучшены в зависимости от ваших реальных условий.

public Queue<Action> GetQueue(bool condition)
{
    var toReturn = new Queue<Action>();
    if (condition)
    {
        toReturn.Enqueue(DoWork1);
        toReturn.Enqueue(DoWork2);
    }
    else
    {
        toReturn.Enqueue(DoWork2);
        toReturn.Enqueue(DoWork1);
    }
    return toReturn;
}

public void MyExecutingMethod()
{
    foreach (var action in GetQueue(true))
    {
        action();
    }
}

public void DoWork1()
{

}

public void DoWork2()
{

}
1 голос
/ 25 ноября 2011

Я бы создал два метода с «Кодом 1» и «Кодом 2», а затем продолжил как ваш второй вариант:

if (condition)
{
Code1(); Code2();
}
else
{
Code 2(); Code1();
}

Вы также можете отшлифовать это с помощью действий или делегатов, в зависимости отчто такое «код 1» и «код 2».

0 голосов
/ 25 ноября 2011

Я предлагаю другое предложение (в псевдокоде).

РЕДАКТИРОВАТЬ: Это действительно зависит от вашей ситуации, какой из различных подходов вы хотите использовать. Преимуществами этого подхода являются простота и гибкость. Под гибкостью я подразумеваю, что решение о заказе теперь отделено от кода, так что вы можете легко делать такие вещи, как добавление нового заказа или позволить указывать порядок в некоторых других средствах (например, что, если вы теперь хотите связать различные заказы с разные пользователи на основе файла свойств)?

if(condition)
       runOrder = [ "one", "two" ];
else
       runOrder = [ "two", "one" ];

for(x=0; x<runOrder.length; x++)
{
     codeToRun = runOrder[x];
     switch(codeToRun)
     {
              Case "one": Code1();
              Case "two": Code2();
     }
} 
0 голосов
/ 25 ноября 2011

Я рискну предположить, что code1 либо не имеет побочных эффектов, либо воздействует на переменные-члены классов, и в этом случае их можно заключить в методы, которые возвращают void. Затем вы можете сделать что-то вроде следующего:

...
    if (condition)
        DoWork(() => Code1(), () => Code2());
    else
    {
        DoWork(() => Code2(), () => Code1());
    }
...

private void Code1()
{
    // Code 1
}

private void Code2()
{
    // code 2
}

private void DoWork(Action action1, Action action2)
{
    action1();
    action2();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...