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