Switch case in C# - a constant value is expected
Asked Answered
A

9

122

My code is as follows:

public static void Output<T>(IEnumerable<T> dataSource) where T : class
{   
    dataSourceName = (typeof(T).Name);
    switch (dataSourceName)
    {
        case (string)typeof(CustomerDetails).Name.ToString(); :
            var t = 123;
            break;
        default:
            Console.WriteLine("Test");
    }
}

But this is not working. The case statement is giving me an error saying that a constant variable is expected. Please help guys thank you!

Alby answered 29/9, 2011 at 6:35 Comment(1)
possible duplicate of C# - Is there a better alternative than this to 'switch on type'?Kudva
P
86

There is this trick which was shared with me (don't ask for details - won't be able to provide them, but it works for me):

switch (variable_1)
{
    case var value when value == variable_2: // that's the trick
        DoSomething();
        break;
    default:
        DoSomethingElse();
        break;
}
Professional answered 9/1, 2021 at 12:36 Comment(5)
Ouch, thanks!!! Why in the hell this works?!?! It functions with the C# 8.0 variable switch lambda too: variable_1 switch var value when value == variable_2:Suspense
in my case variable_2 was nameof(Enums.FormControlType.TextBox).ToLower(), in case statement nameof(Enums.FormControlType.TextBox) work as const but adding to .ToLower() results in error, It works in C#7.3 in my caseLonnie
Maybe use the discard var instead of var value and test variable_1 == variable_2 instead. case var _ when variable_1 == variable_2:Duffer
You can use this because of the new Pattern Matching implementation in switches in C#7Callow
I'd rather have a big if else if else than use this hockey solutionWagtail
S
58

See C# switch statement limitations - why?

Basically Switches cannot have evaluated statements in the case statement. They must be statically evaluated.

Sibyls answered 29/9, 2011 at 6:39 Comment(2)
This is not true in VB.net... I am trying to convert a code which already have this kind of case values (basically methods calls)Gaunt
@Moslem Ben Dhaou yes C# Switch is definitely not equivalent to the VB Case statement. For Case statements you can use expressions (function calls, variables, etc) whereas C# needs constant values (no function calls, variables, etc). The switch statement is quite limited comparably.Sibyls
A
43

You can only match to constants in switch statements.


Example:

switch (variable1)
{
    case 1: // A hard-coded value
        // Code
        break;
    default:
        // Code
        break;
}

Successful!


switch (variable1)
{
    case variable2:
        // Code
        break;
    default:
        // Code
        break;
}

CS0150 A constant value is expected.

Ablebodied answered 29/9, 2011 at 6:40 Comment(1)
As an additional note: "const int myConstant = 3" counts as a constant, but "readonly static int myReadonlyStatic = 3" doesn't.Crooks
C
38

Now you can use nameof:

public static void Output<T>(IEnumerable<T> dataSource) where T : class
{
    string dataSourceName = typeof(T).Name;
    switch (dataSourceName)
    {
        case nameof(CustomerDetails):
            var t = 123;
            break;
        default:
            Console.WriteLine("Test");
    }
}

nameof(CustomerDetails) is basically identical to the string literal "CustomerDetails", but with a compile-time check that it refers to some symbol (to prevent a typo).

nameof appeared in C# 6.0, so after this question was asked.

Clack answered 27/4, 2019 at 20:5 Comment(0)
C
14

You can't use a switch statement for this as the case values cannot be evaluated expressions. For this you have to use an an if/else ...

public static void Output<T>(IEnumerable<T> dataSource) where T : class
{   
    dataSourceName = (typeof(T).Name);
    if(string.Compare(dataSourceName, typeof(CustomerDetails).Name.ToString(), true)==0)
    {
        var t = 123;
    }
    else if (/*case 2 conditional*/)
    {
        //blah
    }
    else
    {
        //default case
        Console.WriteLine("Test");
    }
}

I also took the liberty of tidying up your conditional statement. There is no need to cast to string after calling ToString(). This will always return a string anyway. When comparing strings for equality, bare in mind that using the == operator will result in a case sensitive comparison. Better to use string compare = 0 with the last argument to set case sensitive on/off.

Chancechancel answered 29/9, 2011 at 7:37 Comment(0)
T
13

This seems to work for me at least when i tried on visual studio 2017.

public static class Words
{
     public const string temp = "What";
     public const string temp2 = "the";
}
var i = "the";

switch (i)
{
  case Words.temp:
    break;
  case Words.temp2:
    break;
}
Tawny answered 15/3, 2019 at 23:58 Comment(1)
Nothing to be with VS2017. Words.temp and Words.temp2 are still constants. When compiling Switch statements the compiler will replace the "case values" by its actual value. As long as the compiler is able to get a constant value to use, it will work fine.Decontrol
T
3

switch is very picky in the sense that the values in the switch must be a compile time constant. and also the value that's being compared must be a primitive (or string now). For this you should use an if statement.

The reason may go back to the way that C handles them in that it creates a jump table (because the values are compile time constants) and it tries to copy the same semantics by not allowing evaluated values in your cases.

Terebinthine answered 29/9, 2011 at 6:40 Comment(0)
U
3

Johnnie, Please go through msdn guide on switch. Also, the C# language specification clearly defines the compile time error case:

• If the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string, or an enum-type, or if it is the nullable type corresponding to one of these types, then that is the governing type of the switch statement.

• Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or, a nullable type corresponding to one of those types.

• Otherwise, if no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.

Hope this helps.

Udela answered 29/9, 2011 at 6:49 Comment(0)
E
0

This does require the latest or close to latest version of C#. The advantage is that the variable 'value' in this example can be manipulated, like this,

   switch (args[1])

                {
                    case var value when string.Equals(value, "SELECT_ALL", StringComparison.OrdinalIgnoreCase):
{
....
break;
}
   case var value when string.Equals(value, "UNSELECT_ALL", StringComparison.OrdinalIgnoreCase):

                        {
...
...
break;
}

etc. etc.

which makes sure that you never match to the wrong literal, in this case, because you forgot to use ToUpper() or whatever...

Ec answered 28/4, 2022 at 15:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.