【问题标题】:when an event has multiple subscribers, how do I get the return value for each subscriber?当一个事件有多个订阅者时,如何获取每个订阅者的返回值?
【发布时间】:2010-11-17 05:51:53
【问题描述】:

代码如下:

时钟:

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));
            }
        }
    }
}

显示时钟:

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

日志时钟:

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 声明为事件返回类型而不是手动声明委托是一种好习惯吗?

【问题讨论】:

    标签: c# events return-value subscription


    【解决方案1】:

    使用Delegate.GetInvocationList

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

    仅使用 Action/Func 而不是手动声明委托是一种好习惯吗?

    是的。但我要指出,最好的做法是让事件使用EventHandler&lt;T&gt; 而不是Func&lt;..., TResult&gt;EventHandler&lt;T&gt; 不支持返回值,但您有理由认为有一些 .NET 事件具有返回值。我认为在您用作T 的自定义EventArgs 子类中拥有一个可设置的属性会更好。这是我们在KeyEventArgs.Handled 之类的东西中看到的模式。这样,您可以使用EventHandler&lt;T&gt;,订阅者也可以通过获取和设置该属性,在有限的范围内协调他们的响应。

    【讨论】:

    • 不同意。 (object sender, EventArgs e) 模式充满了微妙的优点。在此处查看两个已接受的答案:social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/…
    • 发送方 args 模式的另一个优点是,如果您添加额外的数据,您只需向 arg 类添加一个元素并提供额外的数据,而不会破坏现有代码。如果您声明自己的委托接受单独的参数,任何添加的数据都会破坏您的所有客户端。这甚至没有创建一个新的子类。
    【解决方案2】:

    我认为使用 Action/Func 代替委托是非常好的。

    但是事件不应该这样使用。 它们在不确定的时间点触发,因此您只是不知道所有参数。

    你真正需要的可能是:

    1. 对时钟使用多态性。
    2. 使用访问者/订阅者/观察者模式来获取它们的值。

    所以代码看起来像:

    var theClock = new Clock();
    theClock.AddSecondsSubscriber(new DisplayClock());
    theClock.AddSecondsSubscriber(new LogClock());
    theClock.RunAndExecuteVisitors( theBoolResultYouNeed => Console.WriteLine(theBoolResultYouNeed) );
    

    【讨论】:

      猜你喜欢
      • 2021-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多