Несколько методов, которые должны быть обработаны одинаково - PullRequest
1 голос
/ 10 ноября 2008

В фрагменте C #, который я пишу в данный момент, мне нужно обрабатывать несколько методов с одинаковой сигнатурой одинаково Также может быть больше таких методов в будущем. Вместо того, чтобы повторять одну и ту же логику снова и снова, я придумал следующее:

private delegate bool cleanStep(BuildData bd, out String strFailure);

List<cleanStep> steps = new List<cleanStep>();
steps.Add(WriteReadme);
steps.Add(DeleteFiles);
steps.Add(TFSHelper.DeleteLabel);
steps.Add(TFSHelper.DeleteBuild);

List<cleanStep>.Enumerator enumerator = steps.GetEnumerator();
bool result = true;
while (result && enumerator.MoveNext())
{
   result = enumerator.Current.Invoke(build, out strFailure);
   if (!result)
   {
      logger.Write(LogTypes.Error, strFailure);
   }
}

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

Можете ли вы поблагодарить за лучший способ сделать это?

кстати:

  • это не должно быть транзакционным.
  • strFailure не скрывает исключения, а переносит их полностью при необходимости

Спасибо.

Ответы [ 4 ]

9 голосов
/ 10 ноября 2008

Почему бы не использовать цикл foreach и просто разрывать его? (Я переименовал cleanStep в CleanStep здесь для условности - я предлагаю вам сделать то же самое.)

foreach(CleanStep step in steps)
{
    string failureText;
    if (!step(build, out failureText))
    {
        logger.Write(LogTypes.Error, strFailure);
        break;
    }
}

Обратите внимание, что это также соответствует контракту IEnumerator<T>, где ваш текущий код не соответствует - foreach автоматически вызывает Dispose, а IEnumerator<T> реализует IDisposable. Это не будет проблемой в этом случае, но с блоками итератора, удаление используется для выполнения finally блоков .

2 голосов
/ 10 ноября 2008

Ваше решение является как простым, так и простым для понимания. Не вижу смысла делать это по-другому:)

Единственное, что я бы предложил, это заменить ваш итератор циклом foreach и завершить работу при ошибке.

0 голосов
/ 10 ноября 2008

Я бы возвратил объект Exception вместо строки. Поскольку исключения часто имеют глобальную политику, я бы написал несколько расширений исключений. Теперь вы получаете:

static Exception Run( this IEnumerable<Step> steps) {
   return 
       steps
       .FirstOrDefault( (step) => step( build ) != null )
       .LogIfFailure();  //or .ThrowIfFailure()
}

Расширения:

public static class ExceptionExtensions {
    private static logger = new Logger();

    public static Exception LogIfFailure( this Exception e ) {
        if( e != null )
            logger.Write( e.Message );
        return e;
    }
    public static Exception ShowDialogIfFailure( this Exception e ) {
        if( e != null )
            MessageBox.Show( e.Message );
        return e;
    }
    public static void ThrowIfFailure( this Exception e ) {
        if( e != null )
            Throw( e );
    }
}
0 голосов
/ 10 ноября 2008

Повторно запутан - ну, foreach с перерывом может быть понятнее (плюс он Dispose() перечислитель, который вы не делаете).

На самом деле, «params cleanStep [] target» может помочь:

static bool RunTargets(params cleanStep[] targets)
{
    // detail as per Jon's post
}

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

bool foo = RunTargets(WriteReadme, DeleteFiles,
              TFSHelper.DeleteLabel, TFSHelper.DeleteBuild);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...