c# – 将任何委托作为参数的构造方法
这是简化的案例.我有一个类来存储它将在完成时调用的委托:
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 =()=> {Console.WriteLine(“trigger”); };只是将处理程序附加到触发器而不是bar. 您可以完成所有这些工作的方法是停止使用事件并使用Microsoft的Reactive Extensions(NuGet“Rx-Main”),它允许您将事件转换为基于LINQ的IObservable< T>可以传递的实例. 以下是我上面的示例代码如何工作: 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(); 那仍然是正确的输出. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |