一次性通用事件调用?

And*_*kus 4 c#

我想要实现的是创建方便的语法,仅在事件上调用一次回调.

public static class Extensions
{
    public static void Once<T>(this EventHandler<T> @event, EventHandler<T> callback)
    {
        EventHandler<T> cb = null;
        cb = (object that, T info) => {
            if (callback != null) {
                callback(that, info);
            }
            @event -= cb;
        };
        @event += cb;
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该允许我们写这样的东西:

obj.OnSomething.Once((sender, obj) => Console.WriteLine(obj));
Run Code Online (Sandbox Code Playgroud)

请注意,OnSomething是某种类型的事件EventHandler.

问题是我收到错误消息:

错误CS0070:事件SharpTox.Core.Tox.OnFriendMessage' can only appear on the left hand side of += or -= when used outside of the type SharpTox.Core.Tox'(CS0070)(SharpTox.Tests)

难道没有办法轻松实现这一目标吗?我是否必须从OnSomething中删除事件并使其成为一个简单的委托?

Luc*_*ski 8

不幸的是,你不能在这里有一个很好的语法.就像错误消息所说的那样,你可以用它定义的类之外的事件字段来处理它,+=或者在左边的引用它-=.

这是Rx用于将observable绑定到事件的方法:

var observable = Observable.FromEventPattern(
    handler => obj.OnSomething += handler,
    handler => obj.OnSomething -= handler);
Run Code Online (Sandbox Code Playgroud)

基本上,FromEventPattern是一个带有两个lambda的助手:一个用于订阅,另一个用于取消订阅.您可以使用类似的模式,或者只使用Rx来实现相同的效果:

Observable.FromEventPattern(h => obj.OnSomething += h, h => obj.OnSomething -= h)
          .Take(1)
          .Subscribe(e => ...);
Run Code Online (Sandbox Code Playgroud)

在旁注中,这将保留对obj使用的lambda 的引用Subscribe(有中间粘合对象,但这是无关紧要的).这意味着如果从未调用该事件,并且如果lambda是长寿的,那么obj将不符合GC(称为事件内存泄漏的情况).对于您的情况,这可能是也可能不是问题.