如何在C#中使用Reflection来调用以字符串数组为参数的方法

本文关键字:数组 字符串 参数 方法 调用 Reflection | 更新日期: 2023-09-27 18:26:59

我有一个如下所示的方法。。。

public bool MakeRequest(string[] args)
    {
        try
        {
            sXmlRequest = args[0];
            sResponse = "";
            Console.WriteLine(sXmlRequest);
            sw.Write(sXmlRequest);
            sw.Flush();
            sResponse = sr.ReadToEnd();
            return true;
        }
        catch (Exception e)
        {
            sResponse = e.Message;
            return false;
        }
    }

由于整个框架的设置方式,我必须使用反射来调用此方法。

这是我用来称之为的代码

string[] innerargs = {"Dummy Args"};
string pAssembly = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "''TCPConnector.dll";
Assembly assemblyInstance = Assembly.LoadFrom(pAssembly);
Type tConnector = assemblyInstance.GetType("Fit.TcpConnector");
Object oLateBound = assemblyInstance.CreateInstance(tConnector.FullName);
result = tConnector.InvokeMember("MakeRequest", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, oLateBound, innerargs);

这将返回MissingMethodException,表示找不到Fit.TcpConnector.MakeRequest方法。

但是,如果我将MakeRequest的签名更改为

  public bool MakeRequest(string args)

而不是

  public bool MakeRequest(string[] args)

然后,它开始发挥作用。在调用以数组为参数的函数时,有人能告诉我正确的方向吗?

如何在C#中使用Reflection来调用以字符串数组为参数的方法

C#在元素类型为引用类型的数组上支持数组元素类型协方差。也就是说,您可以自动将string[]转换为object[]

所以这里发生的是,你传递一个字符串数组,运行时说"啊,这是我期望的对象数组",现在每个字符串都作为参数传递,而不是作为参数传递字符串数组

诀窍是使包含的对象数组成为字符串数组,而不是使与字符串数组相同的对象数组。

您必须向它传递一个包含您的数组的数组:

tConnector.InvokeMember(
    "MakeRequest",
    BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
    null, oLateBound, new object[] { innerargs });

这是因为传递给方法的数组中的每个项都代表函数的一个参数。由于函数有一个类型为string[]的参数,因此需要给它一个包含一个类型string[]项的数组。

话虽如此,我认为使用GetMethod()Invoke()InvokeMember():更清晰

var makeRequestMethod = tConnector.GetMethod("MakeRequest");
makeRequestMethod.Invoke(oLateBound, new object[] { innerargs });

正如Eric Lippert在回答中指出的那样,您的错误代码编译是因为数组协方差。

您只需要将字符串参数放入object数组中。

new Object[] { new String[] { "Mytext" } }

之所以需要这样做,是因为InvokeMember将一个object-数组作为参数,因此您的字符串数组被转换为对象数组,并且每个字符串都作为一个单独的参数受到威胁。

您的innerargs值是错误的。

在innerargs数组中,每个对象表示一个参数

所以你真的应该做

string[] innerargs = {"Dummy Args"};
object[] arg = {innerargs];
result = tConnector.InvokeMember("MakeRequest", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, oLateBound, arg );

或者诸如此类的。

args参数是要传递给成员的参数数组,因此如果您的成员参数是一个数组,则需要将其封装在另一个数组中,否则它将假设您只发送一个字符串参数:

result = tConnector.InvokeMember("MakeRequest", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, oLateBound, new object[] { innerargs });