4

我有以下代码

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;

但是上面对 GetEvents 的调用以及上面设置的所有绑定标志都会返回接口的事件以及两个具体类。

如何从 GetEvents 中过滤掉父接口上定义的事件?

请注意,我正在为每个事件生成扩展方法,就像这样

public static 
IObservable<EventPattern<MouseButtonEventArgs>> 
PreviewMouseLeftButtonDownObserver(this IInputElement This){
        return Observable
               .FromEventPattern
               <MouseButtonEventHandler, MouseButtonEventArgs>
               ( h => This.PreviewMouseLeftButtonDown += h
               , h => This.PreviewMouseLeftButtonDown -= h);
}

所以我只做了事件的根定义,而不是派生的虚拟或接口实现。

4

2 回答 2

4

在示例中:

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()当然,如果您还想排除继承的成员,则必须结合使用。

于 2013-04-09T07:07:59.097 回答
1

您可以尝试使用 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);
}
于 2013-04-09T07:29:13.767 回答