115

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!

implmentor
  • 1,386
  • 4
  • 21
  • 32
johnnie
  • 1,837
  • 5
  • 23
  • 36
  • possible duplicate of [C# - Is there a better alternative than this to 'switch on type'?](http://stackoverflow.com/questions/298976/c-is-there-a-better-alternative-than-this-to-switch-on-type) –  Sep 29 '11 at 06:42

9 Answers9

67

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;
}
MjH
  • 1,170
  • 1
  • 8
  • 16
  • 2
    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:` – Marcelo Scofano Diniz Aug 11 '21 at 01:53
  • 1
    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 case – abdul qayyum Jan 18 '22 at 11:57
  • 3
    Maybe use the discard var instead of var value and test variable_1 == variable_2 instead. `case var _ when variable_1 == variable_2:` – Nk54 Jun 10 '22 at 14:46
  • 1
    You can use this because of the new Pattern Matching implementation in switches in C#7 – Jeferson Almeida Nov 09 '22 at 17:31
  • I'd rather have a big `if else if else` than use this hockey solution – motcke May 14 '23 at 01:02
55

See C# switch statement limitations - why?

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

Community
  • 1
  • 1
deepee1
  • 12,878
  • 4
  • 30
  • 43
  • 7
    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) – Moslem Ben Dhaou Jan 08 '15 at 19:53
  • 6
    @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. – deepee1 Jan 08 '15 at 22:54
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.

Community
  • 1
  • 1
Maximilian Mayerl
  • 11,253
  • 2
  • 33
  • 40
  • 34
    As an additional note: "const int myConstant = 3" counts as a constant, but "readonly static int myReadonlyStatic = 3" doesn't. – Stachu Dec 31 '13 at 20:13
34

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.

0xF
  • 3,214
  • 1
  • 25
  • 29
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.

implmentor
  • 1,386
  • 4
  • 21
  • 32
iDevForFun
  • 978
  • 6
  • 10
12

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;
}
Korey
  • 261
  • 3
  • 15
  • 3
    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. – Zé Carlos Jun 14 '19 at 13:02
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.

Jesus Ramos
  • 22,940
  • 10
  • 58
  • 88
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.

AksharRoop
  • 2,263
  • 1
  • 19
  • 29
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...

Allen
  • 546
  • 5
  • 12