Почему я не могу получить значение для параметров типа out или ref, используя Type.InvokeMember?

Долгое название, но я хотел, чтобы он был конкретным. Название действительно вопрос. Несмотря на то, что метод, вызываемый InvokeMember, имеет параметр out и присваивает значение этому параметру, я не могу захватить это значение. Вот код, который я изначально использовал:

string parameter = "";
int result = Convert.ToInt32(typeof(Ability).InvokeMember(selectedMove, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { parameter }));

Я изменил его, что теперь делает его работу по назначению, но я не знаю, почему:

object[] args = new object[1]; //necessary to retrieve ref/out parameter
int result = Convert.ToInt32(typeof(Ability).InvokeMember(selectedMove, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, args));
3 ответа

В вашем первом примере кода вызов InvokeMember не изменяет значение переменной parameter, он просто заменяет первый элемент массива параметров (который теперь указывает на другой экземпляр string), Поскольку вы не сохранили ссылку на этот массив, вы не можете получить значение выходного параметра.

Другими словами: массив сначала содержит копию переменной parameter (т.е. копию ссылки на пустую строку). После вызова parameter и значение в массиве ссылаются на 2 разных экземпляра строки.


Я просто хотел помочь кому-то, кто борется (я сделал) с неуправляемым (COM) и возвращать параметр ref. Таким образом, при использовании InvokeMember против COM-метода вы должны указать, какие аргументы ref-type. Это достигается с помощью параметра ParameterModifier-class, например:

object[] args = new object[3] { param1, param2, errorStr };
ParameterModifier pMod = new ParameterModifier(3);
pMod[2] = true; 
ParameterModifier[] mods = { pMod };
object tempObj = myCOMObject.GetType().InvokeMember("MyCOMMethod", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public, null, myCOMObject, args, mods, null, null);

В приведенном выше коде третий аргумент устанавливается как ссылка (pMod [2] = true;)


В вашем втором фрагменте отсутствует довольно важная строка кода. Он должен выглядеть так, если аргумент out имеет строку типа:

object[] args = new object[1]; //necessary to retrieve ref/out parameter
int result = Convert.ToInt32(typeof(Ability).InvokeMember(selectedMove, 
 BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, 
 null, null, args));
string outValue = (string)args[0]; // <=== here!

Теперь также должно быть очевидно, почему ваш первый фрагмент не может работать, у вас нет ссылки на массив объектов [], который вы передаете, поэтому вы никогда не сможете получить измененный аргумент.

licensed under cc by-sa 3.0 with attribution.