簡體   English   中英

如何通過反射執行帶有可選參數的私有靜態方法?

[英]How to execute a private static method with optional parameters via reflection?

我有一個帶有可選參數的私有靜態方法的類。 如何通過反射從另一個類調用它? 有一個類似的問題,但它沒有解決靜態方法或可選參數。

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

我如何調用Foo.Bar("test")Foo.Bar() (例如,不傳遞可選參數)?

C# 中的可選參數值是通過在調用站點注入這些值來編譯的。 即即使你的代碼是

Foo.Bar()

編譯器實際上會生成一個類似的調用

Foo.Bar("")

在查找方法時,您需要將可選參數視為常規參數。

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

如果您確切知道要使用哪些值調用該方法,則可以執行以下操作:

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

如果您只有一些參數並希望遵守默認參數的值,則必須檢查方法的ParameterInfo對象以查看參數是否可選以及這些值是什么。 例如,要打印出這些參數的默認值,您可以使用以下代碼:

foreach (ParameterInfo pi in method.GetParameters())
{
    if (pi.IsOptional)
    {
        Console.WriteLine(pi.Name + ": " + pi.DefaultValue);
    }
}

使用這個類

  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);

如果該方法有一些非可選參數,則必須在調用該方法之前將它們插入到參數數組中。

例如

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

會要求你做

parameters[0] = "23"

調用前

我為單元測試寫的東西:

    /// <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);

免責聲明:我僅將此用於具有返回值的函數。 嘗試執行沒有返回值的方法將引發異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM