【问题标题】:How to execute a private static method with optional parameters via reflection?如何通过反射执行带有可选参数的私有静态方法?
【发布时间】:2011-12-11 09:12:26
【问题描述】:

我有一个带有可选参数的私有静态方法的类。如何通过反射从另一个类调用它?有一个类似的question,但它没有解决静态方法或可选参数。

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

如何调用Foo.Bar("test") 和Foo.Bar()(例如,不传递可选参数)?

【问题讨论】:

    标签: c# reflection c#-4.0 .net-4.0 optional-parameters


    【解决方案1】:

    我为我的单元测试写的东西:

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

    免责声明:我仅将其用于具有返回值的函数。尝试执行没有返回值的方法会抛出异常。

    【讨论】:

      【解决方案2】:

      使用这个类

        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"
      

      调用前

      【讨论】:

        【解决方案3】:

        C# 中的可选参数值是通过在调用点注入这些值来编译的。 IE。即使您的代码是

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

        【讨论】:

        • 静态方法部分呢?
        猜你喜欢
        • 2011-01-26
        • 2013-04-23
        • 1970-01-01
        • 2012-07-14
        • 2019-09-02
        • 2012-04-16
        • 2016-05-26
        • 1970-01-01
        • 2014-04-20
        相关资源
        最近更新 更多