有没有一种方法可以完成与传递“事件”相同的功能?通过参考?

发布于 2024-11-29 16:19:27 字数 1325 浏览 1 评论 0原文

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

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

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);
        };
    }      

然后在 Proxy 中我可以这样做:

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

哪个更整洁。

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

我读过其他一些 SO 问题,我发现有一种叫做“反应性扩展”的东西可能会有所帮助,但目前我正在寻找一种更简单的解决方案(如果有的话)。 (如果没有,我就不会这样做。)

是否有另一种方法可以完成我正在尝试做的事情,而没有上述缺点?


如果这个问题不清楚,请参阅我的回答希望有助于澄清它。

I put "event" in quotes because I realize that it's a bit of syntax sugar, rather than a true type.

I have some events which are simply chained to matching events in another class. So when the event is raised, the passage is like

Raiser -> Proxy -> Subscriber

So in the Proxy class I have a common pattern like this:

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

To tidy up my code I wanted to move this out to another method that returns a new delegate that wraps the above event-calling code:

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

And then in Proxy I can just do:

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

Which is much neater.

Well this is fine as long as Subscriber doesn't decide to subscribe to Proxy.SomeEvent after the above call. Unfortunately I'm not passing the "event" around by reference as I'd hoped; I now understand that I'm just passing the invocation list, so when OtherClass.SomeEvent happens and that anonymous method is called and invokes the "event" (delegate) it was given, only the delegates that had been added to that event at the time I called GetHandlerDelegate() will be called. While that would actually suffice for my current situation, it's really not acceptable to code it that way.

I've read some other SO questions and I gather there is something called Reactive Extensions that might help, but at this time I'm looking for a simpler solution if there is one. (If not, I just won't do this.)

Is there another way I can accomplish what I'm trying to do, without said drawback?


If this question is unclear, please see my answer which hopefully helps clarify it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

删除会话 2024-12-06 16:19:27

编辑:好的,我想我现在明白了。其实很简单。您应该能够编写代理以仅拥有一个事件,然后使代理本身订阅 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);
        }
    }
}

现在,这里的困难是让它普遍工作。尽管我现在有点心烦意乱,但我目前想不出任何方法可以做到这一点。

这是您正在考虑的事情吗?或者它至少可以帮助您以不同的方式思考问题吗?

EDIT: Okay, I think I get the point now. It's actually quite simple. You should be able to write the proxy to just have an event, and then make the proxy itself subscribe to the Raiser's event, like this (just for EventHandler - I'll come to that later on):

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);
        }
    }
}

Now, the difficulty here is getting it to work generically. I can't currently think of any way of doing that, although I'm somewhat distracted right now.

Is this the sort of thing you were thinking of, or does it at least help you think about things differently?

缱绻入梦 2024-12-06 16:19:27

由于我最初的目标

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);
};

无论如何,这是一种有趣的方式来了解更多有关事件和委托如何工作(或它们如何不工作)的信息。

Since my original goal of doing:

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

is impossible, I've compromised and come up with this:

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

Whereas GetHandlerDelegate() would return a delegate which raises the event, RaiseEvent() simply (you guessed it) raises the event.

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

And to support events using custom EventArgs:

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

I've put these methods in a static helper class, so the actual call is slightly uglier; here's an example:

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

(I also renamed the method to Raise() and dropped the optional this from the event name being passed).

But I'm not entirely convinced if this is worthwhile, considering the alternative was arguably easier to read:

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

Anyway, it was an interesting way to learn more about how events and delegates work (or how they don't work).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文