Reputation: 9839
I am creating a Windows forms application which executes a lot of similar operations on a piece of data. All these operations are almost the same so I would like to create a single method that
I imagine calling this single method like
ExecuteOperation([method to execute], "Executing operation1")
I am sure that this is simple but I am lost between delegates and tasks so please show me how to write a method that is capable of running a selected method, preferably with multiple parameters and how this method is called.
Note:
By disabling the interface I mean
MainMenu.Enabled = false;
txtData.ReadOnly = true;
Upvotes: 0
Views: 85
Reputation: 786
You can pass methods into methods, so to speak, but the delegates have to match. If you have methods with different signatures, you're angling the wrong way.
The Action and Func delegates are generic. There's one to match almost any signature (up to 16 parameters), but again, they have to match the method signature. If you have one method with one parameter, and another with two, or two with different types of parameters, you can't pass those into the same delegate.
So, really it depends on how similar your methods are. If they have varied types of parameters, you'd probably have to "wrap" these calls.
Simplified example:
void Main()
{
List<Action> actions = new List<Action>
{
() => Method1("myString"),
() => Method2("myString2", "myString3")
};
foreach(var action in actions) InvokeAction(action);
}
void InvokeAction(Action action)
{
action();
}
void Method1(string x)
{
Console.WriteLine(x);
}
void Method2(string y, string z)
{
Console.WriteLine(y);
Console.WriteLine(z);
}
On the other hand, if your methods have the same signature, it's a bit simpler:
void Main()
{
InvokeAction(Method1, "myString");
InvokeAction(Method2, "myString2");
}
void InvokeAction(Action<string> action, string param)
{
action(param);
}
void Method1(string x)
{
Console.WriteLine(x);
}
void Method2(string y)
{
Console.WriteLine(y);
}
Now, as to running that asynchronously, it's as simple as using a System.Threading.Task, if you're on .NET 4.0. You could alter my example method as such:
void InvokeAction(Action<string> action, string param)
{
Task.Factory.StartNew(() => action(param));
}
Upvotes: 1
Reputation: 10108
How about something like this (non async/await - version):
void Foo<T>(Action<T> action, string message)
{
MethodWhichMakesMyInterfaceReadOnlyAndSetsMessage(message);
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (obj, arg) => action.Invoke();
worker.RunWorkerCompleted +=
(obj, arg) =>
{
MethodWhichMakesMyInterfaceReadWrite();
};
worker.RunWorkerAsync();
}
I wrote this before I realised you wanted async/await and tasks specifically - someone else has answered with that however. You can create whatever overloads you want for the extra params for your action.
Upvotes: 0
Reputation: 27495
You're probably looking for something like this (I've shown an example here for a method that takes parameters, since you asked for that case specifically):
private async Task ExecuteOperation(string operationName, Action action)
{
//Disable UI here
//Set 'Executing' message here
await Task.Run(action);
//Set 'Finished' message here
//Enable UI here
}
private async Task CallOperation()
{
int x, y, z; //These get set to something here...
await ExecuteOperation("Operation1", () => OperationWithParams(x, y, z));
}
You most likely also want to add some exception handling in your ExecuteOperation wrapper if you have standard exceptions that your various operations can throw and which should result in UI feedback of some sort.
On a side note, I reordered the name and the action, as this makes it somewhat cleaner (IMO) to pass an anonymous method as the action.
Upvotes: 3