Schaltfall in C # - ein konstanter Wert wird erwartet

70

Mein Code lautet wie folgt:

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");
    }
}

Das funktioniert aber nicht. Die case-Anweisung gibt mir einen Fehler, der besagt, dass eine konstante Variable erwartet wird. Bitte helfen Sie Jungs, danke!

Johnnie
quelle

Antworten:

44

Siehe Einschränkungen der C # -Schalteranweisung - warum?

Grundsätzlich können Switches keine Anweisungen in der case-Anweisung ausgewertet haben. Sie müssen statisch ausgewertet werden.

deepee1
quelle
7
Dies ist nicht wahr in VB.net ... Ich versuche, einen Code zu konvertieren, der bereits diese Art von
Fallwerten hat
6
@ Moslem Ben Dhaou ja C # -Schalter entspricht definitiv nicht der VB-Case-Anweisung. Für Case-Anweisungen können Sie Ausdrücke (Funktionsaufrufe, Variablen usw.) verwenden, während C # konstante Werte benötigt (keine Funktionsaufrufe, Variablen usw.). Die switch-Anweisung ist vergleichsweise begrenzt.
deepee1
36

Sie können nur mit Konstanten in switch-Anweisungen übereinstimmen.


Beispiel:

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

Erfolgreich!


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

CS0150 Ein konstanter Wert wird erwartet.

Maximilian Mayerl
quelle
23
Als zusätzliche Anmerkung: "const int myConstant = 3" zählt als Konstante, "readonly static int myReadonlyStatic = 3" jedoch nicht.
Stachu
13

Sie können hierfür keine switch-Anweisung verwenden, da die Fallwerte keine ausgewerteten Ausdrücke sind. Dafür müssen Sie ein if / else verwenden ...

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");
    }
}

Ich habe mir auch erlaubt, Ihre bedingte Aussage aufzuräumen. Nach dem Aufruf muss keine Zeichenfolge umgewandelt werden ToString(). Dies gibt sowieso immer einen String zurück. Beachten Sie beim Vergleichen von Zeichenfolgen auf Gleichheit, dass die Verwendung des Operators == zu einem Vergleich führt, bei dem zwischen Groß- und Kleinschreibung unterschieden wird. Verwenden Sie besser string compare = 0 mit dem letzten Argument, um die Groß- und Kleinschreibung ein- und auszuschalten.

iDevForFun
quelle
11

Jetzt können Sie verwenden 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)ist im Grunde identisch mit dem String-Literal "CustomerDetails", jedoch mit einer Überprüfung zur Kompilierungszeit, dass es sich auf ein Symbol bezieht (um einen Tippfehler zu verhindern).

nameof erschien in C # 6.0, also nachdem diese Frage gestellt wurde.

0xF
quelle
6

Dies scheint für mich zumindest zu funktionieren, als ich Visual Studio 2017 anprobierte.

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
quelle
3
Nichts mit VS2017 zu sein. Words.temp und Words.temp2 sind immer noch Konstanten. Beim Kompilieren von Switch-Anweisungen ersetzt der Compiler die "case-Werte" durch ihren tatsächlichen Wert. Solange der Compiler einen konstanten Wert zur Verwendung erhält, funktioniert er einwandfrei.
Zé Carlos
3

switch ist sehr wählerisch in dem Sinne, dass die Werte im switch eine Kompilierungszeitkonstante sein müssen. und auch der Wert, der verglichen wird, muss ein Grundelement (oder jetzt eine Zeichenfolge) sein. Verwenden Sie dazu eine if-Anweisung.

Der Grund kann auf die Art und Weise zurückgehen, wie C sie behandelt, indem es eine Sprungtabelle erstellt (da die Werte Kompilierungszeitkonstanten sind) und versucht, dieselbe Semantik zu kopieren, indem in Ihren Fällen keine ausgewerteten Werte zugelassen werden.

Jesus Ramos
quelle
3

Johnnie, bitte gehen Sie die MSDN-Anleitung zum Schalter durch . Außerdem definiert die C # -Sprachenspezifikation den Fehlerfall bei der Kompilierung klar:

• Wenn der Typ des switch-Ausdrucks sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string oder ein Aufzählungstyp ist oder wenn es sich um den nullbaren Typ handelt, der einem dieser Typen entspricht , dann ist das der maßgebliche Typ der switch-Anweisung.

• Andernfalls muss genau eine benutzerdefinierte implizite Konvertierung (§6.4) vom Typ des Schalterausdrucks zu einem der folgenden möglichen maßgeblichen Typen vorhanden sein: sbyte, byte, kurz, ushort, int, uint, long, ulong, char, Zeichenfolge oder ein nullbarer Typ, der einem dieser Typen entspricht.

• Andernfalls tritt ein Fehler zur Kompilierungszeit auf, wenn keine solche implizite Konvertierung vorhanden ist oder wenn mehr als eine solche implizite Konvertierung vorhanden ist.

Hoffe das hilft.

AksharRoop
quelle