Why can't I get a value for parameters like out or ref using Type.InvokeMember?

A long name, but I wanted it to be specific. The title is really a question. Although the method called by InvokeMember has an out parameter and assigns a value to this parameter, I cannot capture this value. Here is the code I originally used:

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

I changed it, which now does its intended work, but I do not know why:

 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)); 
+6
source share
3 answers

In your first code example, calling InvokeMember does not change the value of the parameter variable, it simply replaces the first element of the parameter array (which now points to another instance of string ), since you did not save the reference to this array, you cannot get the value of the output parameter.

In other words: the array first contains a copy of the parameter variable (i.e. a copy of the reference to an empty string). After the call, parameter and the value in the array refer to 2 different instances of the string.

+3
source

I just wanted to help someone who is struggling (I did) with unmanaged (COM) and returning the ref parameter. Thus, when using InvokeMember against the COM method, you must specify which arguments are ref-type. This is achieved using the ParameterModifier-class parameter, for example:

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

In the above code, the third argument is set as a reference (pMod [2] = true;)

+6
source

Your second snippet is missing a pretty important line of code. It should look like this if the out argument has a string like:

 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! 

Now it should also be obvious why your first fragment cannot work, you do not have a reference to the array of objects [] that you pass, so you can never get the changed argument.

+5
source

Source: https://habr.com/ru/post/911705/


All Articles