如何确定一个事件是否已经订阅

在我的.NET应用程序中,我正在订阅来自另一个类的事件。 订阅是有条件的。 我正在订阅控件可见时的事件,而当它变得不可见时则取消订阅。 但是,在某些情况下,即使控件不可见,我也不想取消订阅事件,因为我想要在后台线程上发生的操作的结果。

有什么方法可以确定一个class级是否已经订阅了该活动?

我知道我们可以在课堂上做到这一点,通过检查事件为null来提高这个事件,但是我怎么在一个订阅这个事件的类中做到这一点?

event关键字是明确的发明,以防止你做你想做的事情。 它限制对底层delegate对象的访问,所以没有人可以直接混淆它存储的事件处理器订阅。 事件是委托的访问者 ,就像属性是字段的访问者一样。 一个属性只允许获取和设置,一个事件只允许添加和删除。

这样可以保证代码安全,其他代码只有在知道事件处理程序方法和目标对象时才能移除事件处理程序。 C#语言通过不允许您命名目标对象来提供额外的安全层。

而WinForms提供了一个额外的安全层,所以即使你使用Reflection也变得困难。 它将一个delegate实例存储在一个EventHandlerList并以一个秘密的“cookie”作为关键字,你必须知道这个cookie将对象从列表中挖出来。

那么,不要去那里。 用你的一些代码解决你的问题是微不足道的:

 private bool mSubscribed; private void Subscribe(bool enabled) { if (!enabled) textBox1.VisibleChanged -= textBox1_VisibleChanged; else if (!mSubscribed) textBox1.VisibleChanged += textBox1_VisibleChanged; mSubscribed = enabled; } 

假设你没有访问声明事件的类的内部,你没有办法直接做。 事件只暴露运营商+=-= ,没有别的。 你需要在你的订阅类中有一个标志或其他机制来知道你是否已经订阅了。

  /// <summary> /// Determine if a control has the event visible subscribed to /// </summary> /// <param name="controlObject">The control to look for the VisibleChanged event</param> /// <returns>True if the control is subscribed to a VisibleChanged event, False otherwise</returns> private bool IsSubscribed(Control controlObject) { FieldInfo event_visible_field_info = typeof(Control).GetField("EventVisible", BindingFlags.Static | BindingFlags.NonPublic); object object_value = event_visible_field_info.GetValue(controlObject); PropertyInfo events_property_info = controlObject.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); EventHandlerList event_list = (EventHandlerList)events_property_info.GetValue(controlObject, null); return (event_list[object_value] != null); } 

你可以把决策逻辑放到引发事件的方法中吗? 假设你正在使用Winforms,它看起来像这样:

  if (MyEvent != null && isCriteriaFulfilled) { MyEvent(); } 

isCriteriaFulfilled是由您的可见/不可见逻辑确定的。

// 更新 /////

除了你的第一条评论,根据这个值来改变你的事件处理程序中的行为是没有意义的。 this.Visible

  a.Delegate += new Delegate(method1); ... private void method1() { if (this.Visible) // Do Stuff } 

或者如果你真的需要去订阅和取消订阅:

  private Delegate _method1 = null; ... if(this.visible) { if (_method1 == null) _method1 = new Delegate(method1); a.Delegate += _method1; } else if (_method1 != null) { a.Delegate -= _method1; } 

只要触发事件处理程序,就可以检查控件是否可见。

你不能只记得你是否已经订阅? 目前为止,这种方法对我来说效果不错。 即使你有很多的事件或对象,你仍然可能只想记住(例如在字典中)。

另一方面,能见度的变化至less对我来说不是一个好的订阅/取消订阅点。 我通常宁愿与build设/处置,这比每次可见性变化更清晰。

我只是扩大汉斯的答案。 我只是试图确保我不是多次安装我的处理程序,而不是当我仍然需要时删除它。 这不会防止恶意或不正当的来电者反复取消订阅,因为您需要跟踪来电者,而这只会让您反复订阅超出跟踪机制。

 // Tracks how many times the ReflectionOnlyResolveHandler has been requested. private static int _subscribers = 0; /// <summary> /// Register or unregister the ReflectionOnlyResolveHandler. /// </summary> /// <param name="enable"></param> public static void SubscribeReflectionOnlyResolve(bool enable) { lock(_lock) { if (_subscribers > 0 && !enable) _subscribers -= 1; else if (enable) _subscribers += 1; if (enable && _subscribers == 1) AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ReflectionHelper.ReflectionOnlyResolveHandler; else if (_subscribers == 0) AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= ReflectionHelper.ReflectionOnlyResolveHandler; } }