web-dev-qa-db-fra.com

C # Chaîne de casse de commutation commençant par

Existe-t-il un moyen de créer une condition de casse dans une instruction switch où vous dites si une chaîne commence par quelque chose?

ex

Switch (mystring)
{
   case("abc")://String begins with abc (abcd or abc1 or abcz or abc.. or abc will fall in this condition).
      //Do Something
      break;
   default:
      break;
}

UPDATE D'autres chaînes peuvent avoir une longueur différente.

abc..

abczyv

dcs2.

qwerty

demander

41
Amra

Si vous saviez que la durée des conditions dont vous vous souciez serait la même, alors vous pourriez:

switch(mystring.substring(0, Math.Min(3, mystring.Length))
{
  case "abc":
    //do something
    break;
  case "xyz":
    //do something else
    break;
  default:
    //do a different thing
    break;
}

La Math.Min(3, mystring.Length) est là pour qu'une chaîne de moins de 3 caractères ne lève pas d'exception sur l'opération de sous-chaîne.

Il existe des extensions de cette technique pour correspondre, par exemple un tas de chaînes de 2 caractères et un tas de chaînes de 3 caractères, où certaines comparaisons de 2 caractères correspondant sont ensuite suivies de comparaisons de 3 caractères. Sauf si vous avez un très grand nombre de telles chaînes, cela devient rapidement moins efficace qu'un simple chaînage if-else pour le code en cours d'exécution et la personne qui doit le maintenir.

Edit: ajouté puisque vous avez maintenant déclaré qu'ils seront de longueurs différentes. Vous pouvez faire le modèle que j'ai mentionné en vérifiant les premiers caractères X puis les caractères Y suivants et ainsi de suite, mais à moins qu'il n'y ait un modèle où la plupart des chaînes sont de la même longueur, ce sera à la fois inefficace et horrible à maintenir (un cas classique de pessimisation prématurée).

Le modèle de commande est mentionné dans une autre réponse, donc je ne donnerai pas de détails à ce sujet, comme c'est le cas lorsque vous mappez des modèles de chaîne à des ID, mais ils sont optionnels.

Je ne changerais pas de chaînes if-else à des modèles de commande ou de mappage pour gagner le commutateur d'efficacité parfois a plus de if-else, car vous perdez plus dans les comparaisons pour la commande ou l'obtention du modèle d'ID. Je le ferais bien si cela rendait le code plus clair.

Une chaîne de if-else peut fonctionner assez bien, soit avec des comparaisons de chaînes soit avec des expressions régulières (cette dernière si vous avez des comparaisons plus compliquées que les correspondances de préfixes jusqu'à présent, ce qui serait probablement plus simple et plus rapide, je mentionne reg- ex juste parce qu'ils fonctionnent parfois bien avec des cas plus généraux de ce type de modèle).

Si vous optez pour des if-elses, essayez de considérer les cas qui se produiront le plus souvent et faites ces tests avant ceux pour les cas moins courants (bien que, bien sûr, si "commence par abcd" soit un cas à rechercher, il serait doivent être vérifiés avant "commence par abc").

38
Jon Hanna

Réponse courte: Non.

L'instruction switch prend une expression qui n'est évaluée qu'une seule fois. Sur la base du résultat, un autre morceau de code est exécuté.

Et alors? => String.StartsWith est une fonction. Avec un paramètre donné, c'est une expression. Cependant, pour votre cas, vous devez passer un paramètre différent pour chaque cas, il ne peut donc pas être évalué une seule fois.

La réponse longue n ° 1 a été donnée par d'autres.

Réponse longue # 2:

Selon ce que vous essayez de réaliser, vous pourriez être intéressé par le modèle de commande / modèle de chaîne de responsabilité. Appliqué à votre cas, chaque morceau de code serait représenté par une implémentation d'une Command. En plus de la méthode exécuter, la commande peut fournir une méthode booléenne Accepter, qui vérifie si la chaîne donnée commence par le paramètre respectif.

Avantage: au lieu de votre déclaration de commutateur codée en dur, de Starts codés en dur avec des évaluations et des chaînes codées en dur, vous auriez beaucoup plus de flexibilité.

L'exemple que vous avez donné dans votre question ressemblerait alors à ceci:

var commandList = new List<Command>() { new MyABCCommand() };

foreach (Command c in commandList)
{
    if (c.Accept(mystring))
    {
        c.Execute(mystring);
        break;
    }
}

class MyABCCommand : Command
{
    override bool Accept(string mystring)
    {
        return mystring.StartsWith("abc");
    }
}    
13
chiccodoro

Si tous les étuis ont la même longueur, vous pouvez utiliser
switch (mystring.SubString(0,Math.Min(len, mystring.Length))).
Une autre option est d'avoir une fonction qui retournera categoryId en fonction de la chaîne et activera l'id.

5
Itay Karo

Cela est désormais possible avec la mise en correspondance des modèles de C # 7.0. Par exemple:

var myString = "abcDEF";

switch(myString)
{
    case string x when x.StartsWith("abc"):
        //Do something here
        break;
}
4
Raúl Bojalil

Si le domaine problématique a une sorte de concept d'en-tête de chaîne, cela pourrait être modélisé comme une énumération.

switch(GetStringHeader(s))
{
    case StringHeader.ABC: ...
    case StringHeader.QWERTY: ...
    ...
}

StringHeader GetStringHeader(string s)
{
    if (s.StartsWith("ABC")) return StringHeader.ABC;
    ...
}

enum StringHeader { ABC, QWERTY, ... }
3
Felix Ungman

En plus de la réponse de la sous-chaîne, vous pouvez le faire en tant que mystring.SubString (0,3) et vérifier dans l'instruction case si son "abc".

Mais avant la déclaration de changement, vous devez vous assurer que votre mystring a une longueur d'au moins 3.

1
Sachin Shanbhag