Почему я не могу получить значение для параметров типа 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. Это достигается с помощью 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 имеет тип string:

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!

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

Другие вопросы по тегам