Combine return and switch

后端 未结 12 2060
长情又很酷
长情又很酷 2021-02-03 22:15

How can I combine return and switch case statements?

I want something like

return switch(a)
       {
          case 1:\"lalala         


        
相关标签:
12条回答
  • 2021-02-03 22:25

    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  
        }  
    
    0 讨论(0)
  • 2021-02-03 22:28

    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");
    
    0 讨论(0)
  • 2021-02-03 22:30

    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;
    
    0 讨论(0)
  • 2021-02-03 22:34

    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";
    
    0 讨论(0)
  • 2021-02-03 22:36
    public String doStaff(int a) {
    
       switch(a)
           {
              case 1: return "lalala"
              case 2: return "blalbla"
              case 3: return "lolollo"
              default: return "default" 
           };
    }
    
    0 讨论(0)
  • 2021-02-03 22:37

    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.

    0 讨论(0)
提交回复
热议问题