代码如下所示:
时钟:
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();
其他问题是:
答案 0 :(得分:27)
使用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 :(得分:1)
我认为使用Action / Func代替委托是完全没问题的。
但事件不应该像这样使用。 它们是在无限期的时间点触发的,所以你只是不知道所有的参数。
你真正需要的可能是:
所以代码看起来像:
var theClock = new Clock();
theClock.AddSecondsSubscriber(new DisplayClock());
theClock.AddSecondsSubscriber(new LogClock());
theClock.RunAndExecuteVisitors( theBoolResultYouNeed => Console.WriteLine(theBoolResultYouNeed) );