Уникальная идентификация метода или конструктора с помощью отражения


Мне нужно однозначно определить метод или конструктор для любого данного класса, чтобы я мог вызвать его на более позднем этапе.

Я думал использовать методы ConstructorInfo.GetHashCode() и MethodInfo.GetHashCode() в надежде, что хэш-код будет уникальным для каждого объекта, наследующего MethodBase. Хотя они уникальны, они также изменяются при каждом запуске программы , что означает, что этот метод бесполезен для меня, поскольку мне нужно сохранить объекты в базе данных, чтобы иметь возможность запустить его позже (т. е. после перезагрузки, сервис перезагрузки и т. д.).

Пока единственный способ, который я действительно могу придумать, чтобы однозначно идентифицировать методы и конструкторы, - это

  1. Сначала найдите список соответствующих методов / конструкторов по имени
  2. повторите соответствующие методы / конструкторы, чтобы увидеть, какой список параметров соответствует тому, который я хочу.

Есть ли лучший способ однозначно идентифицировать метод или конструктор с помощью отражения, которое существует в классе без необходимости первой итерации метода сопоставления имена, а затем повторение списка параметров, чтобы найти первое совпадение?

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;
        }
    }
}
2 2

2 ответа:

Включая предложения Стефана, вы можете определить класс метода расширения следующим образом:

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);
    }
}

Затем вы можете упростить сравнение следующим образом:

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

MethodInfo сериализуема. Это может быть полезно в вашем случае.

Смотритеэти примеры .

Недостатком этого является то, что у вас будут проблемы, когда вы обновите свои двоичные файлы до более новой версии и все еще хотите найти метод. (Для таких сценариев следует также не использовать имена методов.)