How do I correctly pass by ref using InvokeMember?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

The following code shows what I am trying to do. The normal invocation of
the CalcByRef produces the correct results, however, using the InvokeMember
fails to correctly pass the single argument by reference. How can I
correctly pass the short by ref through a InvokeMember.

using System;
using System.Reflection;
namespace TestByRef
{
class DoByRef
{
public void CalcByRef (ref short sNum)
{
sNum++;
} // public void CalcByRef ()
} // class DoByRef
class TestByRef
{
[STAThread]
static void Main (string[] args)
{
try
{
short sMyNum = 5;
DoByRef MyRef = new DoByRef ();
MyRef.CalcByRef(ref sMyNum);
Console.WriteLine(sMyNum);
ParameterModifier pm = new ParameterModifier(1);
pm[0] = true;
ParameterModifier [] mods = { pm };
object [] MyArgs = new object[1];
MyArgs[0] = sMyNum;
Type tMyRef = MyRef.GetType();
tMyRef.InvokeMember("CalcByRef",BindingFlags.InvokeMethod,null,MyRef,
MyArgs,mods,null,null);
Console.WriteLine(sMyNum);
} // try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
} // catch (Exception ex)
} // static void Main ()
} // class TestByRef
} // namespace TestByRef
 
Rather than checking the value of sMyNum at the end, try checking the value
of MyArgs[0].

You are copying the value of sMyNum into the args array and the passing that
(not sMyNum) to CalcByRef which is making the adjustment to the value in the
array.

Brendan
 
Hi Brendan,

Yes, I agree that the correct value of sMyNum can be found in the MyArgs[0].
But then the two calls are not equivalent. If you examine the underlying il
code you will find that the C# compiler uses a load address of the argument.
However, with the InvokeMember I can not find a way to have the original
variable location modified as in MyRef.CalcByRef(ref sMyNum). If I am
required to copy the MyArgs[0] back into sMyNum after a InvokeMember then it
is not a pass by reference. I spent a lot of time trying to get the address
of sMyNum (a short *) into an object, but C# complains. Unsafe and fixed
statements only get me part of the way. So do you have any other suggestions
because at this point I am squeezed dry of ideas.

Pat

Brendan Grant said:
Rather than checking the value of sMyNum at the end, try checking the value
of MyArgs[0].

You are copying the value of sMyNum into the args array and the passing that
(not sMyNum) to CalcByRef which is making the adjustment to the value in the
array.

Brendan


Pat Ireland said:
The following code shows what I am trying to do. The normal invocation of
the CalcByRef produces the correct results, however, using the InvokeMember
fails to correctly pass the single argument by reference. How can I
correctly pass the short by ref through a InvokeMember.

using System;
using System.Reflection;
namespace TestByRef
{
class DoByRef
{
public void CalcByRef (ref short sNum)
{
sNum++;
} // public void CalcByRef ()
} // class DoByRef
class TestByRef
{
[STAThread]
static void Main (string[] args)
{
try
{
short sMyNum = 5;
DoByRef MyRef = new DoByRef ();
MyRef.CalcByRef(ref sMyNum);
Console.WriteLine(sMyNum);
ParameterModifier pm = new ParameterModifier(1);
pm[0] = true;
ParameterModifier [] mods = { pm };
object [] MyArgs = new object[1];
MyArgs[0] = sMyNum;
Type tMyRef = MyRef.GetType();
tMyRef.InvokeMember("CalcByRef",BindingFlags.InvokeMethod,null,MyRef,
MyArgs,mods,null,null);
Console.WriteLine(sMyNum);
} // try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
} // catch (Exception ex)
} // static void Main ()
} // class TestByRef
} // namespace TestByRef
 
Pat Ireland said:
Yes, I agree that the correct value of sMyNum can be found in the MyArgs[0].
But then the two calls are not equivalent. If you examine the underlying il
code you will find that the C# compiler uses a load address of the argument.
However, with the InvokeMember I can not find a way to have the original
variable location modified as in MyRef.CalcByRef(ref sMyNum). If I am
required to copy the MyArgs[0] back into sMyNum after a InvokeMember then it
is not a pass by reference.

It's not a pass by reference of sMyNum, but it never could be, given
that when you copy the value into the parameter array, that's all
you're copying - the value.
I spent a lot of time trying to get the address
of sMyNum (a short *) into an object, but C# complains. Unsafe and fixed
statements only get me part of the way. So do you have any other suggestions
because at this point I am squeezed dry of ideas.

Yes - just copy the value back from the parameter array into sMyNum.
You're not going to find any other way of getting pass-by-reference
semantics via reflection.
 
Back
Top