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
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;
}
}
}
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 */ }
}