c # "ИЛИ" делегаты события возвращают bool - PullRequest
6 голосов
/ 18 сентября 2010

Я создал консоль для своей игры в XNA, и у меня есть делегат для ввода команды. В данный момент делегат возвращает значение bool. Я объявил событие внутри класса Console (который возвращает false), а затем подписался на это событие из других классов. Идея состоит в том, что если ни один из классов, подписавшихся на это событие, не возвращает true, то предполагается, что пользователь ввел недопустимую команду. Однако если хотя бы один из подписанных классов возвращает значение true, команда считается действительной.

На данный момент только один класс учитывается для возврата true или false, есть ли способ, которым я могу посмотреть возвращаемые значения всех подписывающихся классов, а затем ИЛИ их результат?

Спасибо

Ответы [ 3 ]

6 голосов
/ 18 сентября 2010

Из класса, который объявляет событие, вы можете получить список вызовов этого события (при условии, что это событие в виде поля). Вызов каждого из них по отдельности позволит вам проверить возвращаемое значение каждого подписчика на событие.

Например:

public event Func<bool> MyEvent = delegate { return false; };

...     

private bool EmitMyEventAndReturnIfAnySubscriberReturnsTrue()
{
    return MyEvent.GetInvocationList()
                  .Cast<Func<bool>>()
                  .Select(method => method()) 
                  .ToList() //Warning: Has side-effects
                  .Any(ret => ret);
}

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

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

EDIT: исправлена ​​ошибка принудительного полного выполнения последовательности на основе комментария Тимви.

3 голосов
/ 18 сентября 2010

Я понял это, как только задал этот вопрос: P

bool handled = false;
foreach (Delegate d in CommandProcessed.GetInvocationList())
    handled |= (bool) d.DynamicInvoke (gameTime, command.ToString());

if (!handled) { } // Command Unrecognized

Где CommandProcessed - мое событие, на которое подписываются классы.
Мой делегат принимает два аргумента: игровое время и командную строку.

0 голосов
/ 18 сентября 2010

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

class CommandEventArgs : EventArgs
{
    public DateTime GameTime {get; set; }
    public string Command {get; set;}
    public bool Valid {get; set;}
}

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

Вот как .NET обрабатывает события клавиатуры, для которых вы установили KeyEventArgs.Handled в значение true, чтобы подавить любые дальнейшие действия с событием.

...