interface 型の Type.GetMembers や GetMethods では継承元は無視される
ref: Type.GetMethods Method (BindingFlags)
具体的にどういう事かは ref 先のユーザーフィードバックのコメントに詳しいが、要するに interface の Type に対して GetMembers などを呼んだ場合、基底 interface のメンバーは列挙されないということである。
したがって、interface の全メンバーなりメソッドなりを列挙するつもりで GetMembers や GetMethods を使うと、派生元になっている interface のメンバーが出てこなくなって悲しいことになる。のでこのようなエントリを書くに至った次第*1。
対処法としては、ref 先にもあるように GetInterfaces() を使って、祖先インターフェースたちのメンバーを再帰的に列挙する他にないだろう。
なお、ref 先では HashSet
そのため、mono 環境でも動く、ランタイムの実装に依存しないコードにするためには、再帰的列挙の過程で過去に列挙済みの interface の型を覚えておくようにし、そもそも同一 interface は必ず一回だけ列挙するようにすれば良いだろう。
具体的には、以下のようなコードが上記を踏まえた workaround になるだろう。
/// <summary> /// /// </summary> [ThreadStatic] private static Dictionary<KeyValuePair<Type, BindingFlags>, MethodInfo[]> allMethods; /// <summary> /// Returns all <see cref="MethodInfo"/>s of given <paramref name="type"/>. /// Even if given type is interface, this method returns all methods (unlike type.GetMethods). /// </summary> /// <param name="type"></param> /// <param name="flags"></param> /// <returns></returns> public static IEnumerable<MethodInfo> GetAllMethods(this Type type, BindingFlags flags) { MethodInfo[] methods; var key = new KeyValuePair<Type, BindingFlags>(type, flags); if (allMethods == null) allMethods = new Dictionary<KeyValuePair<Type, BindingFlags>, MethodInfo[]>(); if (!allMethods.TryGetValue(key, out methods)) { allMethods[key] = methods = (type.IsInterface) ? type.GetAllMethodsOfInterface(flags).ToArray() : type.GetMethods(flags); } return methods; } /// <summary> /// /// </summary> /// <param name="interfaceType"></param> /// <param name="flags"></param> /// <returns></returns> private static IEnumerable<MethodInfo> GetAllMethodsOfInterface(this Type interfaceType, BindingFlags flags) { if (!interfaceType.IsInterface) throw new ArgumentException("Given type isn't interface: " + interfaceType.Name); return interfaceType.GetAllMethodsOfInterface(flags, new HashSet<Type>()); } /// <summary> /// /// </summary> /// <param name="interfaceType"></param> /// <param name="flags"></param> /// <param name="visitedInterfaces"></param> /// <returns></returns> private static IEnumerable<MethodInfo> GetAllMethodsOfInterface(this Type interfaceType, BindingFlags flags, HashSet<Type> visitedInterfaces) { if (!interfaceType.IsInterface) throw new ArgumentException("Given type isn't interface: " + interfaceType.Name); if (!visitedInterfaces.Add(interfaceType)) return Enumerable.Empty<MethodInfo>(); return interfaceType.GetMethods(flags).Concat( interfaceType.GetInterfaces().SelectMany((p) => p.GetAllMethodsOfInterface(flags, visitedInterfaces)) ); }