Как выполнить частный статический метод с дополнительными параметрами через отражение?

У меня есть класс с частным статическим методом с необязательным параметром. Как мне вызвать его из другого класса через Reflection? Есть аналогичный вопрос, но он не обращается к статическому методу или необязательным параметрам.

public class Foo {
    private static void Bar(string key = "") {
       // do stuff
    }
}

Как вызвать Foo.Bar("test") и Foo.Bar() (например, без передачи необязательного параметра)?


person AngryHacker    schedule 19.10.2011    source источник


Ответы (3)


Значения необязательных параметров в C # компилируются путем внедрения этих значений на сайт вызова. Т.е. даже если ваш код

Foo.Bar()

Компилятор фактически генерирует вызов типа

Foo.Bar("")

При поиске метода необязательные параметры следует рассматривать как обычные параметры.

var method = typeof(Foo).GetMethod("Bar", BindingFlags.Static | BindingFlags.NonPublic);

Если вы точно знаете, с какими значениями вы хотите вызвать метод, вы можете:

method.Invoke(obj: null, parameters: new object[] { "Test" });

Если у вас есть только некоторые параметры и вы хотите соблюдать значения по умолчанию, вам необходимо проверить метод _ 5_, чтобы узнать, являются ли параметры необязательными и каковы эти значения. Например, чтобы распечатать значения этих параметров по умолчанию, вы можете использовать следующий код:

foreach (ParameterInfo pi in method.GetParameters())
{
    if (pi.IsOptional)
    {
        Console.WriteLine(pi.Name + ": " + pi.DefaultValue);
    }
}
person marcind    schedule 19.10.2011
comment
А как насчет части статического метода? - person AngryHacker; 20.10.2011

Используя этот класс

  public class Foo
  {
    private static void Bar(string key = "undefined key", string value = "undefined value")
    {
      Console.WriteLine(string.Format("The key is '{0}'", key));
      Console.WriteLine(string.Format("The value is '{0}'", value));
    }
  }

Вы можете использовать следующий код, чтобы вызвать его со значениями по умолчанию

  MethodInfo mi = typeof(Foo).GetMethod("Bar", BindingFlags.NonPublic | BindingFlags.Static);
  ParameterInfo[] pis = mi.GetParameters();

  object[] parameters = new object[pis.Length];

  for (int i = 0; i < pis.Length; i++)
  {
    if (pis[i].IsOptional)
    {
      parameters[i] = pis[i].DefaultValue;
    }
  }

  mi.Invoke(null, parameters);

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

E.g

private static void Bar(int number, string key = "undefined key", string value = "undefined")

Потребует от вас сделать

parameters[0] = "23"

Перед вызовом

person wdavo    schedule 20.10.2011

Что-то, что я написал для своих модульных тестов:

    /// <summary>
    /// Attempts to execute a function and provide the result value against the provided source object even if it is private and/or static. Just make sure to provide the correct BindingFlags to correctly identify the function.
    /// </summary>
    /// <typeparam name="TReturn">The expected return type of the private method.</typeparam>
    /// <param name="type">The object's Type that contains the private method.</param>
    /// <param name="source">The object that contains the function to invoke. If looking for a static function, you can provide "null".</param>
    /// <param name="methodName">The name of the private method to run.</param>
    /// <param name="flags">Binding flags used to search for the function. Example: (BindingFlags.NonPublic | BindingFlags.Static) finds a private static method.</param>
    /// <param name="output">The invoked function's return value.</param>
    /// <param name="methodArgs">The arguments to pass into the private method.</param>
    /// <returns>Returns true if function was found and invoked. False if function was not found.</returns>
    private static bool TryInvokeMethod<TReturn>(Type type, object source, string methodName, BindingFlags flags, out TReturn output, params object[] methodArgs)
    {
        var method = type.GetMethod(methodName, flags);
        if(method != null)
        {
            output = (TReturn)method.Invoke(source, methodArgs);
            return true;
        }

        // Perform some recursion to walk the inheritance. 
        if(type.BaseType != null)
        {
            return TryInvokeMethod(type.BaseType, source, methodName, flags, out output, methodArgs);
        }

        output = default(TReturn);
        return false;
    }

Затем вызовите его так, чтобы вызвать частную статическую функцию:

var success = TryInvokeMethod(typeof(Foo), null, "MyPrivateStaticFunc", BindingFlags.NonPublic | BindingFlags.Static, out result, arg1ToPass);

Отказ от ответственности: я использую это только для функций с возвращаемым значением. Попытка выполнить метод без возвращаемого значения вызовет исключение.

person used2could    schedule 23.05.2020