Search code examples
c#reflectionmethodinfo

Uniquely identifying a method or constructor using reflection


I need to uniquely identify a method or constructor for any given class so that I can then invoke it at a later stage.

I had thought of using the ConstructorInfo.GetHashCode() and MethodInfo.GetHashCode() methods in the hope that the hashcode would be unique for each object inhertiting MethodBase. While they are unique they also change on each run of the program which means this method is useless to me as I need to persist the objects to database to be able to run it later (i.e. after reboots, service restarts etc).

So far, the only way I can really come up with to uniquely identify the methods and constructors is to

  1. Find a list of matching methods/constructors by name first
  2. Iterate the matching methods/constructors to see which parameter list matches the one I want.

Is there a better way of uniquely identifying a method or constructor using reflection that exists in a class without having to first iterate the matching method names and then iterating the parameter list to find the first match?

methodParams = null;
constructorInfo = null;

var methods = instanceType.GetMethods().Where(m => m.Name == constructorName);//this is required to handle methods that are overloaded
foreach (var method in methods)
{
    var internalParams = method.GetParameters();
    if (internalParams.Count() == requiredParams.Count())
    {
        var methodParamDict = internalParams.ToDictionary(x => x.Name, x => String.Empty);
        foreach (var requiredParamKey in requiredParams.Keys)
        {
            if (methodParamDict.ContainsKey(requiredParamKey))
            {
                methodParamDict[requiredParamKey] = requiredParams[requiredParamKey];
            }
        }
        if (methodParamDict.All(x => x.Value != String.Empty))
        {
            //set the methodParams to internalParams (i.e. we have found the correct overloaded method)
            methodParams = internalParams;
            constructorInfo = method as ConstructorInfo;
        }
    }
}

Solution

  • Including Stefan's suggestions, you could define an extension method class like this one:

    public static class CustomReflectionHelpers
    {
        public static String CreateUniqueName(this MethodInfo mi)
        {
            String signatureString = String.Join(",", mi.GetParameters().Select(p => p.ParameterType.Name).ToArray());
            String returnTypeName = mi.ReturnType.Name;
    
            if (mi.IsGenericMethod)
            {
                String typeParamsString = String.Join(",", mi.GetGenericArguments().Select(g => g.AssemblyQualifiedName).ToArray());
    
    
                // returns a string like this: "Assembly.YourSolution.YourProject.YourClass:YourMethod(Param1TypeName,...,ParamNTypeName):ReturnTypeName
                return String.Format("{0}:{1}<{2}>({3}):{4}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, typeParamsString, signatureString, returnTypeName);
            }
    
            return String.Format("{0}:{1}({2}):{3}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, signatureString, returnTypeName);
        }
    }
    

    You can then simplify the comparison like this:

    foreach (MethodInfo mi in yourType.GetMethods())
    {
        if (mi.CreateUniqueName() == stringStoredInDb) { /* do something */ }
    }