-3
int noOfAttempts = 3;
void StartServer();
bool IsServerRunning();

I need to re-attempt StartServer() 3 times based on result from IsServerRunnig(). Something like this:

StartServer();
if (!IsServerRunning())
{
    StartServer();
    if (!IsServerRunning())
    {
        StartServer();
        if (!IsServerRunning())
        {
            StartServer();
        }
    }
}

I don't want to use for loops or the ugly code like above. Is there a better way of doing this? A way in which, I won't have to change my code if noOfAttempts change in future?

EDIT: I'm expecting something from the "delegate" concept (If possible).

Sandeep
  • 5,581
  • 10
  • 42
  • 62
  • 3
    Why do you not want to use for loops? Seems like a good structure for this. – Oded Oct 16 '12 at 08:31
  • @Oded: if noOfAttempts changes, then I will have to add another if condition to the code. – Sandeep Oct 16 '12 at 08:32
  • I don't see why that would be, not if you use for loops correctly. – Oded Oct 16 '12 at 08:33
  • @Oded OP is right, `while` loop is more flexible for this situation, IMO. – Leri Oct 16 '12 at 08:35
  • The point is: I wanted to avoid loops in my code :) – Sandeep Oct 16 '12 at 08:36
  • A `while` loop is great here, but why on earth *must* you have something using a `delegate`? Don't over-complicate things. – Arran Oct 16 '12 at 08:40
  • @Sandeep I'd love to avoid code in my projects. When you want to repeat something in your applications, you have to use loops (I don't even want to mention `goto`). – Leri Oct 16 '12 at 08:40
  • 5
    You _should_ be using loops for this. It makes 0 sense to go for something more complicated and out of the ordinary. – Oded Oct 16 '12 at 08:40
  • 2
    What's wrong if I want to try out something new? It might help me in other complex scenarios. It's a well-known fact that loops are designed to use for this kinda things.. but just trying an attempt out of the box.. – Sandeep Oct 16 '12 at 09:13
  • @Sandeep - Because trying something that is "out of the box" for something this simple is sort of silly. Complicated code is bad...and that is exactly what any other option would give you..complicated unreadable code you don't understand. – Security Hound Oct 16 '12 at 12:15
  • Attempting to avoid loops in code? My dear sir, loops are one of 3 basic structures of any program. Without them, there will be things you can't implement. If you can solve something with a loop easily, why look for a more complicated solution? Prithee, kind sir, look away from this foolishness! It serves you poorly, I assure you! – Sulthan Oct 16 '12 at 12:28
  • You can create a `list<>` of strings in correct order and use an `each` and `reflection` to get the methods to be called.... – bart s Oct 16 '12 at 12:34

11 Answers11

9

UPD:

Seems like you actually want(ed) some neat way to describe retry logic. In this case look at transient-fault-handling libraries such as Polly.


Ok.

3.TimesUntil(IsServerRunning, StartServer); 

Delegate magic here:

public static class Extensions 
{
    public static void TimesWhile(this int count, Func<bool> predicate, Action action)
    {
        for (int i = 0; i < count && predicate(); i++) 
           action();
    }
    public static void TimesUntil(this int count, Func<bool> predicate, Action action)
    {
        for (int i = 0; i < count && !predicate(); i++) 
            action();
    }
}

To esteemed downvoters: It's just for fun and I'd never write this code for real projects.

tukaef
  • 9,074
  • 4
  • 29
  • 45
7

You could use a while loop

int counter = 0;
while(counter < 3 && !IsServerRunning()) {
    StartServer();
    counter++;
}
Jon Taylor
  • 7,865
  • 5
  • 30
  • 55
6

Here you go no loops...

private void Start(int numberOfAttempts)
{
    if (numberOfAttempts == 0)
        return;

    StartServer();

    if (!IsServerRunning())
        Start(numberOfAttempts-1);
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Alan
  • 7,875
  • 1
  • 28
  • 48
  • 6
    Make it `Start(--numberOfAttempts)` or `Start(numberOfAttempts-1)` otherwise you'll face infinite recursion. – Alex Oct 16 '12 at 08:36
1

As everybody already noted a while or for loop is really the most easiest part to solve this problem.

If you really want to setup something really advanced for this stuff take a look at the trampoline function question or take a look into the article from Bart. With this approach you would be able to avoid the loop (hence i don't think it would be worth in this case).

Community
  • 1
  • 1
Oliver
  • 43,366
  • 8
  • 94
  • 151
0

Sure:

while (numRetries > 0 && !IsServerRunning) {
    StartServer();
    numRetries--;
}

If you feel adventurous, you could also use goto ;-)

Joey
  • 344,408
  • 85
  • 689
  • 683
0
int numberOfAttempts = 3;

do
{
    StartServer();
    numberOfAttempts--;
} 
while(!IsServerRunning() && numberOfAttempts > 0)

UPDATE: Thus this operations are closely-related, you can create method

bool TryStartServer()
{
     StartServer();
     return IsServerRunning();
}

And second one which, will try to start server several times (and returns the result of operation)

bool TryStartServer(int numberOfAttemtps)
{
    for(int attempt = 0; attempt < numberOfAttempts; attempt++)
        if (TryStartServer)
            return true;

    return false; 
}
Alan
  • 7,875
  • 1
  • 28
  • 48
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
0

You could use a delegate if you really wanted.. (perhaps for a library of reusable things?)

public void CallFunctionNTimes(Action func, int nTimes, params bool[] conditions) {
    int callCounter = 0;

    while (callCounter < nTimes && conditions.All(x => x == true)) {
        func();
        callCounter++;
    }
}

Usage:

CallFunctionNTimes(StartServer, 3, !IsServerRunning /* Other stuff too if you want */);

.. not really much different than the other answers except its re-usable I guess :)

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
0

How about the do.. while(false) loop? (joking, but seriously I've seen it in code before)

int numTries;

        do
        {
            if(numTries == 0)
                break;

            StartServer();
            numTries--;

            if (!IsServerRunning)
                continue;
        } while (false);
Alan
  • 7,875
  • 1
  • 28
  • 48
0

I'd probably make it a builtin functionality of the StartServer method itself. Something like this (just a proof of concept):

public class ServerNotRunningException : Exception { /*No content here*/ }

public void StartServer(int attempts = 3)
{
    try
    {
        //attempt to start server
        if(!IsServerRunning()) // or check something available in your method
            throw new ServerNotRunningException();
    }
    catch(ServerNotRunningException ex)
    {
        // you should log ex.ToString() here!
        if(attempts>0) StartServer(attempts-1); //try again!
        else throw new ServerNotRunningException(); //mission failed, bubble up!
    }
}

usage:

StartServer();
//or, to make it try i.e. 5 times
StartServer(5);
Alex
  • 23,004
  • 4
  • 39
  • 73
-1

It's better to have the retry logic totally separate from the main code:

void Attempt(Action action, Func<bool> ensure, int noOfAttempts)
{
   while (noOfAttempts-- > 0 && !ensure())
   {
       action();
   }
}

and then:

Attempt(action:StartServer, ensure:IsServerRunning, noOfAttempts:3)
xing
  • 447
  • 2
  • 6
-1

Just for fun

var calls = Enumerable.Repeat<List<string>>(new List<string>() { "IsServerRunning", "StartServer" }, noOfAttempts).ToList();
calls.ForEach(new Action<List<string>>(
    delegate(List<string> item)
    {
        // Use reflection here to create calls to the elements of item
    }
));
bart s
  • 5,068
  • 1
  • 34
  • 55