17

代码如下所示:

钟:

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

2 回答 2

31

使用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>和订阅者也可以通过获取和设置此属性在有限的范围内协调他们的响应。

于 2009-08-06T04:46:26.603 回答
1

我认为使用 Action/Func 代替委托是完全可以的。

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

你真正需要的可能是:

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

所以代码看起来像:

var theClock = new Clock();
theClock.AddSecondsSubscriber(new DisplayClock());
theClock.AddSecondsSubscriber(new LogClock());
theClock.RunAndExecuteVisitors( theBoolResultYouNeed => Console.WriteLine(theBoolResultYouNeed) );
于 2009-08-06T05:01:44.920 回答