Получить метод с одним или без атрибутов с отражением в C#
Я изучаю Reflection и работаю над сериализуемым типом действия, который можно сохранить, а затем загрузить и запустить. Сериализуемое действие поддерживает методы без параметров или одного параметра типа int, float, double, string или bool.
Все методы, имена которых передаются, имеют либо один атрибут из перечисленных выше типов, либо вообще не имеют атрибутов, они также могут иметь один атрибут со значением по умолчанию. И вот идут мои проблемы. Прежде всего, я получаю AmbiguousMatchException, когда я звоню target.GetType().GetMethod(methodName);
для метода, который имеет перегрузки, и я получаю NULL, если я вызываю его для метода с одним необязательным параметром.
Итак, сейчас я начинаю с try-catch, чтобы поймать исключение AmbiguousMatchException, которое затем сообщает мне, что данный метод имеет перегрузки. Если я получаю исключение, я начинаю пытаться заставить метод передавать массивы различных типов атрибутов для поиска:
public static MethodInfo GetMethod(string methodName, Object _target)
{
try
{
MethodInfo info = _target.GetType().GetMethod(methodName);
return info;
}
catch (AmbiguousMatchException ex)
{
MethodInfo info = _target.GetType().GetMethod(methodName, new System.Type[0]);
if (info != null) return info;
info = _target.GetType().GetMethod(methodName, new[] { typeof(int) });
if (info != null) return info;
info = _target.GetType().GetMethod(methodName, new[] { typeof(float) });
if (info != null) return info;
info = _target.GetType().GetMethod(methodName, new[] { typeof(double) });
if (info != null) return info;
info = _target.GetType().GetMethod(methodName, new[] { typeof(string) });
if (info != null) return info;
info = _target.GetType().GetMethod(methodName, new[] { typeof(bool) });
return info;
}
}
Это очень уродливо, но хорошо работает для перегруженных методов. Однако он возвращает NULL, если метод имеет необязательный параметр. Я пытался использовать флаг привязки OptionalParamBinding, но он возвращал NULL даже для методов без перегрузок и одного необязательного параметра.
Итак, мой вопрос: как я могу это сделать? Мне нужен этот статический метод, чтобы найти: - Перегрузку метода с параметром int, float, double, string или bool - Если это не удастся, перегрузку с необязательным параметром int, float, double, string или bool - И если это не удается перегрузить без параметров
1 ответ
Для ваших конкретных требований это довольно легко сделать в запросе LINQ.
var validParameterTypes = new HashSet<Type> { typeof(int), typeof(float), ... };
var methods = from method in _target.GetType().GetMethods()
let parameters = method.GetParameters()
let hasParameters = parameters.Length > 0
let firstParameter = hasParameters ? parameters[0] : null
let isOptionalParameter = (hasParameters && firstParameter.IsOptional) ? true : false
where method.Name == methodName &&
(!hasParameters || validParameterTypes.Contains(firstParameter.ParameterType))
orderby parameters.Length descending, isOptionalParameter
select method;
В этот момент вы оцениваете методы по мере их появления в запросе и проверяете, соответствуют ли они вашим потребностям.
Однако есть другой вопрос: "Должен ли я так поступить?". TyCobb уже упоминал об этом в своем комментарии, и он прав.
Нынешний способ, которым вы пытаетесь что-то сделать, - это много работы без немедленной выгоды. Таким образом, вы получите список перегрузок, которые на самом деле вам не помогут. Теперь вам нужно самостоятельно разрешить перегрузку и найти "лучшую" перегрузку для вызова (или просто взять первую найденную, но она может очень легко сломаться, если методы будут добавлены / удалены / изменены).
Предположим, что вы также сохранили тип параметра (если есть), который вы ищете. Знание того, что сократит ваш код до этого:
var parameterTypes = (knownParameterType == null ) ? Type.EmptyTypes : new[] { knownParameterType };
var method = _target.GetType().GetMethod(methodName, parameterTypes);
Проще, чище и вернее правильно! Вам даже не нужно проверять допустимые типы параметров здесь, заставьте их сделать это как часть создания действительного "типа действия", который вы определяете.