考虑一个有一些事件的类。此事件列表将会增长。有些是可选的。其他是必需的。
为了简化一些初始验证,我有一个自定义属性,将事件标记为必需属性。 例如:
[RequiredEventSubscription("This event is required!")]
public event EventHandler ServiceStarted;
到目前为止一切顺利。 要使用反射验证所有事件,我会迭代事件列表并获取自定义属性。 但我需要一种方法来确定事件是否已订阅。
没有反射,ServiceStarted.GetInvocationList可以完成这项工作。但事件必须来自此列表: var eventList = this.GetType()。GetEvents()。ToList();
有没有办法检查事件列表中的给定事件是否使用反射订阅?
- [更新] - 这是基于Ami答案的可能解决方案:
private void CheckIfRequiredEventsAreSubscribed()
{
var eventList = GetType().GetEvents().ToList().Where(e => Attribute.IsDefined(e, typeof(RequiredEventSubscription)));
StringBuilder exceptionMessage = new StringBuilder();
StringBuilder warnMessage = new StringBuilder();
foreach (var evt in eventList)
{
RequiredEventSubscription reqAttr = (RequiredEventSubscription) evt.GetCustomAttributes(typeof(RequiredEventSubscription), true).First();
var evtDelegate = this.GetType().GetField(evt.Name, BindingFlags.Instance | BindingFlags.NonPublic);
if (evtDelegate.GetValue(this) == null)
{
warnMessage.AppendLine(reqAttr.warnMess);
if (reqAttr.throwException) exceptionMessage.AppendLine(reqAttr.warnMess);
}
}
if (warnMessage.Length > 0)
Console.WriteLine(warnMessage);
if (exceptionMessage.Length > 0)
throw new RequiredEventSubscriptionException(exceptionMessage.ToString());
}
非常感谢!!
答案 0 :(得分:4)
这里有一些主要的设计问题。通常,没有办法向对象询问其事件的订阅者是谁。任何人都想要这个功能是非常不寻常的,但是如果你真的想要它,你应该让类以某种方式公开它,例如,通过实现一个方法的接口,如:
public IEnumerable<Delegate> GetSubscribers(string eventName);
无论如何,要回答问题,你可以使用反射,但前提是你确切知道如何维护订阅者。例如, 假设所有事件都是使用C#字段类事件的当前实现实现的,您可以执行类似(强烈不鼓励)的事情:
object o = ...
var unsubscribedEvents =
from e in o.GetType().GetEvents()
where Attribute.IsDefined(e, typeof(RequiredEventSubscriptionAttribute))
let field = o.GetType()
.GetField(e.Name, BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(o)
where field == null
select field;
var isValid = !unsubscribedEvents.Any();