когда у события есть несколько подписчиков, как я могу получить возвращаемое значение для каждого подписчика? - PullRequest
15 голосов
/ 06 августа 2009

Код выглядит следующим образом:

Часы

public class Clock
{
    public event Func<DateTime, bool> SecondChange;

    public void Run()
    {
        for (var i = 0; i < 20; i++)
        {
            Thread.Sleep(1000);

            if (SecondChange != null)
            {
                //how do I get return value for each subscriber?
                Console.WriteLine(SecondChange(DateTime.Now));
            }
        }
    }
}

DisplayClock:

public class DisplayClock
{
    public static bool TimeHasChanged(DateTime now)
    {
        Console.WriteLine(now.ToShortTimeString() + " Display");
        return true;
    }
}

LogClock:

public class LogClock
{
    public static bool WriteLogEntry(DateTime now)
    {
        Console.WriteLine(now.ToShortTimeString() + " Log");
        return false;
    }
}

Для запуска кода:

var theClock = new Clock();
theClock.SecondChange += DisplayClock.TimeHasChanged;
theClock.SecondChange += LogClock.WriteLogEntry;
theClock.Run();

Другие вопросы:

  • Рекомендуется ли каждому подписчику возвращать значение?
  • Полезно ли просто объявлять Action / Func как тип возвращаемого события вместо того, чтобы вручную объявлять делегат?

Ответы [ 2 ]

27 голосов
/ 06 августа 2009

Использование Delegate.GetInvocationList.

if (SecondChange != null)
{
    DateTime now = DateTime.Now;
    foreach (Delegate d in SecondChange.GetInvocationList())
    {
        Console.WriteLine(d.DynamicInvoke(now));
    }
}

это хорошая практика, чтобы просто использовать Action / Func вместо того, чтобы вручную объявлять делегата?

Да. Но я укажу, что для событий лучше всего использовать EventHandler<T> вместо Func<..., TResult>. EventHandler<T> не поддерживает возвращаемые значения, но вы несколько оправдываетесь тем, что есть несколько событий .NET, которые имеют возвращаемые значения. Я бы посоветовал иметь настраиваемое свойство в пользовательском подклассе EventArgs, который вы используете в качестве T. Это образец, который мы видим в таких вещах, как KeyEventArgs.Handled. Таким образом, вы можете использовать EventHandler<T>, и подписчики также могут ограничивать свои ответы в ограниченной степени, получая и устанавливая это свойство.

1 голос
/ 06 августа 2009

Я думаю, что вполне нормально использовать Action / Func вместо делегата.

НО События не должны использоваться таким образом. Они срабатывают в неопределенный момент времени, поэтому вы просто не знаете все параметры.

Возможно, вам действительно нужно:

  1. Использовать полиморфизм для часов.
  2. Используйте шаблоны посетителей / подписчиков / наблюдателей, чтобы получить их значения.

Таким образом, код будет выглядеть так:

var theClock = new Clock();
theClock.AddSecondsSubscriber(new DisplayClock());
theClock.AddSecondsSubscriber(new LogClock());
theClock.RunAndExecuteVisitors( theBoolResultYouNeed => Console.WriteLine(theBoolResultYouNeed) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...