Нахождение хостинга PropertyInfo из MethodInfo метода получения / установки

Я делаю анализ типов во время выполнения, используя Reflection. Если у меня есть экземпляр MethodInfo, как я могу выяснить, является ли это "реальным" методом или методом получения / установки свойства? И если это собственность, как я могу найти ее хостинг PropertyInfo обратно?

6 ответов

Решение

Ecma 335 указывает (но не требует), чтобы компиляторы использовали префиксы get_/set_ (глава 22.28). Я не знаю ни одного языка, который нарушает эту рекомендацию. Сделать это легко:

public static PropertyInfo GetPropFromMethod(Type t, MethodInfo method) {
  if (!method.IsSpecialName) return null;
  return t.GetProperty(method.Name.Substring(4), 
    BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
}

Ну, метод, стоящий за геттером и сеттером, является "реальным" методом.

Повторное отслеживание обратно к свойству - шаблон (возврат против 1 аргумента) поможет сузить его - но вам придется вызывать GetGetMethod/GetSetMethod для каждого, чтобы найти свойство.

Вы могли бы попробовать Name (меньше get__/set__) - но это кажется хрупким. Вот более длинная версия (не использовать Name):

static PropertyInfo GetProperty(MethodInfo method)
{
    bool takesArg = method.GetParameters().Length == 1;
    bool hasReturn = method.ReturnType != typeof(void);
    if (takesArg == hasReturn) return null;
    if (takesArg)
    {
        return method.DeclaringType.GetProperties()
            .Where(prop => prop.GetSetMethod() == method).FirstOrDefault();
    }
    else
    {
        return method.DeclaringType.GetProperties()
            .Where(prop => prop.GetGetMethod() == method).FirstOrDefault();
    }
}

Я бы очень хотел оставить это как комментарий, но не могу, так как мой представитель недостаточно высок:(

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

    [Pure]
    public static PropertyInfo GetParentProperty(this MethodInfo method)
    {
        if (method == null) throw new ArgumentNullException("method");
        var takesArg = method.GetParameters().Length == 1;
        var hasReturn = method.ReturnType != typeof(void);
        if (!(takesArg || hasReturn)) return null;

        if (takesArg && !hasReturn)
        {
            return method.DeclaringType.GetProperties().FirstOrDefault(prop => prop.GetSetMethod() == method);
        }
        else
        {
            return method.DeclaringType.GetProperties().FirstOrDefault(prop => prop.GetGetMethod() == method);
        }
    }

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

Насколько мне известно, нет способа найти PropertyInfo без перебора свойств и сравнения методов.

Для современного .NET я считаю, что следующий ответ эквивалентен ответу Марка, но более лаконичен и, возможно, немного более эффективен. Я может что-то пропустил.

      public static PropertyInfo? GetPropertyInfo(this MethodInfo getSetMethodInfo) 
    => getSetMethodInfo.DeclaringType?.GetProperties()
    .FirstOrDefault(prop => prop.GetSetMethod() == getSetMethodInfo 
    || prop.GetGetMethod() == getSetMethodInfo);

Трюк, с которым можно поиграть, это BindingFlags.DeclaredOnly и IsSpecialName

Другие вопросы по тегам