Вызов методов с необязательными параметрами посредством отражения

Я столкнулся с другой проблемой, используя C # 4.0 с дополнительными параметрами.

Как вызвать функцию (или, скорее, конструктор, у меня есть объект ConstructorInfo ), для которого я знаю, что он не требует каких-либо параметров?

Вот код, который я использую сейчас:

 type.GetParameterlessConstructor() .Invoke(BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod | BindingFlags.CreateInstance, null, new object[0], CultureInfo.InvariantCulture); 

(Я только что попробовал с разными BindingFlags ).

GetParameterlessConstructor – это специальный метод расширения, который я написал для Type .

5 Solutions collect form web for “Вызов методов с необязательными параметрами посредством отражения”

Согласно MSDN , чтобы использовать параметр по умолчанию, вы должны передать Type.Missing .

Если у вашего конструктора три необязательных аргумента, то вместо передачи пустого массива объектов вы должны передать массив из трех элементов, где каждое значение элемента – Type.Missing , например

 type.GetParameterlessConstructor() .Invoke(BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod | BindingFlags.CreateInstance, null, new object[] { Type.Missing, Type.Missing, Type.Missing }, CultureInfo.InvariantCulture); 

Необязательные параметры обозначаются обычным атрибутом и обрабатываются компилятором.
Они не влияют (кроме флага метаданных) на IL и не поддерживаются напрямую reflectionм (за исключением свойств IsOptional и DefaultValue ).

Если вы хотите использовать необязательные параметры с reflectionм, вам необходимо вручную передать их значения по умолчанию.

Я просто добавлю код … потому что. Я не согласен с этим кодом, но он довольно прямолинейный. Надеюсь, это поможет кому-то, кто спотыкается об этом. Он проверен, хотя, вероятно, не так хорошо, как вы хотели бы в производственной среде:

Вызов метода methodName для объекта obj с аргументами args:

  public Tuple Evaluate(IScopeContext c, object obj, string methodName, object[] args) { // Get the type of the object var t = obj.GetType(); var argListTypes = args.Select(a => a.GetType()).ToArray(); var funcs = (from m in t.GetMethods() where m.Name == methodName where m.ArgumentListMatches(argListTypes) select m).ToArray(); if (funcs.Length != 1) return new Tuple(false, null); // And invoke the method and see what we can get back. // Optional arguments means we have to fill things in. var method = funcs[0]; object[] allArgs = args; if (method.GetParameters().Length != args.Length) { var defaultArgs = method.GetParameters().Skip(args.Length) .Select(a => a.HasDefaultValue ? a.DefaultValue : null); allArgs = args.Concat(defaultArgs).ToArray(); } var r = funcs[0].Invoke(obj, allArgs); return new Tuple(true, r); } 

И функция ArgumentListMatches ниже, которая в основном заменяет логику, которая, вероятно, найдена в GetMethod:

  public static bool ArgumentListMatches(this MethodInfo m, Type[] args) { // If there are less arguments, then it just doesn't matter. var pInfo = m.GetParameters(); if (pInfo.Length < args.Length) return false; // Now, check compatibility of the first set of arguments. var commonArgs = args.Zip(pInfo, (margs, pinfo) => Tuple.Create(margs, pinfo.ParameterType)); if (commonArgs.Where(t => !t.Item1.IsAssignableFrom(t.Item2)).Any()) return false; // And make sure the last set of arguments are actually default! return pInfo.Skip(args.Length).All(p => p.IsOptional); } 

Множество LINQ, и это не было проверено на производительность!

Кроме того, это не будет обрабатывать общие вызовы функций или методов. Это делает это значительно более уродливым (как в повторных вызовах GetMethod).

С исходной структурой ImpromptuInterface с версии 4 вы можете использовать DLR в C # 4.0 для вызова конструкторов очень поздно, и он полностью знает конструкторы с именованными / необязательными аргументами, это выполняется в 4 раза быстрее, чем Activator.CreateInstance(Type type, params object[] args) и вам не нужно отражать значения по умолчанию.

 using ImpromptuInterface; using ImpromptuInterface.InvokeExt; 

 //if all optional and you don't want to call any Impromptu.InvokeConstructor(type) 

или

 //If you want to call one parameter and need to name it Impromptu.InvokeConstructor(type, CultureInfo.InvariantCulture.WithArgumentName("culture")) 

Все вопросы исчезают, как вы видите, что ваш код декомпилирован:

C #:

 public MyClass([Optional, DefaultParameterValue("")]string myOptArg) 

MSIL:

 .method public hidebysig specialname rtspecialname instance void .ctor([opt]string myOptArg) cil managed 

Как вы видите, необязательный параметр представляет собой реальный отдельный объект, который украшен определенными атрибутами и должен соблюдаться соответствующим образом при вызове посредством отражения, как описано выше.

  • C # Использование Reflection для копирования свойств базового classа
  • Насколько дорого стоит .NET-reflection?
  • GetMethod для общего метода
  • Как я могу оценивать выражение C # динамически?
  • В чем разница между a.getClass () и A.class в Java?
  • Получение атрибутов значения Enum
  • Получить имя и тип свойства, используя выражение lambda
  • Java ищет метод с конкретной аннотацией и элементом annotations
  • Как десериализация WCF создает объекты без вызова конструктора?
  • Я хочу получить тип переменной во время выполнения
  • Поиск различий свойств между двумя объектами C #
  • Давайте будем гением компьютера.