views:

846

answers:

2

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:

  • Is it good practice for each subscriber to return a value?
  • Is it good practice to just declare Action/Func as the event return type instead of manually declaring a delegate?
+7  A: 

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.

binarycoder
Thank you very much.
Jeffrey C
<EventArgs is redundant> Disagree. The (object sender, EventArgs e) pattern is full of subtle goodness. See both of the accepted answers here: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/83e9f2f4-908b-4679-811d-c5b1471730d7
binarycoder
Ok, I see your point.
Jeffrey C
Another advantage of the sender, args pattern is that if you add additional data, you can just add an element to the arg class and provide extra data without breaking existing code. If you declare your own delegate that takes individual parameters, any additions of data will break all of your clients. And that's without even *having* to create a new subclass.
kyoryu
A: 

I think it is perfectly fine to use Action/Func instead of the delegate.

BUT Events are not supposed to be used like that. They are triggered at indefinite time point, so you just don't know all the parameters.

What you really need is probably:

  1. Use polymorphism for clock.
  2. Use visitor/subscriber/observer patterns to get their values.

So the code will look like:

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