Translating a MethodInfo object obtained from an interface type, to the corresponding MethodInfo object on an implementing type in C#?
我的问题是:如果我有一个MethodInfo对象,对于一个方法,从一个接口类型中获取,并且我也有一个实现这个接口的类的类型对象,但是它用一个显式的实现来实现这个方法,我如何正确地获得这个实现方法对应的MethodInfo对象呢?班级?
我需要这样做的原因是,实现方法可以应用一些属性,我需要通过反射来找到这些属性,但是需要找到这些属性的类只具有实现类的对象引用,以及接口的类型对象(+对应的MethodInfo对象)。
那么,假设我有以下程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | using System; using System.Reflection; namespace ConsoleApplication8 { public interface ITest { void Test(); } public class Test : ITest { void ITest.Test() { throw new NotImplementedException(); } } class Program { static void Main(string[] args) { Type interfaceType = typeof(ITest); Type classType = typeof(Test); MethodInfo testMethodViaInterface = interfaceType.GetMethods()[0]; MethodInfo implementingMethod = classType.GetMethod(/* ??? */"Test"); Console.Out.WriteLine("interface:" + testMethodViaInterface.Name); if (implementingMethod != null) Console.Out.WriteLine("class:" + implementingMethod.Name); else Console.Out.WriteLine("class: unable to locate"); Console.Out.Write("Press enter to exit..."); Console.In.ReadLine(); } } } |
运行这个可以让我:
1 2 3 | interface: Test class: unable to locate Press enter to exit... |
在代码中有一个.getMethod调用,带有????评论。这部分是我需要帮助的。要么我需要在这里指定什么(我已经测试了很多,这让我想到了另一种方法),要么我需要用什么来替换这个代码。
因为我使用了接口中方法的显式实现,所以方法的实际名称不仅仅是"test"。如果使用以下代码转储类类型的getMethods()数组的全部内容:
1 2 3 4 5 | foreach (var mi in classType.GetMethods( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { Console.Out.WriteLine(mi.Name); } |
然后我得到这个:
1 2 3 4 5 6 7 | ConsoleApplication8.ITest.Test <-- this is the one I want ToString Equals GetHashCode GetType Finalize MemberwiseClone |
显然,该名称前面有接口及其命名空间的全名。但是,由于重载,我必须在类中找到所有这样的实现方法(即假设有多个测试方法随参数变化),然后比较参数。
有更简单的方法吗?基本上,我希望,一旦我有了接口方法的MethodInfo对象,通过获取其MethodInfo对象,找到实现此方法的类的确切方法。
请注意,这里的情况比较复杂,所以如果我必须循环使用类中的方法从接口中找到准确的方法,这是可以的,只要我有一个很好的方法来识别什么时候找到了正确的方法。
我试着这样改变上面的循环:
1 2 3 4 5 6 | foreach (var mi in classType.GetMethods( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { if (mi.GetBaseDefinition() == testMethodViaInterface) Console.Out.WriteLine(mi.Name); } |
这并没有打印出任何内容,因此很明显,此类方法上的
有指针吗?
为了将来参考,如果其他人感兴趣,这里@greg beech提供给我的解决方案是使用type.getinterfacemap。
下面是修改过的程序代码,底部有一个扩展方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | using System; using System.Linq; using System.Reflection; using System.Diagnostics; namespace ConsoleApplication8 { public interface ITest { void Test(); } public class Test : ITest { void ITest.Test() { throw new NotImplementedException(); } } class Program { static void Main(string[] args) { Type interfaceType = typeof(ITest); Type classType = typeof(Test); InterfaceMapping map = classType.GetInterfaceMap(interfaceType); MethodInfo testMethodViaInterface = interfaceType.GetMethods()[0]; MethodInfo implementingMethod = testMethodViaInterface.GetImplementingMethod(classType); Console.Out.WriteLine("interface:" + testMethodViaInterface.Name); if (implementingMethod != null) Console.Out.WriteLine("class:" + implementingMethod.Name); else Console.Out.WriteLine("class: unable to locate"); Console.Out.Write("Press enter to exit..."); Console.In.ReadLine(); } } public static class TypeExtensions { /// <summary> /// Gets the corresponding <see cref="MethodInfo"/> object for /// the method in a class that implements a specific method /// from an interface. /// </summary> /// <param name="interfaceMethod"> /// The <see cref="MethodInfo"/> for the method to locate the /// implementation of.</param> /// <param name="classType"> /// The <see cref="Type"/> of the class to find the implementing /// method for. /// </param> /// <returns> /// The <see cref="MethodInfo"/> of the method that implements /// <paramref name="interfaceMethod"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <para><paramref name="interfaceMethod"/> is <c>null</c>.</para> /// <para>- or -</para> /// <para><paramref name="classType"/> is <c>null</c>.</para> /// </exception> /// <exception cref="ArgumentException"> /// <para><paramref name="interfaceMethod"/> is not defined in an interface.</para> /// </exception> public static MethodInfo GetImplementingMethod(this MethodInfo interfaceMethod, Type classType) { #region Parameter Validation if (Object.ReferenceEquals(null, interfaceMethod)) throw new ArgumentNullException("interfaceMethod"); if (Object.ReferenceEquals(null, classType)) throw new ArgumentNullException("classType"); if (!interfaceMethod.DeclaringType.IsInterface) throw new ArgumentException("interfaceMethod","interfaceMethod is not defined by an interface"); #endregion InterfaceMapping map = classType.GetInterfaceMap(interfaceMethod.DeclaringType); MethodInfo result = null; for (Int32 index = 0; index < map.InterfaceMethods.Length; index++) { if (map.InterfaceMethods[index] == interfaceMethod) result = map.TargetMethods[index]; } Debug.Assert(result != null,"Unable to locate MethodInfo for implementing method"); return result; } } } |
看看