67

How can I combine return and switch case statements?

I want something like

return switch(a)
       {
          case 1:"lalala"
          case 2:"blalbla"
          case 3:"lolollo"
          default:"default" 
       };

I know about this solution

switch(a)
{
    case 1: return "lalala";
    case 2: return "blalbla";
    case 3: return "lolollo";
    default: return "default";
}

But I want to only use the return operator.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
Neir0
  • 12,849
  • 28
  • 83
  • 139

15 Answers15

194

Actually this is possible using switch expressions starting with C# 8.

return a switch
    {
        1 => "lalala",
        2 => "blalbla",
        3 => "lolollo",
        _ => "default"
    };

Switch Expressions

There are several syntax improvements here:

  • The variable comes before the switch keyword. The different order makes it visually easy to distinguish the switch expression from the switch statement.
  • The case and : elements are replaced with =>. It's more concise and intuitive.
  • The default case is replaced with a _ discard.
  • The bodies are expressions, not statements.

For more information and examples check the Microsoft's C# 8 Whats New.

taha
  • 722
  • 7
  • 15
Daniel Z.
  • 2,988
  • 2
  • 19
  • 23
27

Note: As of C#8 (ten years later!) this is now possible, please see the answer below.


switch and return can't combine that way, because switch is a statement, not an expression (i.e., it doesn't return a value).
If you really want to use just a single return, you could make a Dictionary to map the switch variable to return values:

var map = new Dictionary<int, string>() 
{
    {1, "lala"}, 
    {2, "lolo"}, 
    {3, "haha"}, 
};
string output;
return map.TryGetValue(a, out output) ? output : "default";
tzaman
  • 46,925
  • 11
  • 90
  • 115
22

I believe that this solution is the most straighforward one, and you should definitely use it:

switch(a) { 
  case 1: return "lalala"; 
  case 2: return "blabla"; 
  case 3: return "lololo"; 
  default: return "default"; 
} 

But, since you asked for one return, you could use this little fluent class:

public class Switch<TElement, TResult> {
  TElement _element;
  TElement _currentCase;
  IDictionary<TElement, TResult> _map = new Dictionary<TElement, TResult>();

  public Switch(TElement element) { _element = element; }
  public Switch<TElement, TResult> Case(TElement element) {
    _currentCase = element;
    return this;
  }
  public Switch<TElement, TResult> Then(TResult result) {
    _map.Add(_currentCase, result);
    return this;
  }
  public TResult Default(TResult defaultResult) {
    TResult result;
    if (_map.TryGetValue(_element, out result)) {
      return result;
    }
    return defaultResult;
  }
}

To create code like this:

  return new Switch<int, string>(a)
    .Case(1).Then("lalala")
    .Case(2).Then("blabla")
    .Case(3).Then("lololo")
    .Default("default");

Unfortunately, the type parameters could not be inferred by the compiler, and it feels a bit clumsy. The Default will trigger the evaluation of the "switch", and must be the last method call in the chain. Note that you always need a default value, since you've turned switch into an expression.

UPDATE: You can solve the type inference problem and drive the user to do the right thing with this code:

public static class Switch {

  public static SwitchBuilder<TElement>.CaseBuilder On<TElement>(TElement element) {
    return new SwitchBuilder<TElement>(element).Start();
  }

  public class SwitchBuilder<TElement> {
    TElement _element;
    TElement _firstCase;
    internal SwitchBuilder(TElement element) { _element = element; }
    internal CaseBuilder Start() {
      return new CaseBuilder() { Switch = this };
    }
    private ThenBuilder Case(TElement element) {
      _firstCase = element;
      return new ThenBuilder() { Switch = this };
    }
    private SwitchBuilder<TElement, TResult>.CaseBuilder Then<TResult>(TResult result) {
      return new SwitchBuilder<TElement, TResult>(
        _element,
        _firstCase,
        result).Start();
    }
    public class CaseBuilder {
      internal SwitchBuilder<TElement> Switch { get; set; }
      public ThenBuilder Case(TElement element) {
        return Switch.Case(element);
      }
    }
    public class ThenBuilder {
      internal SwitchBuilder<TElement> Switch { get; set; }
      public SwitchBuilder<TElement, TResult>.CaseBuilder Then<TResult>(TResult result) {
        return Switch.Then(result);
      }
    }
  }

  public class SwitchBuilder<TElement, TResult> {
    TElement _element;
    TElement _currentCase;
    IDictionary<TElement, TResult> _map = new Dictionary<TElement, TResult>();
    internal SwitchBuilder(TElement element, TElement firstCase, TResult firstResult) {
      _element = element;
      _map.Add(firstCase, firstResult);
    }
    internal CaseBuilder Start() {
      return new CaseBuilder() { Switch = this };
    }
    private ThenBuilder Case(TElement element) {
      _currentCase = element;
      return new ThenBuilder() { Switch = this };
    }
    private CaseBuilder Then(TResult result) {
      _map.Add(_currentCase, result);
      return new CaseBuilder() { Switch = this };
    }
    private TResult Default(TResult defaultResult) {
      TResult result;
      if (_map.TryGetValue(_element, out result)) {
        return result;
      }
      return defaultResult;
    }
    public class CaseBuilder {
      internal SwitchBuilder<TElement, TResult> Switch { get; set; }
      public ThenBuilder Case(TElement element) {
        return Switch.Case(element);
      }
      public TResult Default(TResult defaultResult) {
        return Switch.Default(defaultResult);
      }
    }
    public class ThenBuilder {
      internal SwitchBuilder<TElement, TResult> Switch { get; set; }
      public CaseBuilder Then(TResult result) {
        return Switch.Then(result);
      }
    }
  }

}

The result is this nice, type-safe, fluent interface; where at each step you'll only have the right choice of methods to call (e.g. Then after Case):

return Switch.On(a)
  .Case(1).Then("lalala")
  .Case(2).Then("blabla")
  .Case(3).Then("lololo")
  .Default("default");
Jordão
  • 55,340
  • 13
  • 112
  • 144
  • 2
    This is great, Jordao, but it would make more sense to have methods as parameters to the Thens (they could be anonymous). Like a normal case statement. You can have multiple lines of code in a case statement. So, you could say int x = b + c * d; return "The answer is " + a.ToString(); for example. Anyway, it would have to be a method that returns the same type of object that a (in the On clause) is. Make sense? – vbullinger Jun 21 '12 at 22:17
  • 1
    @vbullinger: yes, it makes perfect sense. In fact, that's exactly what I started doing some time ago but didn't really finish. – Jordão Jun 21 '12 at 23:13
  • 1
    Mind-blowing construction. Deep generic and functional magic. – SerG Sep 11 '17 at 13:10
  • A minor comment, the fluent expression is nice for smaller switch statements but for larger ones you'd lose the hashing functionality for speed that switch statements give. Although you probably wouldn't want to do a large switch in this method anyway :) – robs Aug 21 '20 at 07:48
17

I normally do it this way:

var result = null;

switch(a)
{
    case 1:
        result = "lalala";
        break;
    case 2:
        result = "blalbla";
        break;
    case 3:
        result = "lolollo";
        break;
    default:
        result = "default";
        break;
};

return result;
Oliver
  • 43,366
  • 8
  • 94
  • 151
13

With the new C# 8, you can combine both return and switch. The new switch is so cute.

public static RGBColor FromRainbow(Rainbow colorBand) =>
    colorBand switch
    {
        Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
        Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
        Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
        Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
        Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
        Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
        Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
        _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand))
    };

The equivalent old switch is as below.

public static RGBColor FromRainbowClassic(Rainbow colorBand)
{
    switch (colorBand)
    {
        case Rainbow.Red:
            return new RGBColor(0xFF, 0x00, 0x00);
        case Rainbow.Orange:
            return new RGBColor(0xFF, 0x7F, 0x00);
        case Rainbow.Yellow:
            return new RGBColor(0xFF, 0xFF, 0x00);
        case Rainbow.Green:
            return new RGBColor(0x00, 0xFF, 0x00);
        case Rainbow.Blue:
            return new RGBColor(0x00, 0x00, 0xFF);
        case Rainbow.Indigo:
            return new RGBColor(0x4B, 0x00, 0x82);
        case Rainbow.Violet:
            return new RGBColor(0x94, 0x00, 0xD3);
        default:
            throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand));
    };
}

You can read about this feature here.

Sibeesh Venu
  • 18,755
  • 12
  • 103
  • 140
6
switch(a)
{
    case 1: return "lalala";
    case 2: return "blalbla";
    case 3: return "lolollo";
    default: return "default";
}
djdd87
  • 67,346
  • 27
  • 156
  • 195
Ahmet Kakıcı
  • 6,294
  • 4
  • 37
  • 49
6

This is the closest I can think of:

return    a==1 ? "lalala"
        : a==2 ? "blalbla"
        : a==3 ? "lolollo"
        : "default";
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
4

My mapping solution looks like Jordão's solution but it is more flexible and shorter.

return a
  .Map(1,"lalala")
  .Map(2,"blabla")
  .Map(3,"lololo")
  .Else(string.Empty);

Both arguments can also be a function:

return a
    .Map(x => x <= 0, "lalala")
    .Map(2, "blabla")
    .Map(x => x >= 3, x => "lololo" + x.ToString()); // lololo3 etc.
Alex Siepman
  • 2,499
  • 23
  • 31
3

I've created a Nuget package (FluentSwitch) that should do what you want. So you can do the following:

var result = myValue.Switch()
    .When(1, "lalala")
    .When(2, "blalbla")
    .When(3, "lolollo")
    .Else("default")
    .Value();
mrstebo
  • 911
  • 9
  • 12
2

Using latest version of C# I have done with following way :

public string GetValue(string name)
        {
            return name switch
            {
                var x when name is "test1" || name is "test2" => "finch",
                "test2" => somevalue,
                _ => name
            };
        }
Nic
  • 439
  • 4
  • 14
1

If you want switch to return value, you can use delegate:

int a = 2;
string result = new Func<string>(delegate ()
{
    switch (a)
    {
        case 1: return "lalala";
        case 2: return "blalbla";
        case 3: return "lolollo";
        default: return "default";
    }
})();

Or:

int a = 2;
string result = new Func<int,string>(delegate (int i)
{
    switch (i)
    {
        case 1: return "lalala";
        case 2: return "blalbla";
        case 3: return "lolollo";
        default: return "default";
    }
})(a);

Or just use lambda:

int a = 2;
string result = new Func<int,string>((int i) =>
{
    switch (i)
    {
        case 1: return "lalala";
        case 2: return "blalbla";
        case 3: return "lolollo";
        default: return "default";
    }
})(a);
Cluster
  • 998
  • 10
  • 14
1

As an extension to others' responses, i recommend using tuples together with return switch when a few parameters are involved in decision making. This combination with discard is pretty strong:

return (param1, param2, param3) switch
{
    (value1, value2, value3) => returnValue1,
    (value2, _, value3) => returnValue2
    (value3, _, _) => returnValue3

}

Another sample by Microsoft: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#tuple-patterns

Adel Tabareh
  • 1,478
  • 14
  • 10
0

We can have one use case where we may need to return the value from condition written inside the switch; let's say:

public void SomeMethod(SomeType enumType)  
{   
    switch (enumType)  
    {  
        case a:  
            if (condition)  
            {  
                if (condition1  && condition2)  
                {  
                    return true;  
                }  
            }  
            return false;  
            //break; break is actually not be required here if return used before break  
        case b:  
            if (condition)  
            {  
                if (condition3  && condition4)  
                {  
                    return true;  
                }  
            }  
            return false;  
            // break;  
        default:  
            return false;  
            //break;  
    }  

    Public enum SomeType  
    {  
        a,  
        b,  
        c,  
        d  
    }  
Cairnarvon
  • 25,981
  • 9
  • 51
  • 65
Rupz
  • 1
  • 1
0
public String doStaff(int a) {

   switch(a)
       {
          case 1: return "lalala"
          case 2: return "blalbla"
          case 3: return "lolollo"
          default: return "default" 
       };
}
-2

You can use (switch case) instead of (if statement).

    public InvoiceDeliveryStatus InvoiceDeliveryStatus { get; set; }

public string GetInvoiceDeliveryStatusTxt { get { return InvoiceDeliveryStatusSwitch(); } }


        private string InvoiceDeliveryStatusSwitch()
        {
           
            if (InvoiceDeliveryStatus == InvoiceDeliveryStatus.Canceled) return "Is Rejected";
            if (InvoiceDeliveryStatus == InvoiceDeliveryStatus.Completed) return "Is Completed";
       

                return InvoiceDeliveryStatus.ToString();
        }