Как использовать Reflection для вызова метода, который принимает массив строк в качестве аргумента в C#

У меня есть метод, как показано ниже...

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

    }

Я должен вызывать этот метод, используя Reflection, из-за способа настройки всей структуры.

Вот код, который я использую для его вызова

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)

тогда это работает. Кто-нибудь может указать мне правильное направление при вызове функции, которая принимает массив в качестве параметра?

5 ответов

Решение

Вы должны передать ему массив, содержащий ваш массив:

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

Ваш неправильный код компилируется из-за ковариации массива, как указал Эрик Липперт в своем ответе.

C# поддерживает ковариацию типа элемента массива для массивов, где тип элемента является ссылочным типом. То есть вы можете автоматически конвертировать string[] в object[],

Итак, что здесь происходит, вы передаете массив строк, и среда выполнения говорит: "А, это тот массив объектов, который я ожидал", и теперь каждая строка передается в качестве аргумента, а не передается массив строк в качестве аргумента.

Хитрость заключается в том, чтобы создать массив объектов, который содержит массив строк, а не тот, который идентичен массиву строк.

Вам просто нужно поместить строковые аргументы в object-array.

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

Причина, по которой вам нужно это сделать, заключается в том, что InvokeMember занимает object-array как параметр, поэтому ваш массив строк преобразуется в массив объектов, и каждая строка представляет собой один параметр.

Ваше внутреннее значение неверно.

В массиве 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 });
Другие вопросы по тегам