如何在C#中引用事件

时间:2011-01-21 06:20:58

标签: c# events reference callback event-handling

我有以下课程,其中有一个名为LengthChanged的公共事件:

class Dimension
{
    public int Length
    {
        get
        {
            return this.length;
        }
        set
        {
            if (this.length != value)
            {
                this.length = value;
                this.OnLengthChanged ();
            }
    }

    protected virtual void OnLengthChanged()
    {
        var handler = this.LengthChanged;
        if (handler != null)
        {
            handler (this, System.EventArgs.Empty);
        }
    }

    public event System.EventHandler LengthChanged;

    private int length;
}

我希望能够在名为Observer的方法中注册/取消注册此事件的处理程序,该方法对Dimension类一无所知。我提出了两个场景,其中没有一个真的令人满意:

  1. 使用ILengthChanged事件定义接口LengthChanged,然后确保Dimension实现ILengthChanged。然后我必须为我定义的每个接口提供Observer方法的一个实现。这绝不是通用的。我真的希望能够简单地传递对System.EventHandler事件的引用。

  2. 使用System.Action<System.EventHandler>回调在Observer方法中注册和取消注册事件处理程序,就像这样:

    类Foo {     public void Observer(System.Action register,                          System.Action取消注册)     {         注册(this.MyEventHandler);

        // keep track of the unregister callback, so that we can unregister
        // our event handler later on, if needed...
    }
    
    private void MyEventHandler(object sender, System.EventArgs e)
    {
        ...
    }
    

    }

  3. 然后会像这样调用:

    Foo foo = ...;
    Dimension dim = ...;
    
    foo.Observer (x => dim.LengthChanged += x, x => dim.LengthChanged -= x);
    

    并且在执行时,最终将使用内部事件处理程序LengthChanged连接MyEventHandler事件。但这不是很优雅。我本来希望能够写这个:

    Foo foo = ...;
    Dimension dim = ...;
    
    foo.Observer (dim.LengthChanged);
    

    但我不知道如何实现这一目标。也许我错过了一些非常明显的东西?我想有些dynamic魔法可以做到这一点,不知何故,但是这不会强制执行编译时类型检查:我不希望Observer的用户传入对不是的事件的引用满足System.EventHandler事件签名。

3 个答案:

答案 0 :(得分:10)

不幸的是,没有办法做到这一点。事件通常不是.NET中的一等公民 - 尽管F#试图在那里推广它们。

传递subscribe / unsubscribe代理或使用指示事件名称的字符串。 (后者通常较短,但在编译时显然不太安全。)

这些是Reactive Extensions采取的方法 - 如果有更简洁的方法,我相信他们会使用它:(

答案 1 :(得分:3)

您可以创建自定义访问器。

   public event EventHandler NewEvent
            {
                add { Dimension.LengthChanged += value; }
                remove { Dimension.LengthChanged -= value; }
            }

请参阅 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-implement-custom-event-accessors

答案 2 :(得分:2)

事件不应该传递给另一个方法。但是,您可以将委托传递给另一个方法。也许,你所寻找的只是一个简单的公共代表,而不是事件。

如果您将活动更改为

public System.EventHandler LengthChanged; 

您只需将LengthChanged传递给Observer就像这样

Foo foo = ...;
Dimension dim = ...;
foo.Observer (dim.LengthChanged);