有没有办法完成相当于通过引用传递“事件”?

时间:2011-08-16 22:58:26

标签: c# .net events delegates anonymous-methods

我把“event”放在引号中,因为我意识到它是一些语法糖,而不是真正的类型。

我有一些事件只是链接到另一个类中的匹配事件。所以当事件发生时,这段话就像

Raiser - >代理 - >订户

所以在Proxy类中我有一个像这样的通用模式:

Raiser.SomeEvent += 
    (_, args) =>
    {
        if (this.SomeEvent != null)
            this.SomeEvent(this, args);
    };

为了整理我的代码,我想把它移到另一个返回包含上述事件调用代码的新委托的方法:

public static EventHandler GetHandlerDelegate(EventHandler handler, Object sender)
{
    return
        (_, args) =>
        {                
            if (handler != null)
                handler(sender, args);
        };
    }      

然后在代理我可以做:

Raiser.SomeEvent += GetHandlerDelegate(this.SomeEvent, this);

哪个更整洁。

只要订阅者在上述调用之后没有决定订阅Proxy.SomeEvent ,这就没问题了。不幸的是,我并没有像我希望的那样通过参考传递“事件”;我现在明白我只是传递了调用列表,所以当OtherClass.SomeEvent发生并调用匿名方法并调用“event”(委托)时,它被赋予了,只有已添加到该事件的代理我将调用调用GetHandlerDelegate()。虽然这实际上足以满足我目前的情况,但以这种方式进行编码实际上是不可接受的。

我已经阅读了其他一些SO问题,我收集了一些可能有帮助的Reactive Extensions,但此时我正在寻找一个更简单的解决方案(如果有的话)。 (如果没有,我就不会这样做。)

还有另一种方法可以完成我正在尝试做的事情,没有这个缺点吗?


如果这个问题不明确,请参阅my answer,希望有助于澄清它。

2 个答案:

答案 0 :(得分:3)

编辑:好的,我想我现在明白了。它实际上非常简单。您应该能够编写代理只是为了拥有一个事件,然后让代理本身订阅Raiser的事件,就像这样(仅适用于EventHandler - 我稍后会谈到):

Proxy proxy = new Proxy();
raiser.SomeEvent += Proxy.Handler;

// Then in the subscriber...
proxy.ProxiedEvent += (whatever)

// And the proxy class...
public class Proxy
{
    public event EventHandler ProxiedEvent;

    public void Handler(object sender, EventArgs e)
    {
        EventHandler proxied = ProxiedEvent;
        if (proxied != null)
        {
            // Or pass on the original sender if you want to
            proxied(this, e);
        }
    }
}

现在,困难在于让它一般地运作起来。我现在无法想到这样做的任何方式,虽然我现在有点分心。

这是你想到的事情,还是至少可以帮助你以不同的方式思考问题?

答案 1 :(得分:0)

由于我最初的目标:

Raiser.SomeEvent += GetHandlerDelegate(this.SomeEvent, this); 

是不可能的,我已妥协并想出了这个:

Raiser.SomeEvent += (_, args) => RaiseEvent(this.SomeEvent, this, args); 

尽管GetHandlerDelegate()会返回一个提升事件的委托,RaiseEvent()只是(你猜对了)会引发事件。

public static void RaiseEvent(EventHandler _event, Object sender, EventArgs args)
{
    if (_event != null)
        _event(sender, args);
}

并使用自定义EventArgs支持事件:

public static void RaiseEvent<TArgs>(EventHandler<TArgs> _event, Object sender, TArgs args)
    where TArgs : EventArgs
{
    if (_event != null)
        _event(sender, args);
}

我已将这些方法放在一个静态助手类中,因此实际调用稍微有点粗暴;这是一个例子:

ViewControl.OpenFilesetClick += (_, args) => EventHelper.Raise(OpenFilesetClick, this, args); 

(我还将方法重命名为Raise()并从正在传递的事件名称中删除了可选的this

但我并不完全相信这是否值得,考虑到替代方案可以说更容易阅读:

ViewControl.OpenFilesetClick += (_, args) => 
{
    if (OpenFilesetClick != null)
        OpenFilesetClick(this, args);
};

无论如何,这是一个有趣的方式来了解更多关于事件和代表如何工作(或他们如何工作)。