Как использовать 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 });