为什么使用 Method Invoke 方法会失败并出现参数异常?

3

考虑这个来自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;
        }
    }

当你点击按钮1时,控制台会打印出“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方法的签名也明确期望一个对象数组。那么为什么调用会将数组中的第一个对象取出并尝试传递它呢?

或者还有其他我不理解的情况吗?

4个回答

6
MethodInfo.Invoke 需要一个对象数组作为参数,对象数组中的每个对象对应方法的一个参数。对象数组中的第一个对象是方法的第一个参数,对象数组中的第二个对象是方法的第二个参数,以此类推。
因为您希望方法的第一个参数是一个 object[] 数组,所以您需要确保传递给 MethodInfo.Invoke 的对象数组的第一个对象 是一个表示 DoSomething 应该使用的数组的对象数组

1
现在这很有道理 - 当然它会这样工作。是时候离开键盘几分钟了 :-) - Gojira

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

使用:

public static string DoSomething(object[] parms)

这就是问题所在:第一个参数不是一个string,而是一个object[]。你传递给Invoke方法的object[]依次表示每个参数,因此长度为1且包含字符串的object[]可以匹配static string DoSomething(string s),但不能匹配你的方法。要么改变方法签名,要么将值包装起来。坦率地说,我建议在这里更改方法签名是更好的想法,但:

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

也将起作用。


1

参数明显是一个对象数组,DoSomething的方法签名也明确期望一个对象数组。

是的,它期望一个对象数组。但是当你传递这个:

object[] parms = new object[1];

你所说的是调用 DoSomething 方法的参数,所以 parms[0] 是传递给 DoSomething 的第一个参数,如果 parms 中有更多的项,则 parms[1] 将是第二个参数,依此类推。
显然,DoSomething 的第一个参数不是 string(parms[0]),因此会出现以下错误:
引发了 System.ArgumentException 异常,位于 mi.Invoke(null, parms) 行(无法将类型为“System.String”的对象转换为类型“System.Object[]”。)

1

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

由于您的函数也期望一个对象数组作为参数,因此您正在传递的不是对象数组而是字符串。

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接