The code looks like below:
Clock:
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;
}
}
To run the code:
var theClock = new Clock();
theClock.SecondChange += DisplayClock.TimeHasChanged;
theClock.SecondChange += LogClock.WriteLogEntry;
theClock.Run();
The other questions are:
Use Delegate.GetInvocationList
.
if (SecondChange != null)
{
DateTime now = DateTime.Now;
foreach (Delegate d in SecondChange.GetInvocationList())
{
Console.WriteLine(d.DynamicInvoke(now));
}
}
is it good practice to just use Action/Func instead of manually declaring a delegate?
Yes. But I will point out that the best practice is for events to use EventHandler<T>
instead of Func<..., TResult>
. EventHandler<T>
does not support return values, but you are somewhat justified in that there are a few .NET events that have return values. I would consider it better to have a settable property in a custom EventArgs
subclass that you use as your T
. This is the pattern we see in things like KeyEventArgs.Handled
. In this way, you can use EventHandler<T>
and the subscribers can also coordinate their responses to a limited extent by getting and setting this property.