Control.Invoke and ref parameter

G

Guest

Hi,

Does anyone know how Control.Invoke can invoke a method which has ref
parameters?

For example,

class A {
public delegate MyFuncHandler(ref int i, ref int j);

public void MyFunc(ref int i, ref int j)
{
..
}

public A

public void MyCaller(DataGridView oDataGridView)
{
int x = 1;
int y = 1;

...

oDataGridView.Invoke(new MyHandler(MyFunc), new object { ref x, ref y });

....
}

oDataGridView.Invoke(new MyHandler(MyFunc), new object { ref x, ref y });

produces compilation error. Am I doing this wrong, or Control.Invoke does
not allow method with ref parameters?

Thanks,
 
B

Barry Kelly

George said:
Does anyone know how Control.Invoke can invoke a method which has ref
parameters?
oDataGridView.Invoke(new MyHandler(MyFunc), new object { ref x, ref y });

instead use:

object[] args = { x, y };
oDataGridView.Invoke(new MyHandler(MyFunc), args);
// use args[0] (returned value of x)
// use args[1] (returned value of y)

Now, args will have been modified based on what MyFunc did to x and y.

-- Barry
 
G

Guest

Hi,

Tried it, but I don't think it worked.
instead use:

object[] args = { x, y };
oDataGridView.Invoke(new MyHandler(MyFunc), args);

This would have been equivalent to

oDataGridView.Invoke(new MyHandler(MyFunc), new object { x, y});

Above, I believe, pass x and y by value, instead of by reference.





--
George


Barry Kelly said:
George said:
Does anyone know how Control.Invoke can invoke a method which has ref
parameters?
oDataGridView.Invoke(new MyHandler(MyFunc), new object { ref x, ref y });

instead use:

object[] args = { x, y };
oDataGridView.Invoke(new MyHandler(MyFunc), args);
// use args[0] (returned value of x)
// use args[1] (returned value of y)

Now, args will have been modified based on what MyFunc did to x and y.

-- Barry
 
B

Barry Kelly

George said:
Tried it, but I don't think it worked.
instead use:

object[] args = { x, y };
oDataGridView.Invoke(new MyHandler(MyFunc), args);

This would have been equivalent to

oDataGridView.Invoke(new MyHandler(MyFunc), new object { x, y});

Above, I believe, pass x and y by value, instead of by reference.

Did you even try the code? The arguments array passed in receives the
changed values.

To repeat myself, x and y don't change, the values in the *array*
change. The code above *is* *not* *equivalent*, because you've thrown
away the reference to the array.

When I said "// use args[0]", I meant that it receives the new value of
x.

For example, try this code (in C# 2.0, but the principle is the same):

---8<---
using System;
using System.Windows.Forms;
using System.Threading;

class App
{
delegate void IntFiddler(ref int value);

static void Main()
{
Form form = new Form();
ThreadPool.QueueUserWorkItem(delegate
{
Thread.Sleep(1000);

// Run some code in the context of the UI.
object[] args = { 21 };
form.Invoke(new IntFiddler(Fiddle), args);
Console.WriteLine(args[0]);
});
Application.Run(form);
}

static void Fiddle(ref int x)
{
x *= 2;
}
}
--->8---

-- Barry
 
T

Tom Spink

George said:
Hi,

Tried it, but I don't think it worked.
instead use:

object[] args = { x, y };
oDataGridView.Invoke(new MyHandler(MyFunc), args);

This would have been equivalent to

oDataGridView.Invoke(new MyHandler(MyFunc), new object { x, y});

Above, I believe, pass x and y by value, instead of by reference.

Hi George,
This would have been equivalent to

I'm afraid it's not equivalent. Quite different in fact. In your code, you
immediately instantiate an object array straight into the Invoke routine.
In Barry's code, the array is instantiated *outside* of the routine. It's
the instance of the array that changes, not the instance of the values
inside the array.

-- Tom Spink
 
G

Guest

Hi Barry.

Thanks for your help again. It is my mistake that I checked against the
wrong variables.

In your first example, I checked against the value in x and y, instead of
the new values in args.

If you don't mind telling me: I spent a lot of time searching for an answer
to this question before I posted here. I must have been searching the wrong
topic. Do you know if Microsoft published a document regarding the proper
use of

Control.Invoke(Delegate, object[])

especially when the Delegate contains "ref" or "out" parameters. It seems
like

1. without "ref" or "out", the object array *contents* are not modified.

2. with "ref" or "out", the object array * contents" are modified.

Is this a method marshalling thing?

Thanks





--
George


Barry Kelly said:
George said:
Tried it, but I don't think it worked.
instead use:

object[] args = { x, y };
oDataGridView.Invoke(new MyHandler(MyFunc), args);

This would have been equivalent to

oDataGridView.Invoke(new MyHandler(MyFunc), new object { x, y});

Above, I believe, pass x and y by value, instead of by reference.

Did you even try the code? The arguments array passed in receives the
changed values.

To repeat myself, x and y don't change, the values in the *array*
change. The code above *is* *not* *equivalent*, because you've thrown
away the reference to the array.

When I said "// use args[0]", I meant that it receives the new value of
x.

For example, try this code (in C# 2.0, but the principle is the same):

---8<---
using System;
using System.Windows.Forms;
using System.Threading;

class App
{
delegate void IntFiddler(ref int value);

static void Main()
{
Form form = new Form();
ThreadPool.QueueUserWorkItem(delegate
{
Thread.Sleep(1000);

// Run some code in the context of the UI.
object[] args = { 21 };
form.Invoke(new IntFiddler(Fiddle), args);
Console.WriteLine(args[0]);
});
Application.Run(form);
}

static void Fiddle(ref int x)
{
x *= 2;
}
}
--->8---

-- Barry
 
B

Barry Kelly

George said:
If you don't mind telling me: I spent a lot of time searching for an answer
to this question before I posted here. I must have been searching the wrong
topic. Do you know if Microsoft published a document regarding the proper
use of

Control.Invoke(Delegate, object[])

I don't know. I originally (several years ago) just guessed that's what
it would do when looking at MethodBase.Invoke(), and ran a program to
test out the theory. I was right :)
Is this a method marshalling thing?

In so far as the CLR needs to take the arguments out of the array and
put them on the stack and in regesters to call the method, and then copy
out all the modified 'ref' and 'out' parameters back into the array,
yes.

-- Barry
 
J

Jeffrey Tan[MSFT]

Hi George,

In addition to Barry's reply, I still want to add some comment to your 2
questions:

Based on the C# language reference, "ref" is a method parameter keyword,
which is only used in the parameter decoration.
1. without "ref" or "out", the object array *contents* are not modified.
2. with "ref" or "out", the object array * contents" are modified.

The key point is where the keyword applies: does it apply to the object
array itself or to the elements in the array?

If you are marking the object array with "ref", it means that the array
*contents* will remain the normal behavior, which we do not care, but the
array itself may point to another array after invoking the method, please
refer to the guide below:
"Passing Arrays Using ref and out (C# Programming Guide) "
http://msdn2.microsoft.com/en-us/library/szasx730.aspx

If you are marking the elements in the array with "ref", it means the array
remains the same, but the element itself may be *modified* after invoking.
Your problem demonstrates this scenario.

Actually, your scenario is somewhat specific, which I also can not find a
definite sample or document regarding the syntax passing to
Control.Invoke.(anyway, with the help of the community, you finally got the
answer). In this scenario, I think we have to try with the existing C#
document to find out the correct syntax.

1. Based on "ref" document, "An argument passed to a ref parameter must
first be initialized.", so we should initialize the object array outside of
the method first.
2. Marking "ref" in front of the object array element is invalid(because
"ref" is only valid in method parameter), so we have no option of marking
the "ref" keyword.

With these 2 constraints, the code snippet Barry provided should be the
only valid syntax.

Hope this comment makes sense to you. If you have any concern, please feel
free to tell me. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

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