C # enums и booleans - ищем более элегантный способ - PullRequest
3 голосов
/ 22 января 2009

У меня есть класс, который имеет свойство enum и логическое свойство, основываясь на том, что он вызывает определенный метод с конкретными параметрами. Я использую оператор switch для перечисления и if для логического значения в каждом случае переключателя. Это длинный список, и я не считаю его самым элегантным решением. У кого-нибудь есть более элегантный или простой способ реализовать это?

            switch (ReadDecision)
            {
                case ReadDecisions.ReadNext:
                    {
                        if (UseTimeout)
                        {
                            Message = queue.Receive(Timeout);
                        }
                        else
                        {
                            Message = queue.Receive();
                        }
                        break;
                    }
                case ReadDecisions.PeekNext:
                    {
                        if (UseTimeout)
                        {
                            Message = queue.Peek(Timeout);
                        }
                        else
                        {
                            Message = queue.Peek();
                        }
                        break;
                    }
                case ReadDecisions.ReadMessageId:
                    {
                        if (UseTimeout)
                        {
                            Message = queue.ReceiveById(Id, Timeout);
                        }
                        else
                        {
                            Message = queue.ReceiveById(Id);
                        }
                        break;
                    }
                case ReadDecisions.PeekMessageId:
                    {
                        if (UseTimeout)
                        {
                            Message = queue.PeekById(Id, Timeout);
                        }
                        else
                        {
                            Message = queue.PeekById(Id);
                        }
                        break;
                    }
                case ReadDecisions.ReadCorrelationId:
                    {
                        if (UseTimeout)
                        {
                            Message = queue.ReceiveByCorrelationId(Id, Timeout);
                        }
                        else
                        {
                            Message = queue.ReceiveByCorrelationId(Id);
                        }
                        break;
                    }
                case ReadDecisions.PeekCorrelationId:
                    {
                        if (UseTimeout)
                        {
                            Message = queue.PeekByCorrelationId(Id, Timeout);
                        }
                        else
                        {
                            Message = queue.PeekByCorrelationId(Id);
                        }
                        break;
                    }
                default:
                    {
                        throw new Exception("Unknown ReadDecisions provided");
                    }
            }

Ответы [ 11 ]

5 голосов
/ 22 января 2009

В зависимости от того, что такое queue, вы можете изменить подпись Peek() и Peek(bool) на Peek(bool?)? (Остальные методы также должны следовать.)

Таким образом, вместо:

if (UseTimeout)
{
    Message = queue.Peek(Timeout);
}
else
{
    Message = queue.Peek();
}

Вы можете иметь:

Message = queue.Peek(UseTimeout ? Timeout : null);

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

if(UseTimeout)
    Message = queue.PerformAction(ReadDecision, Timeout)
else
    Message = queue.PerformAction(ReadDecision)
3 голосов
/ 22 января 2009

Часто используемое соглашение заключается в том, что нулевое время ожидания означает отсутствие времени ожидания. Может быть, вы могли бы удалить UseTimeout (свойство?) И использовать вместо этого значение ноль. Это устранит некоторые вещи.

3 голосов
/ 22 января 2009

Шаблон, который я вижу здесь, это множество пар методов с именами foo (ID) и foo (ID, timeout). В вашей ситуации я бы:

  • Создайте метод третьего типа foo(ID, timeout, bool useTimeout), объединив тела foo(ID) и foo(ID, timeout).
  • Измените foo(ID) для вызова foo(ID, null, false) и foo(ID, timeout) для вызова foo(ID, timeout, true)
  • Измените свой оператор switch, чтобы он всегда вызывал foo(ID, Timeout, UseTimeout).
  • Повторите вышеуказанное для каждой подходящей пары методов.

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

3 голосов
/ 22 января 2009

Замените перечисление классами:
http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html

Вы также можете взглянуть на шаблон Стратегии:
http://www.dofactory.com/Patterns/PatternStrategy.aspx

2 голосов
/ 22 января 2009

Мне нравится, что предложение Скотта о нулевом тайм-ауте означает отсутствие тайм-аута. Это приведет к следующему коду, который будет более читабельным, но не включает создание дополнительных классов. OTOH, если у вас есть такой же оператор switch где-нибудь еще в вашем коде, я бы пошел на рефакторинг enum-> classes.

switch (ReadDecision)
 {
  case ReadDecisions.ReadNext:
   {
    Message = queue.Receive(Timeout);
    break;
   }
  case ReadDecisions.PeekNext:
   {
    Message = queue.Peek(Timeout);
    break;
   }
  case ReadDecisions.ReadMessageId:
   {
    Message = queue.ReceiveById(Id, Timeout);
    break;
   }
  case ReadDecisions.PeekMessageId:
   {
    Message = queue.PeekById(Id, Timeout);
    break;
   }
  case ReadDecisions.ReadCorrelationId:
   {
    Message = queue.ReceiveByCorrelationId(Id, Timeout);
    break;
   }
  case ReadDecisions.PeekCorrelationId:
   {
    Message = queue.PeekByCorrelationId(Id, Timeout);
    break;
   }
  default:
   {
    throw new Exception("Unknown ReadDecisions provided");
   }
  }
1 голос
/ 22 января 2009

Я бы использовал словарь, содержащий перечисление в качестве ключа и действия, которые вы делаете в качестве значения:

Dictionary<ReadDecisions,YourAction> decisions = new
           Dictionary<ReadDecisions,YourAction>();

decisions[ReadDecisions.ReadNext] = queue.Receive;
decisions[ReadDecisions.PeekNext] = queue.PeekById;
// you understand the main idea
//.... 

затем замените ваш переключатель на:

if(UseTimeout)
   decisions[ReadDecision](id, Timeout);
else
   decisions[ReadDecision](id, 0);  //or another value 
                                    //telling you there is no timeout .
                                    // it just have to be the same signature

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

0 голосов
/ 26 февраля 2009

Вы, вероятно, не хотите читать д, как вы делаете. Может быть, рефакторинг вещь, чтобы использовать обратный вызов? MessageQueue queue = новая MessageQueue (queuePath); // обработчик события queue.ReceiveCompleted + = QueueMessageReceived; // имя метода, который вызывается // начинаем "слушать" сообщения queue.BeginReceive ();

0 голосов
/ 22 января 2009

Могу предложить следующее:

1] «Парные» методы могут быть сгруппированы вместе

Каждый человек должен иметь возможность обрабатывать значение NULL. Таким образом, у вас будут следующие две группы:

Queue.Peek(TimeOut)
Queue.Receive(TimeOut)

Queue.ReceiveById(Id, TimeOut)
Queue.PeekById(Id, TimeOut)
...

2] Объявить двух делегатов для групп методов

delegate Message MethodType1(Timeout)
delegate Message MethodType2(Id, TimeOut)

3] Иметь метод GetDelegate (), который будет возвращать соответствующий метод для выполнения

object GetDelegate(ReadDecisions param)
{
 switch(param)
 {

   case ReadNext:
             MethodType1 receiveDlgt = new MethodType1(queue.Receive);
   case PeekMessageId:
             MethodType2 peekDlgt = new MethodType2(queue.Peek);
   ...
 }
}

4] Выполните соответствующий вызов в зависимости от типа делегата

InvokingMethod()
{
  object methodToExecute = GetDelegate(ReadDecision)
  if (methodToExecute.GetType() == typeof(MethodType1)) 
    {
    methodToExecute(TimeOut)
    }
    else
    {
    methodToExecute(Id, TimeOut)
    }

}

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

0 голосов
/ 22 января 2009

Почему бы не упростить передаваемые параметры

int? optionalTimeout = UseTimeout ? Timeout : null;

switch (ReadDecision) {
    case ReadDecisions.ReadNext:
        Message = queue.Receive( optionalTimeout ); break;

    case ReadDecisions.PeekNext:
        Message = queue.Peek( optionalTimeout ); break;

    // and so on ...

Затем в вашем методе очереди обработайте нулевое значение, переданное для Timeout как "не время ожидания"

0 голосов
/ 22 января 2009

Не могли бы вы использовать хеш-таблицу делегатов, ключом которой была бы комбинация ReadDecision и UseTimeout?
У меня такое чувство, что я прошу понизить голосование здесь ...

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