When I need to invoke some code in the specified thread, i am using something like this:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
delegate void MethodToInvokeDelegate(string foo, int bar);
void MethodToInvoke(string foo, int bar)
{
DoSomeWork(foo);
DoMoreWork(bar);
}
void SomeMethod()
{
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {S, I});
}
This code works fine, but it's quite heavy. I'd like to make it without declaring MethodToInvoke
and MethodToInvokeDelegate
- using an anonymous method. But I can't figure out how to pass parameters to it.
I can't write this like:
dispatcher.BeginInvoke((Action)delegate() { DoSomeWork(S); DoMoreWork(I); });
I need to actually pass parameters to method.
Is it any way to write it short and simple?
Example:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke( { ArrayToFill[i] = 10; } );
}
This code will not work: method will be called with i = 1, 2, 3 and will raise IndexOutOfRange exception. i
will be incremented before method begins to execute. So we need to rewrite it like:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
delegate void MethodToInvokeDelegate(int i);
void MethodToInvoke(int i)
{
ArrayToFill[i] = 10;
}
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {i});
}
This method dynamically invokes the method reflected by this instance on obj , and passes along the specified parameters. If the method is static, the obj parameter is ignored. For non-static methods, obj should be an instance of a class that inherits or declares the method and must be the same type as this class.
The out is a keyword in C# which is used for the passing the arguments to methods as a reference type. It is generally used when a method returns multiple values.
You can declare a variable in a separate statement before you pass it as an out argument. The following example declares a variable named number before it is passed to the Int32. TryParse method, which attempts to convert a string to a number.
also C# and . NET framework hast many many data structures that are very flexible like List and Array and you can use them as an output parameter or as return type so there is no need to implement a way to have optional output parameters.
if you wish to avoid creating a delegate type for each call, make use of Action<>
, Action<,>
, etc
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(
(Action<string, int>)((foo, bar) =>
{
MessageBox.Show(bar.ToString(), foo);
//DoSomeWork(foo);
//DoMoreWork(bar);
}),
new object[] { S, I }
);
an example with ArrayToFill[j] = 10;
action can be fixed very simple:
for (int i = 0; i < 3; i++)
{
int j = i;
// lambda captures int variable
// use a new variable j for each lambda to avoid exceptions
dispatcher.BeginInvoke(new Action(() =>
{
ArrayToFill[j] = 10;
}));
}
Try this:
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new Action(() =>
{
DoSomeWork(S);
DoMoreWork(I);
}));
[EDIT]
In response to your modified question:
The issue you are seeing there is modified closure problem.
To fix it, you merely need to copy the argument before invoking the method:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
for (int i = 0; i < 3; i++)
{
int index = i;
dispatcher.BeginInvoke(new Action(() => { ArrayToFill[index] = 10; } ));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With