C# 如何确定事件是否已订阅
在我的.NET应用程序中,我订阅了另一个类的事件。订阅是有条件的。当控件可见时,我订阅事件;当控件不可见时,我取消订阅事件。但是,在某些情况下,即使控件不可见,我也不希望取消订阅事件,因为我希望得到在后台线程上发生的操作的结果 是否有一种方法可以确定某个类是否已经订阅了该事件C# 如何确定事件是否已订阅,c#,.net,C#,.net,在我的.NET应用程序中,我订阅了另一个类的事件。订阅是有条件的。当控件可见时,我订阅事件;当控件不可见时,我取消订阅事件。但是,在某些情况下,即使控件不可见,我也不希望取消订阅事件,因为我希望得到在后台线程上发生的操作的结果 是否有一种方法可以确定某个类是否已经订阅了该事件 我知道我们可以在通过检查事件的null来引发该事件的类中执行此操作,但是在订阅该事件的类中如何执行此操作?您难道不记得您是否已经订阅了吗?到目前为止,这种方法对我很有效。即使您有很多事件或对象,您可能仍然希望记住这些(例如
我知道我们可以在通过检查事件的
null
来引发该事件的类中执行此操作,但是在订阅该事件的类中如何执行此操作?您难道不记得您是否已经订阅了吗?到目前为止,这种方法对我很有效。即使您有很多事件或对象,您可能仍然希望记住这些(例如,在字典中)
另一方面,可见性的改变,至少对我来说,不是订阅/取消订阅的好时机。我通常更倾向于使用construction/Disposed,这比每次可见性发生变化时都更加清晰。假设您无法访问声明事件的类的内部,那么您就无法直接执行该操作。事件仅公开运算符
+=
和-=
,其他不公开。订阅类中需要一个标志或其他机制来知道是否已订阅。能否将决策逻辑放入触发事件的方法中?假设您使用的是Winforms,它看起来是这样的:
if (MyEvent != null && isCriteriaFulfilled)
{
MyEvent();
}
其中isCriteriaCompleted
由您的可见/不可见逻辑决定
//更新/////
除了您的第一条评论之外,根据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;
}
只要在触发事件处理程序时检查控件是否可见。显式地发明了
事件
关键字,以阻止您执行想要执行的操作。它限制对底层委托
对象的访问,因此没有人可以直接处理它存储的事件处理程序订阅。事件是委托的访问器,就像属性是字段的访问器一样。属性只允许获取和设置,事件只允许添加和删除
这样可以确保代码的安全,其他代码只能在知道事件处理程序方法和目标对象的情况下删除事件处理程序。C语言通过不允许您命名目标对象,增加了一层安全性
WinForms增加了一层安全性,因此即使使用反射,也会变得很困难。它将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;
}
//
///确定控件是否订阅了可见的事件
///
///用于查找VisibleChanged事件的控件
///如果控件订阅了VisibleChanged事件,则为True,否则为False
已订阅专用bool(控制对象)
{
FieldInfo event\u visible\u field\u info=typeof(Control).GetField(“EventVisible”,
BindingFlags.Static | BindingFlags.NonPublic);
object object\u value=event\u visible\u field\u info.GetValue(controlObject);
PropertyInfo events\u property\u info=controlObject.GetType().GetProperty(“事件”,
BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList事件\列表=(EventHandlerList)事件\属性\信息.GetValue(controlObject,null);
返回(事件列表[对象值]!=null);
}
我只是想进一步说明汉斯的答案。我只是想确保我不会多次安装我的处理程序,也不会在我仍然需要它的时候删除它。这并不能防止恶意或恶意的呼叫者重复取消订阅,因为您需要跟踪呼叫者,而这只会使重复订阅超出跟踪机制
// 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;
}
}
//跟踪请求ReflectionOnlyResolveHandler的次数。
私有静态int_订阅服务器=0;
///
///注册或取消注册ReflectionOnlyResolveHandler。
///
///
公共静态void subscriberReflectionOnlyResolve(布尔启用)
{
锁
{
如果(_subscribers>0&&!enable)_subscribers-=1;
如果(启用)_+=1,则为else;
如果(启用&&&U订阅服务器==1)
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve+=ReflectionHelper.ReflectionOnlyResolveHandler;
else if(_订阅服务器==0)
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve-=ReflectionHelper.ReflectionOnlyResolveHandler;
}
}
如果仅关于是否有人订阅,请检查此链接:''bool subscribedTo=theEvent!=null `我想知道arecriteriamplemented
在语法上是否更好?如果(this.visible){a.Delegate+=newdelegate(method1);}或者{a.Delegate-=newdelegate(method1);},我会这样做我不想按照你的建议去做,因为事件是按固定的时间间隔触发的,我只想在我的控件不可见时使用它们。如果我照你说的做,那将是一次性能上的打击。@Ram:再次更新。但我仍然很好奇,为什么你认为这会影响性能?订阅事件也会增加分配和(最终)释放内存的开销。@Phil:是的,我同意这会增加开销。谢谢。:)我不想这样做,因为事件是按固定间隔触发的,我只想在控件不可见时使用它们。如果我照你说的去做,那将是一场表演
// 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;
}
}