构造函数,将任何委托作为参数

亚历山大·孔德拉斯基(Alexander Kondratskiy)

这是简化的情况。我有一个存储委托的类,它将在完成时调用:

public class Animation
{
     public delegate void AnimationEnd();
     public event AnimationEnd OnEnd;
}

我还有另一个实用程序类,我想订阅各种代表。在构造上,我希望自己向代理注册,但除此之外,它并不关心类型。问题是,我不知道如何在类型系统中表达它。这是我的伪C#

public class WaitForDelegate
{
    public delegateFired = false;

    // How to express the generic type here?
    public WaitForDelegate<F that's a delegate>(F trigger)
    {
        trigger += () => { delegateFired = true; };
    }
}

提前致谢!


感谢Alberto Monteiro,我只是将其System.Action用作活动的类型。我现在的问题是,如何将事件传递给构造函数以便它可以注册?这可能是一个非常愚蠢的问题。

public class Example
{
    Animation animation; // assume initialized

    public void example()
    {
        // Here I can't pass the delegate, and get an error like
        // "The event can only appear on the left hand side of += or -="
        WaitForDelegate waiter = new WaitForDelegate(animation.OnEnd);
    }
}
谜团

恐怕你做不了你要问的事。

首先,您不能受到代表的约束。最接近合法C#的代码是这样的:

public class WaitForDelegate<F> where F : System.Delegate
{
    public bool delegateFired = false;

    public WaitForDelegate(F trigger)
    {
        trigger += () => { delegateFired = true; };
    }
}

但是它不会编译。

但是更大的问题是,无论如何您都不能像这样传递代表。

考虑这个简化的类:

public class WaitForDelegate
{
    public WaitForDelegate(Action trigger)
    {
        trigger += () => { Console.WriteLine("trigger"); };
    }
}

然后,我尝试像这样使用它:

Action bar = () => Console.WriteLine("bar");

var wfd = new WaitForDelegate(bar);

bar();

唯一的输出是:

bar

这个词trigger没有出现。这是因为委托是按值复制的,因此该行trigger += () => { Console.WriteLine("trigger"); };仅将处理程序附加到trigger而不是附加bar

完成所有这些工作的方式是停止使用事件,并使用Microsoft的Reactive Extensions(NuGet“ Rx-Main”),它使您可以将事件转换为IObservable<T>可以传递的基于LINQ的实例。

这就是我上面的示例代码将如何工作:

public class WaitForDelegate
{
    public WaitForDelegate(IObservable<Unit> trigger)
    {
        trigger.Subscribe(_ => { Console.WriteLine("trigger"); });
    }
}

现在,您将其称为:

Action bar = () => Console.WriteLine("bar");

var wfd = new WaitForDelegate(Observable.FromEvent(h => bar += h, h => bar -= h));

bar();

现在将产生输出:

bar
trigger

注意,该Observable.FromEvent调用包含在有权访问的范围内附加和分离处理程序的代码。它允许最终的订阅呼叫与的呼叫无关.Dispose()

我已经使该类非常简单,但是更完整的版本是这样的:

public class WaitForDelegate : IDisposable
{
    private IDisposable _subscription;

    public WaitForDelegate(IObservable<Unit> trigger)
    {
        _subscription = trigger.Subscribe(_ => { Console.WriteLine("trigger"); });
    }

    public void Dispose()
    {
        _subscription.Dispose();
    }
}

如果您不想充分利用Rx,可以采用以下方法:

public class WaitForDelegate : IDisposable
{
    private Action _detach;

    public WaitForDelegate(Action<Action> add, Action<Action> remove)
    {
        Action handler = () => Console.WriteLine("trigger");
        _detach = () => remove(handler);
        add(handler);
    }

    public void Dispose()
    {
        if (_detach != null)
        {
            _detach();
            _detach = null;
        }
    }
}

您这样称呼它:

Action bar = () => Console.WriteLine("bar");

var wfd = new WaitForDelegate(h => bar += h, h => bar -= h);

bar();

那仍然可以正确输出。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章