views:

55

answers:

2

I'd like a delegate that calls a function in a different thread when it is invoked. Currently, I'm using the following implementation:

delegate void someFunctionDelegate();
//...

someFunctionDelegate callBackFunction = someForm.SomeFunction;
someForm.Invoke(someFunctionDelegate);

However, I'd like a more compact form, combining both the someForm instance and the SomeForm.SomeFunction member function. I'm thinking of something like this:

var callBackFunction = new AsynchronousCrossThreadDelegate(someForm, SomeForm.SomeFunction);
callBackFunction(); // Should call someForm.BeginInvoke(SomeForm.SomeFunction);

Is there a way to do so in C#/.NET?

Update I'm looking for a solution that will work for functions with 0 or more parameters.

+1  A: 

Would this help?

You'd just do:

var callBackFunction = AsynchronousCrossThreadDelegate.Create(someForm, SomeForm.SomeFunction);   
callBackFunction(); // Should call someForm.BeginInvoke(SomeForm.SomeFunction);   

instead.

public class AsynchronousCrossThreadDelegate
{
    public delegate void someFunctionDelegate(); 

    private Control _ctrl;
    private someFunctionDelegate _callback;

    private AsynchronousCrossThreadDelegate( Control ctrl, someFunctionDelegate callback )
    {
        _ctrl = ctrl;
        _callback = callback;
    }

    private void invoke()
    {
        _ctrl.BeginInvoke( _callback );
    }

    public static someFunctionDelegate Create( Control ctrl, someFunctionDelegate callback )
    {
        return (new AsynchronousCrossThreadDelegate( ctrl, callback )).invoke;
    }

}
danbystrom
Thanks for your response. I didn't tell in my question, but I'm looking for a solution that will work for functions with 0 or more parameters.
Dimitri C.
Since .BeginInvoke just passes an object[] as it's parameter list - maybe you can do the same...? Just asking...? :-)
danbystrom
Yes, but doesn't "someFunctionDelegate" have to be declared using the full function signature, complete with its parameter list?
Dimitri C.
Yes. But you *could* declare it aspublic delegate void someFunctionDelegate( params object[] args );Not saying that you should, though.
danbystrom
OK, I now understand what you mean. You're right, as Invoke doesn't do parameter type checking, it is useless to try to store it anyway. A disadvantage is that the function to be called back will always require an object[] parameter list. I'll consider whether this drawback doesn't neutralize the advantage of this AsynchronousCrossThreadDelegate class.
Dimitri C.
The only other option that I can think of right now would be to write a bunch of generic classes: one for each number of parameters! Actually, that would not be so bad in practice: how often do you have more than, say, five parameters...
danbystrom
You're right, but I wonder whether C#'s template system is sufficiently powerful for this.
Dimitri C.
+1  A: 

Partly thanks to my discussion with danbystrom, I found a sufficient solution:

public static Action<T> MakeAsyncDelegate<T>(
    this Control form, Action<T> functionToCallAsynchronously)
{
    Action<T> ret = ((T t) => {
        form.BeginInvoke(functionToCallAsynchronously, t);
    });
    return ret;
}

This allows you to keep the client code clean:

Action<string> signal = form.MakeAsyncDelegate(form.SomeFunction);
signal("some string");

Regrettably, the caller has to explicitly specify the template parameter, as the compiler cannot infer it automatically (see this article), neither can the compiler check whether the type really matches the function signature (in C++ this can be done).

Dimitri C.