为什么方法调用会因参数异常而失败?

Why does Method Invoke fail with argument exception?

考虑来自 WinForms 应用程序的代码示例:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            object[] parms = new object[1];
            parms[0] = "foo";

            DoSomething(parms);
        }

        public static string DoSomething(object[] parms)
        {
            Console.WriteLine("Something good happened");
            return null;
        }
    }

它按预期工作,当您单击 button1 时,它会在控制台上打印 "Something good happened"。

现在考虑这个代码示例,它除了使用反射调用 DoSomething 之外是相同的:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            object[] parms = new object[1];
            parms[0] = "foo";

            System.Reflection.MethodInfo mi = typeof(Form1).GetMethod("DoSomething");
            mi.Invoke(null, parms);

        }

        public static string DoSomething(object[] parms)
        {
            Console.WriteLine("Something good happened");
            return null;
        }
    }

它在行 mi.Invoke(null, parms) 上抛出一个 System.ArgumentException(类型 'System.String' 的对象无法转换为类型 'System.Object[]'。)

parms 显然是一个对象数组,而 DoSomething 的方法签名显然需要一个对象数组。那么为什么 invoke 将第一个对象从数组中拉出并试图传递它呢?

或者是其他我不理解的事情发生了?

object[] parms = new object[1];
parms[0] = "foo";

与:

public static string DoSomething(object[] parms)

这就是问题所在;第一个参数不是 string - 它是 object[]。您传递给 Invokeobject[] 依次表示 每个参数 ,因此长度为 1 的 object[] 与字符串将匹配 static string DoSomething(string s),但与您的方法不符。要么更改签名,要么包装值。坦率地说,我建议在这里更改签名是更好的主意,但是:

parms[0] = new object[] { "foo" };

也可以

MethodInfo.Invoke 需要一个对象数组,其中对象数组中的每个对象对应于方法 的一个参数。对象数组中的第一个参数是第一个参数,数组中的第二个对象是第二个方法,等等

由于您希望方法的第一个参数是 object[],因此您需要确保传递给 MethodInfo.Invoke 的对象数组中的第一个对象是表示 DoSomething 应该使用的数组的对象数组

MethodInfo.Invoke 期望一个对象数组作为参数将多个参数传递给函数,数组中的每个对象将是一个不同的参数。

由于您的函数还需要一个对象数组,您作为参数传递的不是对象数组而是字符串。

您必须将该数组包装到另一个数组中,这样 Invoke 将打开第一个数组并将内部数组用作调用的第一个参数。

mi.Invoke(null, new object[]{ parms });

parms is clearly an object array, and DoSomething's method signature is clearly expecting an object array.

是的,它需要一个对象数组。但是当你通过这个时:

object[] parms = new object[1];

你说这些是 DoSomething 的参数,所以 parms[0] 是 DoSomething 的第一个参数,如果 parms 中有更多项目,那么 parms[1]将是第二个参数,依此类推。

很明显 DoSomething 的第一个参数不是 string (parms[0]) 所以你得到这个错误:

It throws an System.ArgumentException on the line mi.Invoke(null, parms) (Object of type 'System.String' cannot be converted to type 'System.Object[]'.)