web-dev-qa-db-fra.com

Pourquoi l'interpolation de chaîne ne fonctionne pas avec les chaînes const

Pourquoi l'interpolation de chaîne en c # ne fonctionne-t-elle pas avec les chaînes const? Par exemple:

private const string WEB_API_ROOT = "/private/WebApi/";
private const string WEB_API_PROJECT = $"{WEB_API_ROOT}project.json";

De mon point de vue, tout est connu au moment de la compilation. Ou est-ce une fonctionnalité qui sera ajoutée plus tard?

Message du compilateur:

L'expression affectée à 'DynamicWebApiBuilder.WEB_API_PROJECT' doit être constante.

Merci beaucoup!

19
BendEg

Les chaînes interpolées sont simplement converties en appels à string.Format. Donc, votre ligne ci-dessus lit réellement

private const string WEB_API_PROJECT = string.Format("{0}project.json", WEB_API_ROOT);

Et ce n’est pas une constante de temps de compilation car un appel de méthode est inclus.


D'autre part, string concaténation (de littéraux de chaîne simples et constants) peut être effectué par le compilateur, donc cela fonctionnera:

private const string WEB_API_ROOT = "/private/WebApi/";
private const string WEB_API_PROJECT = WEB_API_ROOT + "project.json";

ou passez de const à static readonly:

private static readonly string WEB_API_PROJECT = $"{WEB_API_ROOT}project.json";

la chaîne est donc initialisée (et string.Format appelée) lors du premier accès à un membre du type déclarant.

33
René Vogt

Une explication supplémentaire pour laquelle les expressions d'interpolation de chaînes ne sont pas considérées comme constantes est que elles ne sont pas constantes , même si toutes leurs entrées sont des constantes. Plus précisément, ils varient en fonction de la culture actuelle. Essayez d’exécuter le code suivant:

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

Console.WriteLine($"{3.14}");

CultureInfo.CurrentCulture = new CultureInfo("cs-CZ");

Console.WriteLine($"{3.14}");

Sa sortie est:

3.14
3,14

Notez que la sortie est différente, même si l'expression d'interpolation de chaîne est la même dans les deux cas. Donc, avec const string pi = $"{3.14}", le code que le compilateur devrait générer ne serait pas clair.

15
svick

Il y a une discussion dans le projet Roslyn à roslyn qui conclut la conclusion suivante:

Lire l'extrait:

Ce n'est pas un bug, il a été explicitement conçu pour fonctionner comme ceci. Si vous ne l'aimez pas, cela n'en fait pas un bug. String.Format n'est pas nécessaire pour concaténer des chaînes, mais ce n'est pas le cas que fais tu. Vous les interpolez et String.Format est nécessaire pour cela en fonction de la spécification et de la mise en œuvre de comment. l'interpolation fonctionne en C #. 

Si vous voulez concaténer des chaînes, allez et utilisez la même syntaxe que celle utilisée depuis C # 1.0 . Modifier l’implémentation pour qu’il se comporte différemment en fonction de l’utilisation rendrait. produire des résultats inattendus:

  const string FOO = "FOO";
  const string BAR = "BAR";
  string foobar = $"{FOO}{BAR}";
  const string FOOBAR = $"{FOO}{BAR}"; // illegal today

  Debug.Assert(foobar == FOOBAR); // might not always be true

Même la déclaration:

  private static readonly string WEB_API_PROJECT = $"{WEB_API_ROOT}project.json";

Le compilateur génère une erreur:

 "The name 'WEB_API_ROOT' does not exist in the current context". 

La variable 'WEB_API_ROOT' doit être définie dans le même contexte 

Donc, pour la question de OP: Pourquoi l’interpolation de chaîne ne fonctionne-t-elle pas avec les chaînes const? pour plus de détails, lisez .NET Compiler Platform ("Roslyn") - Interpolation de chaînes pour C #

5
M.Hassan

Une constante utilisée avec string.Format serait, par nature, destinée à fonctionner avec un nombre spécifique d'arguments ayant chacun une signification prédéterminée.

En d'autres termes, si vous créez cette constante:

const string FooFormat = "Foo named '{0}' was created on {1}.";

Ensuite, pour l'utiliser, vous devez avoir deux arguments qui sont probablement supposés être un string et un DateTime

Donc, même avant l'interpolation des chaînes, nous utilisions en quelque sorte la constante comme fonction. En d’autres termes, au lieu de séparer la constante, il aurait peut-être été plus logique de la placer dans une fonction, comme ceci:

string FormatFooDescription(string fooName, DateTime createdDate) =>
    string.Format("Foo named '{0}' was created on {1}.", fooName, createdDate);

C'est toujours la même chose, sauf que la constante (chaîne littérale) se trouve maintenant avec la fonction et les arguments qui l'utilisent. Ils pourraient aussi bien être ensemble, parce que la chaîne de format est inutile à d’autres fins. De plus, vous pouvez maintenant voir l'intention des arguments qui sont appliqués à la chaîne de formatage.

Lorsque nous considérons cela de la sorte, l’utilisation similaire de l’interpolation de chaîne devient évidente:

string FormatFooDescription(string fooName, DateTime createdDate) =>
    $"Foo named '{fooName}' was created on {createdDate}.";

Que faire si nous avons plusieurs chaînes de format et que nous voulons en choisir une au moment de l'exécution?

Au lieu de choisir quelle chaîne utiliser, nous pourrions sélectionner une fonction:

delegate string FooDescriptionFunction(string fooName, DateTime createdDate);

Ensuite, nous pourrions déclarer des implémentations comme ceci:

static FooDescriptionFunction FormatFoo { get; } = (fooName, createdDate) => 
    $"Foo named '{fooName}' was created on {createdDate}.";

Ou mieux encore:

delegate string FooDescriptionFunction(Foo foo);

static FooDescriptionFunction FormatFoo { get; } = (foo) => 
    $"Foo named '{foo.Name}' was created on {foo.CreatedDate}.";
}
0
Scott Hannen