0

I have a question about switches in C#. I have a basic switch, three cases and a default, as you can see here:

string firstSwitch = Console.ReadLine().ToLower();
switch (firstSwitch)
{ 
    case "goodbye":
        Console.WriteLine("Hello, Goodbye");
        break;

    case "gandalf":
        Console.WriteLine("YOU SHALL NOT PASS!");
        break;

    case "skyrim":
        Console.WriteLine("I used to be an adventurer like you, then I took an arrow to the knee.");
        break;

    default:
        Console.WriteLine("The Force is strong with this one.");
        break;

Now I want to add another case that will respond with a random case output that was previously added. For example:

case "giveRandom":
    //Code that returns the value for Case 0, case 1, or case 2,//
    break;

Thanks in advance for your help guys.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Just use a list of strings and pick a random one out of that list? Or use Dictionary. – L-Four Jan 26 '15 at 14:11
  • 1
    I don't thing it is possible without using some dirty hacks. It is possible but you should not do it this way. Consider using some Strategy pattern with a list of reads – Venson Jan 26 '15 at 14:12
  • Its not clear what you are asking. What exactly should happen in `case giveRandom` ? – DrKoch Jan 26 '15 at 14:13
  • @JPVenson It is possible using `goto case`, but I guess many people might consider the use of `goto` even within a `switch` to be a "dirty hack". – juharr Jan 26 '15 at 14:26

4 Answers4

3

Put all of your cases in a dictionary, and use this one in your switch statements:

var dict = new Dictionary<string, string>()
{
     new { "goodbye", "Hello, Goodbye" },
     new { "gandalf", "YOU SHALL NOT PASS!" },
     // etc
    new { "default", "The Force is strong with this one."}
};

string firstSwitch = Console.ReadLine().ToLower();
switch (firstSwitch)
{ 
    case "goodbye":
        Console.WriteLine(dict["goodbye"]);
        break;

    case "gandalf":
        Console.WriteLine(dict["gandalf"]);
        break;

    case "giveRandom":
        // choose a random element in dict and display it
        break;

    default:
        Console.WriteLine(dict["default"]);
        break;
}

For the random switch, you just take a random element out of the dictionary as described here.

In fact, you can maybe even reduce the number of switches like:

switch (firstSwitch)
{             
   case "giveRandom":
        // choose a random element in dict and display it
        break;

    default:
        if (dict.ContainsKey(firstSwitch))
        {
            Console.WriteLine(dict[firstSwitch]);
        }
        else
        {
             Console.WriteLine(dict["default"]);
        }
        break;
}

And as stated in the comments below, maybe you don't even need a switch (a simple if-then may suffice), but it depends on the logic that is involved.

if (firstSwitch == "giveRandom")
{
    // choose a random element in dict and display it
} 
else
{
     if (dict.ContainsKey(firstSwitch))
     {
          Console.WriteLine(dict[firstSwitch]);
     }
     else
     {
          Console.WriteLine(dict["default"]);
     }
}

And finally, also think about case sensitivity when comparing strings.

Community
  • 1
  • 1
L-Four
  • 13,345
  • 9
  • 65
  • 109
  • And how do you propose to pick a random element from the dictionary? – Jim Mischel Jan 26 '15 at 14:17
  • 1
    @L-Three there is only one case statement for the last piece of code, so do you really need a switch? if-else would be more than enough – Carbine Jan 26 '15 at 14:21
  • @Jim: see the link to pick a random item from the dictionary – L-Four Jan 26 '15 at 14:27
  • @CarbineCoder: I don't know the use case in detail, but it may very well be the case that switch is overkill. But hard to tell, there may be other logic involved. – L-Four Jan 26 '15 at 14:28
1

There is no syntax that will do what you want directly (especially since case is deterministic so there's no way to execute a "random" case), but what you want should be doable by thinking about it a different way. One way would be to put your cases in a List<string> and if giveRandom is selected then pick a string at random:

List<string> cases = new List<string> {"goodbye","gandalf","skyrim"};
string firstSwitch = Console.ReadLine().ToLower();

if(firstSwitch == "giveRandom")
{
    // if this method will be called in a tight loop 
    // then make rand a field of the class instead
    Random rand = new Random();

    // pick a case at random
    firstSwitch = cases[rand.Next(0, cases.Count)];
}

switch (firstSwitch)
{ 
    case "goodbye":
        Console.WriteLine("Hello, Goodbye");
        break;

    case "gandalf":
        Console.WriteLine("YOU SHALL NOT PASS!");
        break;

    case "skyrim":
        Console.WriteLine("I used to be an adventurer like you, then I took an arrow to the knee.");
        break;

    default:
        Console.WriteLine("The Force is strong with this one.");
        break;
}
D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • You'll want to create that `Random` at class scope. Otherwise multiple calls in quick succession will result in the same "random" number being generated. – Jim Mischel Jan 26 '15 at 14:19
  • @JimMischel Agreed, which is why I added that comment in the example. – D Stanley Jan 26 '15 at 14:21
0

You can do this with a SortedDictionary directly, and no switch statement:

readonly SortedDictionary<string, string> _nameLookup = new SortedDictionary<string, string>
{
    {"goodbye", "Hello, Goodbye"},
    {"gandalf", "YOU SHALL NOT PASS"},
    {"skyrim", "I used to be an adventurer . . ."},
    {"default", "The force is strong with this one."}
};
readonly Random _rand = new Random();

Then, in your function:

void foo()
{
    string firstSwitch = Console.ReadLine().ToLower();
    string result;
    if (firstSwitch == "chooserandom")
    {
        result = _nameLookup[_rand.Next(_nameLookup.Count)];
    }
    else if (!_nameLookup.TryGetValue(firstSwitch, out result))
    {
        result = _nameLookup["default"];
    }
    Console.WriteLine(result);
}

Granted, SortedDictionary is slower at lookup than Dictionary, but in a user interface application like this or if the number of options isn't huge, you'll never notice the difference. And selecting a random element here is easier and faster than with Dictionary.

This approach can also work well if you want to do more than just output a string. If you wanted to do a lot of processing for each item, you could replace the value in the dictionary with a method name (or an anonymous function). For example:

readonly SortedDictionary<string, Action> _nameDispatch = new SortedDictionary<string, Action>
{
    {"gandalf", ProcessGandalf},
    {"skyrim", ProcessSkyrim},
    // etc.
}

Of course, you'd need to define the methods ProcessGandalf, ProcessSkyrim, etc.

You'd use the same logic as above, but rather than writing the result, you'd have:

Action result;
// logic here to get the proper result.
// And then call that function:
result();
Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
-1

I think this is the way to go

  string firstSwitch = Console.ReadLine().ToLower();
            const string goodbye = "Hello, Goodbye";
            const string gandalf = "YOU SHALL NOT PASS!";
            const string skyrim = "I used to be an adventurer like you, then I took an arrow to the knee.";
            const string otherWise = "The Force is strong with this one.";
            switch (firstSwitch)
            {
                case "goodbye":
                    Console.WriteLine(goodbye);
                    break;

                case "gandalf":
                    Console.WriteLine(gandalf);
                    break;

                case "skyrim":
                    Console.WriteLine(skyrim);
                    break;
                case "giveRandom":
                    var dic = new Dictionary<int, string>();
                    dic[0] = goodbye;
                    dic[1] = gandalf;
                    dic[2] = skyrim;
                    var rnd = new Random();
                    Console.WriteLine(dic[rnd.Next(2, 0)]);
                    break;
                default:
                    Console.WriteLine(otherWise);
                    break;
            }
Rajdeep Dosanjh
  • 1,157
  • 1
  • 9
  • 20