C# - Get switch value if in default case
Asked Answered
T

5

16

Help please, I have this case:

switch(MyFoo()){
    case 0: //...
        break;
    case 1: //...
        break;
    case 2: //...
        break;
    default:
        // <HERE>
        break;
}

As you can see the switch gets the value directly from a method without saving it as a variable.

Is it possible to get which value fires the default case? For example if MyFoo() returns 7, how can I get that value?

I want to avoid to save the method result as a variable, is there a way to get the switch value from inside a case? Something like this:

default:
    this.SwitchValue // <<--
    break;

Thank you for reading, ~Saba

Tights answered 14/4, 2015 at 13:22 Comment(5)
"I want to avoid to save the method result as a variable" - why?Lafontaine
If you call MyFoo() again, will it return the same value?Lafontaine
"I want to avoid to save the method result as a variable" - There is no reason not to. It's on the stack anyway.Gussi
Your approach to me, seems like poor architecture and design.Lothar
This is a good can the language do that question, because it can't do that and so it is obviously not documented. Keep a trace about it is a job for SO.Foxe
F
15

Is there a way to get the switch value from inside a case?

The only (proper) way is actually to store the result of MyFoo() in a variable.

var fooResult = MyFoo();
switch (fooResult)
{
    case 0:
        ...
        break;
    ...
    default:
        handleOthersCase(fooResult);
        break;
}

This code is readable and understandable and have no extra cost (As @SheldonNeilson says: It's on the stack anyway).

Also, the MSDN first example about switch totally look like this. You can also find informations int the language specification.

You also can make your own switch based on a dictionary, but the only advantage I see is that you can use it for complex cases (any kind of object instead of string/int/...). Performance is a drawback.

It may look like this:

public class MySwitch<T> : Dictionary<T, Action<T>>
{
    private Action<T> _defaultAction;

    public void TryInvoke(T value)
    {
        Action<T> action;
        if (TryGetValue(value, out action))
        {
            action(value);
        }
        else
        {
            var defaultAction = _defaultAction;
            if (defaultAction != null)
            {
                defaultAction(value);
            }
        }
    }

    public void SetDefault(Action<T> defaultAction)
    {
        _defaultAction = defaultAction;
    }
}

And be used like this:

var mySwitch = new MySwitch<int>();

mySwitch.Add(1, i => Console.WriteLine("one"));                             // print "one"
mySwitch.Add(2, i => Console.WriteLine("two"));                             // print "two"
mySwitch.SetDefault(i => Console.WriteLine("With the digits: {0}", i));     // print any other value with digits.

mySwitch.TryInvoke(42);                                                     // Output: "With the digits: 42"

Or based on this response, this:

public class MySwitch2<T>
{
    private readonly T _input;

    private bool _done = false;

    private MySwitch2(T input)
    {
        _input = input;
    }

    public MySwitch2<T> On(T input)
    {
        return new MySwitch2<T>(input);
    }

    public MySwitch2<T> Case(T caseValue, Action<T> action)
    {
        if (!_done && Equals(_input, caseValue))
        {
            _done = true;
            action(_input);
        }
        return this;
    }

    public void Default(Action<T> action)
    {
        if (!_done)
        {
            action(_input);
        }
    }
}

Can be used like that:

MySwitch2<int>.On(42)
    .Case(1, i => Console.WriteLine("one"))
    .Case(2, i => Console.WriteLine("two"))
    .Default(i => Console.WriteLine("With the digits: {0}", i));
Foxe answered 14/4, 2015 at 13:28 Comment(3)
Wouldn't it be nicer if you could do the following so that fooResult is only visible in the scope of the switch block? switch (var fooResult = MyFoo()) { case 0: ... break; ... default: handleOthersCase(fooResult); break; }Awoke
...if you agree, please vote at visualstudio.uservoice.com/forums/121579-visual-studio/…Awoke
The problem is just that a goto case statement that refers to an undeclared case and therefore will go to the default will not pass the case label value because it's not the value of the case variable.Pavior
E
6

I can't see a reason as well why to use it like that but may be a work around will be like this:

int x;
switch ( x = MyFoo())
{
    case 0: //...
        break;
    case 1: //...
        break;
    case 2: //...
        break;
    default:
        var s = x; // Access and play with x here
        break;
}
Educator answered 14/4, 2015 at 13:31 Comment(0)
A
3

No, this isn't possible. You can assign the value to variable inside switch, if you want to look like reinventing the wheel:

        int b;
        .....
        switch (b = MyFoo())
        {
            case 1:
                break;
            case 2:
                break;
            default:
                //do smth with b
                break;
        }
Aquatic answered 14/4, 2015 at 13:32 Comment(0)
C
2

This is possible now.

https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#property-patterns

Example:

int? TryGetColumnIndex(string columnName)
    => GetValue(columnName)
    switch
    { var result when result > -1 => result, _ => new int?() };

result will capture the result of GetValue.

Even cooler, you can do propery checks.

i.e instead of when result > -1 you can even say when result.ToString().Length > 2 and such.

Cordovan answered 15/2, 2022 at 16:35 Comment(1)
but can we capture it for default?Collision
B
1

The easiest way is to save the result of MyFoo() as a variable.. But if you don't want to do that you could do:

switch(MyFoo()){
    case 0: //...
        break;
    case 1: //...
        break;
    case 2: //...
        break;
    default:
        this.SwitchCase = MyFoo();
        break;
}

Although I would advise against this and say save the value as a variable to save your program the extra work.

Saving the value of MyFoo as a variable becomes more important the more complex the example gets as the value of MyFoo could have changed between the switch and default case.

Also this will only work where MyFoo has no side-effects and obviously must always return the same value for any given parameter.

for example the following would work:

Private int MyFoo()
{
   return 3;
}

But the following would not:

private int MyFoo()
{
  Random r = new Random();
  return r.Next(5);
}
Bramwell answered 14/4, 2015 at 13:30 Comment(1)
I don't think the edit here makes the answer any clearer, the concept of a pure function is clearer than the replacement text in my opinion.Profiterole

© 2022 - 2024 — McMap. All rights reserved.