Question

I want my code to keep trying a method until no exception is thrown, however, unlike this question, I would like it to be written as a generic method capable of running any input delegate/method. Here is what I've had in mind, but I am not sure how to pass the arguments or generic methods through it:

public void tryLoop(Delegate anyMethod, T[] arguments) {
    while (true) {                              
        // Could be replaced by timer timeout
        try {
            anyMethod(arguments);
            break;
        }
        catch {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

Is this possible?

EDIT: For the academics of it, I would also be curious to know if it's possible to return the result as well.

Was it helpful?

Solution

If you can settle for using closures, you won't need to have to pass parameters to this method all (or have multiple overloads). The result can be returned using a Func.

  public T tryLoop<T>(Func<T> anyMethod)
  {
     while (true)
     {
        try
        {
           return anyMethod();
        }
        catch
        {
           System.Threading.Thread.Sleep(2000); // *
        }
     }
     return default(T);
  }


  void SomeMethod(int param)
  {
     var someLocal = "Hi";
     var anotherLocal = 0;
     var result = tryLoop(() =>
     {
        Console.WriteLine(someLocal);
        return param + anotherLocal;
     });
     Console.Write(result);
  }

To be honest, I wouldn't set an infinite retry, however - at best, if certain types of retryable error were returned, such as a database deadlock, or a timeout calling an erratic web service, then possibly 3 or 4 retries might be in order. Exceptions such DivideByZero or FileNotFound aren't likely to go away by running them indefinitely :-)

*** especially with deadlocks, sleeping for a random period is recommended, just in case other threads are also simultaneously deadlocking on exactly the same data - you don't want the same deadlock recurrence happening in 2000ms :-).

OTHER TIPS

A way to do this is by using an Action, and remove the arguments parameter:

public void tryLoop(Action anyMethod) {
    while ( true ) {
        // Could be replaced by timer timeout
        try {
            anyMethod();
            break;
        }
        catch {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

This gives you ultimate freedom in how to use it:

tryLoop(() => string.Reverse("abc"));

or like this:

String s1 = "A";
String s2 = "b";

tryLoop(() => string.Concat(s1, s2));

As you can see in the second example, you can directly take the arguments from the context of the tryLoop method being called. You can invoke anything there.

The good thing for this approach is that you will not have to use Invoke or DynamicInvoke as with a Delegate instead of Action, because these introduce a performance penalty.

If you need the result, you can re-write the above with a Func<T> instead of Action, like this:

public T tryLoop<T>(Func<T> anyMethod) {
    while ( true ) {
        // Could be replaced by timer timeout
        try {
            return anyMethod();
        }
        catch {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

and use it like this:

var reversed = tryLoop(() => string.Reverse("abc"));

String s1 = "A";
String s2 = "b";

var concatenated = tryLoop(() => string.Concat(s1, s2));

Check if this suit your needs. If not then please comment. Also not sure how it will be performance wise.

Also the DynamicInvoke method has an object return type. This you can use to return the result of the delegate. You can change the return type of method from void to object.

public void tryLoop<T>(Delegate anyMethod, T[] arguments)
{
    while (true)
    {                              // Could be replaced by timer timeout
        try
        {
            anyMethod.DynamicInvoke(arguments);
            break;
        }
        catch
        {
            System.Threading.Thread.Sleep(2000); // wait 2 seconds
        }
    }
}

Hope this helps

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top