How do I correctly pass by ref using InvokeMember?

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
 
G

Guest

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
 
G

Guest

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
 
J

Jon Skeet [C# MVP]

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top