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 を呼び出すと、インターフェイスのイベントと 2 つの具象クラスが返されます。

親インターフェイスで定義されているイベントを 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あなたの質問のような場所です。最初の基準は、それが親タイプで定義されたイベントでないことを確認します。2 番目の基準は、インターフェイスの実装ではないことを確認します。正確な設定によっては、2 番目の基準が必要ない場合もあります。

編集して回答

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 に答える