Reputation: 7050
I have a chunk of code that does a "file put" operation inside a moderately complicated piece of retry and try/catch logic. This is working fine, it looks roughly like this:
while (...) {
try {
FilePut(source, destination)
}
catch () {
//Check exception type, possibly re-throw, possibly return, possibly increment
//counters being checked by while loop
}
}
The details of this logic aren't the issue. But I'm realizing I have several other operations that also need to execute inside this same kind of logic and I want to avoid copy and pasting this logic around my application. I'd like to move it to a function and reuse that function. That function would have to take some sort of reference to the operation to be called, and the try logic would execute that operation (file put, file get, whatever).
This seems like a great place for a delegate, but the problem is, each of these operations has a different signature, so I'm not sure how to be able to write my above logic to be able to call "any" operation.
Is there a good way to do this in C#?
Upvotes: 5
Views: 2032
Reputation: 23142
You need an Action
delegate to hide all of the different signatures. Something like this:
public void DoAction(Action action)
{
// Make the boilerplate code whatever you need it to be.
// I've just used a try catch for simplicity.
try
{
// Call the action at the appropriate time.
action();
}
catch
{
// Handle any exceptions as you wish.
}
}
Then, to be able to handle actions with different signatures, you can define a few overloads that take different types of the generic Action<T>
delegates and all of the necessary arguments. These overloads will "curry" the generic action and its arguments to a plain Action
:
public void DoAction<T>(Action<T> action, T arg1)
{
DoAction(() => action(arg1));
}
public void DoAction<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
{
DoAction(() => action(arg1, arg2));
}
public void DoAction<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
DoAction(() => action(arg1, arg2, arg3));
}
// etc...
To use:
public void SomeOtherMethod()
{
DoAction(MethodThatTakesTwoInts, 42, 23);
DoAction(MethodThatTakesAString, "Don't Panic!");
}
Also, if you not familiar with them, take a look at the related family of Func
delegates as well for good measure.
Upvotes: 6
Reputation: 8814
You can use recursion:
protected void TryNTimes(int numberOfTries, Action action)
{
try
{
if (numberOfTries == 0) return;
action();
}
catch (Exception)
{
TryNTimes(numberOfTries - 1, action);
}
}
And then use it like this:
TryNTimes(10, () => Foo());
Upvotes: 0