views:

520

answers:

3

We're working on a Windows App that periodically has to launch operations which may take some time. We've gotten into a pattern of having these operations run on a BackgroundWorker, and writing up a quick WinForm for each operation, where you pass in to the form the necessary parameters, the form wires up the BackgroundWorker and makes the function call, and the form displays the output (progress bar moves, text fills up with updates, etc).

Now obviously, this form is very cookie-cutter. The only part that really differs between form copies is which method is called on which object. So what we'd love to do is make it generic, whereby we can take the form, pass in an object (or null for static calls?), a function name, and an array of parameters, and have it just "go" from there. We've been able to do this with Reflection. The thing we don't like about reflection in this case is the lack of strong-typing; things like mis-spelling the method call are caught at runtime, and not compile time. Is there anything available now that might make this more elegant and robust? I've heard of people talking about things like Delegates and Expression Trees; but I'm not sure the former applies and still a little in the dark about the latter.

+6  A: 

Make a common form and pass it a delegate pointing to the method that it should run on BackgroundWorker, would be a sensible solution.

You can have the Form constructor take a generic delegate (Action might be a good idea) as an argument, and pass a lambda expression in the constructor, that matches the signature of Action). Then, foreach action, you would only need to specify the appropiate lambda expression.

Remember that a lambda expression can capture local variables, so you will be able to call whatever logic that you did before and pass the same parameters.

driis
As I understand it, I'd then have to create a new delegate for each method that could eventually wind up being called in this way?
GWLlosa
@GWLIosa - I tried to expand the answer a bit to clarify that. You do not need to specify an explicit delegate type for each method.
driis
+3  A: 

You may want to check out Lambda functions as well. I use them specifically when I work with Generics. Otherwise, delegates will probably work fine.

theG
+2  A: 

One thing you could do is create several different methods (one for methods with no arguments, one for methods with one argument, etc.) like this:

public static void DisplayForm(Action action) {
    DisplayFormUsingInvoke(action);
}

public static void DisplayForm<T>(Action<T> action, T param) {
    DisplayFormUsingInvoke(action, param);
}

public static void DisplayForm<T,U>(Action<T,U> action, T param1, U param2) {
    DisplayFormUsingInvoke(action, param1, param2);
}

...

Then, you can have a private method which actually does the work, similarly to your current method, but not exposed to client code:

private static void DisplayFormUsingInvoke(Delegate d, params object[] parms) {
    // Edit this code to run it on the background thread, report progress, etc.
    d.DynamicInvoke(parms);
}

Then client code will call one of the public methods which will enforce the requirement that the right number and types of arguments are supplied.

kvb