这是简化的情况。我有一个存储委托的类,它将在完成时调用:
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] 删除。
我来说两句