Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shortest way to invoke a method with parameters in C#

Tags:

c#

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});
}
like image 355
AndrewR Avatar asked Jan 19 '16 08:01

AndrewR


People also ask

What invoke () method do in C#?

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.

What is out _ in C#?

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.

Do you need to declare and out variable before you use it?

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.

Can out parameter be optional C#?

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.


2 Answers

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;
    }));
}
like image 148
ASh Avatar answered Oct 18 '22 21:10

ASh


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; } ));
}
like image 1
Matthew Watson Avatar answered Oct 18 '22 21:10

Matthew Watson