如何通过反射获取类型的事件,忽略父接口上的事件
本文关键字:事件 接口 获取 取类型 何通过 反射 | 更新日期: 2023-09-27 18:08:05
我有以下代码
Type type = ...
var events=type.GetEvents(
BindingFlags.DeclaredOnly
| BindingFlags.Instance
| BindingFlags.Public).ToList();
然而,这也返回了声明的事件父接口。例如
UIElement
ContentElement
实施IInputElement
定义事件
//
// Summary:
// Occurs when the mouse pointer moves while the mouse pointer is over the element.
event MouseEventHandler PreviewMouseMove;
,但上面的调用geteevents与所有的绑定标志设置如上返回接口和两个具体类的事件。
如何过滤掉定义在父接口上的事件GetEvents吗?
请注意,我正在为每个事件生成扩展方法,如下所示
public static
IObservable<EventPattern<MouseButtonEventArgs>>
PreviewMouseLeftButtonDownObserver(this IInputElement This){
return Observable
.FromEventPattern
<MouseButtonEventHandler, MouseButtonEventArgs>
( h => This.PreviewMouseLeftButtonDown += h
, h => This.PreviewMouseLeftButtonDown -= h);
}
所以我只做了事件的根定义,而不是派生的虚拟或接口实现。
示例中:
interface IFace
{
event EventHandler A;
}
class Base
{
public virtual event EventHandler B;
public event EventHandler C;
}
class YourType : Base, IFace
{
public event EventHandler A; // implements interface
public override event EventHandler B; // overrides base class implementation
public event EventHandler D; // new event
}
如果您在typeof(YourType)
上使用反射,您想查看哪个事件?
答:
你可以这样写:
events.Where(x =>
x.GetAddMethod().GetBaseDefinition().DeclaringType == type
&& !x.GetAddMethod().IsFinal)
);
,其中type
在你的问题中是这样的。第一个条件确保它不是在父类型上定义的事件。第二个标准确保它不是接口实现。您可能不需要第二个条件,这取决于您的确切设置。
编辑回答
events.Where(x =>{
var addMethod = x.GetAddMethod();
var basetype = addMethod.GetBaseDefinition().DeclaringType;
return basetype == type && (!addMethod.IsFinal || basetype.IsInterface);
})
这个添加确保我也得到接口。
替代方法:要确定成员是否实现了某个接口,可以使用:
var interfaceImplementingMethods = new HashSet<MethodInfo>(type.GetInterfaces()
.SelectMany(i => type.GetInterfaceMap(i).TargetMethods));
var result = events.Where(x => !interfaceImplementingMethods
.Contains(x.GetAddMethod()));
即使实现成员被声明为virtual
(或abstract
),它也应该工作。当然,如果您想要排除同样继承的成员,则必须与GetBaseDefinition()
结合使用。
您可以尝试使用linq过滤掉接口的事件,像这样…
Type type = typeof (Bar);
Type interfaceType = typeof (IFoo);
var interfaceEvents = interfaceType.GetEvents(BindingFlags.DeclaredOnly
| BindingFlags.Instance
| BindingFlags.Public);
var events = type.GetEvents(BindingFlags.DeclaredOnly
| BindingFlags.Instance
| BindingFlags.Public);
events = events.Where(e => interfaceEvents.FirstOrDefault(
ie => ie.Name == e.Name &&
ie.EventHandlerType == e.EventHandlerType) == null).ToArray();
编辑:
基类中的事件不应该包含在GetEvents方法的结果中。这里是一个方法,它删除该类型实现的所有接口的事件。
编辑2:
此方法还将删除重写的基类事件:
public IEnumerable<EventInfo> GetEventsEx(Type type)
{
var baseEvents = new List<EventInfo>();
// Adds Events of interfaces to baseEvents
foreach (var interfaceType in type.GetInterfaces())
{
baseEvents.AddRange(interfaceType.GetEvents(
BindingFlags.DeclaredOnly
| BindingFlags.Instance
| BindingFlags.Public));
}
// Adds Events of base classes to baseEvents
var baseType = type.BaseType;
while (baseType != typeof (object))
{
baseEvents.AddRange(baseType.GetEvents(
BindingFlags.DeclaredOnly
| BindingFlags.Instance
| BindingFlags.Public));
baseType = baseType.BaseType;
}
// Get events for type
var events = type.GetEvents(
BindingFlags.DeclaredOnly
| BindingFlags.Instance
| BindingFlags.Public);
// Remove baseEvents and return
return events.Where(e => baseEvents.FirstOrDefault(
ie => ie.Name == e.Name &&
ie.EventHandlerType == e.EventHandlerType) == null);
}
编辑3:删除BindingFlags.DeclaredOnly
标志的新方法,这可能会工作得更好:
public IEnumerable<EventInfo> GetEventsEx(Type type)
{
var baseEvents = new List<EventInfo>();
// Adds Events of interfaces to baseEvents
foreach (var interfaceType in type.GetInterfaces())
{
baseEvents.AddRange(interfaceType.GetEvents(
BindingFlags.Instance
| BindingFlags.Public));
}
// Adds Events of base classes to baseEvents
var baseType = type.BaseType;
if (baseType != null && baseType != typeof (object))
{
baseEvents.AddRange(baseType.GetEvents(
BindingFlags.Instance
| BindingFlags.Public));
}
// Get events for type
var events = type.GetEvents(
BindingFlags.DeclaredOnly
| BindingFlags.Instance
| BindingFlags.Public);
// Remove baseEvents and return
return events.Where(e => baseEvents.FirstOrDefault(
ie => ie.Name == e.Name &&
ie.EventHandlerType == e.EventHandlerType) == null);
}