呼叫类型.使用泛型方法的接口上的GetRuntimeMethod返回null
本文关键字:GetRuntimeMethod 返回 null 接口 呼叫 泛型方法 类型 | 更新日期: 2023-09-27 18:05:59
我在我的一个c#项目中使用反射:它是针对Windows 8.1和Windows Phone 8.1的便携式类库。
在那个项目中,我有一个名为IMyInterface的接口,它有一个带泛型参数TGenericObject的方法DoSomething。我还有一个名为MyClass的类。在某一点上,我需要通过反射查找指定接口中的DoSomething方法。所以,我使用的是Type类的GetRuntimeMethod方法和实际参数的类型,在我的例子中是MyClass。
请记住,我在这里提供的例子只是为了突出我所面临的问题。实际情况是接口IMyInterface和类MyClass在另一个项目中。
这里是交易:我期待GetRuntimeMethod返回DoSomething方法的MethodInfo,但它没有:返回null。
是否有一些容易的东西,我错过了从IMyInterface找到DoSomething方法,或者我必须让手更脏?
public interface IMyInterface
{
void DoSomething<TGenericObject>(TGenericObject myGenericObject);
}
public class MyClass
{ }
class Program
{
static void Main(string[] args)
{
MyClass myClassInst = new MyClass();
MethodInfo methodInfo = typeof (IMyInterface).GetRuntimeMethod("DoSomething", new [] { myClassInst.GetType() });
}
}
我能够编写我自己的扩展方法,实际做我期望从GetRuntimeMethod方法。困扰我的是,我仍然不明白为什么。net提供的GetRuntimeMethod方法在我的示例中返回null。
这是暂时解决我的问题的不完整类。这是一个非常幼稚的方法,但它是一个起点。那门课有很多东西没讲,但至少,它是一个让我能继续讲下去的答案。
public static class TypeExtensions
{
#region Public Methods
/// <summary>
/// Looks for the method in the type matching the name and arguments.
/// </summary>
/// <param name="type"></param>
/// <param name="methodName">
/// The name of the method to find.
/// </param>
/// <param name="args">
/// The types of the method's arguments to match.
/// </param>
/// <returns></returns>
/// <exception cref="ArgumentNullException">
/// Thrown if:
/// - The name of the method is not specified.
/// </exception>
public static MethodInfo GetRuntimeMethod(this Type type, string methodName, Type[] args)
{
if (ReferenceEquals(type, null))
throw new NullReferenceException("The type has not been specified.");
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("methodName", "The name of the method has not been specified.");
var methods = type.GetRuntimeMethods().Where(methodInfo => string.Equals(methodInfo.Name, methodName, StringComparison.OrdinalIgnoreCase)).ToList();
if (!methods.Any())
return null; // No methods have the specified name.
if (methods.Count == 1)
{
MethodInfo methodInfo = methods.Single();
return IsSignatureMatch(methodInfo, args) ? methodInfo : null;
}
// Oh noes, don't make me go there.
throw new NotImplementedException("Resolving overloaded methods is not implemented as of now.");
}
#endregion
#region Private Methods
/// <summary>
/// Finds out if the provided arguments matches the specified method's signature.
/// </summary>
/// <param name="methodInfo"></param>
/// <param name="args"></param>
/// <returns></returns>
private static bool IsSignatureMatch(MethodBase methodInfo, Type[] args)
{
Debug.Assert(!ReferenceEquals(methodInfo, null), "The methodInfo has not been specified.");
// Gets the parameters of the method to analyze.
ParameterInfo[] parameters = methodInfo.GetParameters();
int currentArgId = 0;
foreach (ParameterInfo parameterInfo in parameters)
{
if (!ReferenceEquals(args, null) && currentArgId < args.Length)
{
// Find out if the types matchs.
if (parameterInfo.ParameterType == args[currentArgId])
{
currentArgId++;
continue; // Yeah! Try the next one.
}
// Is this a generic parameter?
if (parameterInfo.ParameterType.IsGenericParameter)
{
// Gets the base type of the generic parameter.
Type baseType = parameterInfo.ParameterType.GetTypeInfo().BaseType;
// TODO: This is not good v and works with the most simple situation.
// Does the base type match?
if (args[currentArgId].GetTypeInfo().BaseType == baseType)
{
currentArgId++;
continue; // Yeah! Go on to the next parameter.
}
}
}
// Is this parameter optional or does it have a default value?
if (parameterInfo.IsOptional || parameterInfo.HasDefaultValue)
continue; // Uhum. So let's ignore this parameter for now.
// No need to go further. It does not match :(
return false;
}
// Ye!
return true;
}
#endregion
}