当一个事件有多个订阅者时,如何获得每个订阅者的返回值?

代码如下所示:

时钟:

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

使用Delegate.GetInvocationList

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

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

是。 但我要指出,最佳做法是使事件使用EventHandler而不是Func<..., TResult>EventHandler不支持返回值,但您有点合理,因为有一些.NET事件具有返回值。 我认为在自定义的EventArgs子类中使用可设置的属性更好,您可以将其用作T 这是我们在KeyEventArgs.Handled东西中看到的模式。 通过这种方式,您可以使用EventHandler ,订阅者也可以通过获取和设置此属性来在有限的范围内协调其响应。

我认为使用Action / Func代替委托是完全没问题的。

但事件不应该像这样使用。 它们是在无限期的时间点触发的,所以你只是不知道所有的参数。

你真正需要的可能是:

  1. 将多态性用于时钟。
  2. 使用visitor / subscriber / observer模式获取其值。

所以代码看起来像:

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