Getting a Generic MethodInfo with “Type.GetMethod()” is not really possible. That’s why I wrote this little Function which helps finding any Methods and return it’s correct MethodInfo on which you then can Invoke on.
/// <summary>
/// Finds a Method with the given Specifications
/// </summary>
/// <example>
/// MethodInfo mi;
/// ParameterInfo[] parameters;
/// FindMethod(this.GetType(), "Save", new Type[] { typeof(int) }, new Type[] { typeof(DataRow) }, out mi, out parameters);
/// mi.Invoke(this, new object[] { row });
/// </example>
/// <param name="type">The Type which holds the Method</param>
/// <param name="methodName">The Name of the Method</param>
/// <param name="typeArguments">Generic Type List or Null if not Generic</param>
/// <param name="parameterTypes">Parameter Type List or Null if no Parameters</param>
/// <param name="methodInfo">The returned MethodInfo</param>
/// <param name="parameters">The returned ParameterInfo List</param>
/// <returns>True if found, false otherwise</returns>
private static bool FindMethod(Type type, string methodName, Type[] typeArguments, Type[] parameterTypes, out MethodInfo methodInfo, out ParameterInfo[] parameters)
{
// Reset the Out Parameters
methodInfo = null;
parameters = null;
if (typeArguments == null)
{
// Non-Generic Method
methodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null);
}
else
{
// Generic Method
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
// Loop thru all Methods
foreach (MethodInfo method in methods)
{
if (method.Name != methodName)
{
// Name does not match
continue;
}
if (!method.IsGenericMethod)
{
// Non-Generic
continue;
}
// Compare the Method Parameters
bool paramsOk = false;
if (method.GetParameters().Length == parameterTypes.Length)
{
// Count Matches
paramsOk = true;
// Check each Type
for (int i = 0; i < method.GetParameters().Length; i++)
{
if (method.GetParameters()[i].ParameterType != parameterTypes[i])
{
// Parameter Type doesn't Match
paramsOk = false;
break;
}
}
}
if (!paramsOk)
{
// Parameters didn't match
continue;
}
// Check the Generic Arguments
bool argsOk = false;
if (method.GetGenericArguments().Length == typeArguments.Length)
{
// Count Matches
argsOk = true;
// TODO: Check for "where" Limitation in the Generic Definition
}
if (!argsOk)
{
// Generic Arguments didn't match
continue;
}
// If we're here, we got the right Method
methodInfo = method.MakeGenericMethod(typeArguments);
break;
}
}
if (null == methodInfo)
{
return false;
}
else
{
parameters = methodInfo.GetParameters();
return true;
}
}
#
Regarding:
// TODO: Check for “where” Limitation in the Generic Definition
You should not check for the where, because the generic argument constraints aren’t actually used to resolve method overloads.
This extension method has worked very well for me so far:
public static MethodInfo GetGenericMethod(this Type type, string name, int genericArguments, params Type[] parameterTypes)
{
return (from method in type.GetMethods()
where method.Name == name
where parameterTypes.SequenceEqual(method.GetParameters().Select(p => p.ParameterType))
where method.GetGenericArguments().Count() == genericArguments
select method).Single();
}
In my case I need to keep the generic MethodInfo because I then call MakeGenericMethod() for each type I encounter while emitting IL into a dynamic method.
Happy coding!
Alex G