如何通过反射执行带有可选参数的私有静态方法
本文关键字:参数 静态方法 反射 执行 行带 何通过 | 更新日期: 2023-09-27 18:11:40
我有一个带有可选参数的私有静态方法的类。我如何通过反射从另一个类调用它?还有一个类似的问题,但它不涉及静态方法或可选参数。
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);
免责声明:我只将此用于具有返回值的函数。尝试执行没有返回值的方法将抛出异常。