Нахождение хостинга 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