C# Language Interpolation de chaîne

Exemple

L'interpolation de chaînes permet au développeur de combiner des variables et du texte pour former une chaîne.


Exemple de base

Deux variables int sont créées: foo et bar .

int foo = 34;
int bar = 42;

string resultString = $"The foo is {foo}, and the bar is {bar}.";

Console.WriteLine(resultString);

Sortie :

Le foo est 34 et le bar 42.

Voir la démo

Les accolades dans les chaînes peuvent toujours être utilisées, comme ceci:

var foo = 34;
var bar = 42;

// String interpolation notation (new style)
Console.WriteLine($"The foo is {{foo}}, and the bar is {{bar}}.");

Cela produit la sortie suivante:

Le foo est {foo}, et la barre est {bar}.


Utilisation de l'interpolation avec des littéraux de chaîne textuels

L'utilisation de @ avant la chaîne entraînera l'interprétation de la chaîne textuellement. Par exemple, les caractères Unicode ou les sauts de ligne resteront exactement tels qu'ils ont été saisis. Cependant, cela n'affectera pas les expressions d'une chaîne interpolée, comme illustré dans l'exemple suivant:

Console.WriteLine($@"In case it wasn't clear:
\u00B9
The foo
is {foo},
and the bar
is {bar}.");
Sortie:

Au cas où ce ne serait pas clair:
\ u00B9
Le foo
est 34,
et le bar
est 42.

Voir la démo


Expressions

Avec l'interpolation de chaîne, les expressions entre accolades {} peuvent également être évaluées. Le résultat sera inséré à l'emplacement correspondant dans la chaîne. Par exemple, pour calculer le maximum de foo et de bar et l'insérer, utilisez Math.Max dans les accolades:

Console.WriteLine($"And the greater one is: { Math.Max(foo, bar) }");

Sortie:

Et le plus grand est: 42

Remarque: Tout espace de début ou de fin (espace, tabulation et CRLF / newline compris) entre l'accolade et l'expression est complètement ignoré et n'est pas inclus dans la sortie.

Voir la démo

Comme autre exemple, les variables peuvent être mises en forme en tant que devise:

Console.WriteLine($"Foo formatted as a currency to 4 decimal places: {foo:c4}");

Sortie:

Foo au format 4 décimales: $ 34.0000

Voir la démo

Ou ils peuvent être formatés en dates:

Console.WriteLine($"Today is: {DateTime.Today:dddd, MMMM dd - yyyy}");

Sortie:

Nous sommes aujourd'hui: lundi 20 juillet 2015

Voir la démo

Les instructions avec un opérateur conditionnel (ternaire) peuvent également être évaluées dans l'interpolation. Cependant, ceux-ci doivent être mis entre parenthèses, car les deux points sont utilisés pour indiquer le formatage comme indiqué ci-dessus:

Console.WriteLine($"{(foo > bar ? "Foo is larger than bar!" : "Bar is larger than foo!")}");

Sortie:

Le bar est plus grand que le foo!

Voir la démo

Les expressions conditionnelles et les spécificateurs de format peuvent être mélangés:

Console.WriteLine($"Environment: {(Environment.Is64BitProcess ? 64 : 32):00'-bit'} process");

Sortie:

Environnement: processus 32 bits


Séquences d'échappement

Les barres obliques inverses ( \ ) et les guillemets ( " ) fonctionnent exactement de la même manière dans les chaînes interpolées que dans les chaînes non interpolées, à la fois pour les chaînes littérales textuelles et non textuelles:

Console.WriteLine($"Foo is: {foo}. In a non-verbatim string, we need to escape \" and \\ with backslashes.");
Console.WriteLine($@"Foo is: {foo}. In a verbatim string, we need to escape "" with an extra quote, but we don't need to escape \");

Sortie:

Foo a 34 ans. Dans une chaîne non verbatim, nous devons nous échapper "et \ avec des barres obliques inverses.
Foo a 34 ans. Dans une chaîne verbatim, nous devons nous échapper "avec une citation supplémentaire, mais nous n'avons pas besoin de nous échapper \

Pour inclure une accolade { ou } dans une chaîne interpolée, utilisez deux accolades {{ ou }} :

$"{{foo}} is: {foo}"

Sortie:

{foo} est: 34

Voir la démo


Type de chaîne formatée

Le type d'une expression d'interpolation de chaîne $"..." n'est pas toujours une simple chaîne. Le compilateur décide quel type attribuer en fonction du contexte:

string s = $"hello, {name}";
System.FormattableString s = $"Hello, {name}";
System.IFormattable s = $"Hello, {name}";

C'est également l'ordre de préférence de type lorsque le compilateur doit choisir la méthode surchargée à appeler.

Un nouveau type , System.FormattableString , représente une chaîne de format composite, avec les arguments à mettre en forme. Utilisez ceci pour écrire des applications qui gèrent spécifiquement les arguments d'interpolation:

public void AddLogItem(FormattableString formattableString)
{
    foreach (var arg in formattableString.GetArguments())
    {
        // do something to interpolation argument 'arg'
    }

    // use the standard interpolation and the current culture info
    // to get an ordinary String:
    var formatted = formattableString.ToString();

    // ...
}

Appelez la méthode ci-dessus avec:

AddLogItem($"The foo is {foo}, and the bar is {bar}.");
Par exemple, on pourrait choisir de ne pas encourir le coût des performances de la mise en forme de la chaîne si le niveau de journalisation était déjà utilisé pour filtrer l'élément de journal.

Conversions implicites

Il existe des conversions de types implicites à partir d'une chaîne interpolée:

var s = $"Foo: {foo}";
System.IFormattable s = $"Foo: {foo}";
Vous pouvez également produire une variable IFormattable qui vous permet de convertir la chaîne avec un contexte invariant:
var s = $"Bar: {bar}";
System.FormattableString s = $"Bar: {bar}";

Méthodes de culture actuelles et invariantes

Si l'analyse de code est activée, les chaînes interpolées produiront toutes un avertissement CA1305 (spécifiez IFormatProvider ). Une méthode statique peut être utilisée pour appliquer la culture actuelle.

public static class Culture
{
    public static string Current(FormattableString formattableString)
    {
        return formattableString?.ToString(CultureInfo.CurrentCulture);
    }
    public static string Invariant(FormattableString formattableString)
    {
        return formattableString?.ToString(CultureInfo.InvariantCulture);
    }
}

Ensuite, pour produire une chaîne correcte pour la culture actuelle, utilisez simplement l'expression:

Culture.Current($"interpolated {typeof(string).Name} string.")
Culture.Invariant($"interpolated {typeof(string).Name} string.")
Remarque : Current et Invariant ne peuvent pas être créés en tant que méthodes d'extension car, par défaut, le compilateur attribue le type String à l' expression de chaîne interpolée , ce qui empêche la compilation du code suivant:

$"interpolated {typeof(string).Name} string.".Current();

FormattableString classe FormattableString contient déjà la méthode Invariant() , de sorte que le moyen le plus simple de passer à la culture invariante est d' using static :

using static System.FormattableString;

string invariant = Invariant($"Now = {DateTime.Now}"); string current = $"Now = {DateTime.Now}";


Dans les coulisses

Les chaînes interpolées ne sont qu'un sucre syntaxique pour String.Format() . Le compilateur ( Roslyn ) le transformera en String.Format en coulisse:

var text = $"Hello {name + lastName}";

Ce qui précède sera converti en quelque chose comme ceci:

string text = string.Format("Hello {0}", new object[] {
    name + lastName
});

Interpolation de chaînes et Linq

Il est possible d'utiliser des chaînes interpolées dans les instructions Linq pour augmenter la lisibilité.

var fooBar = (from DataRow x in fooBarTable.Rows
          select string.Format("{0}{1}", x["foo"], x["bar"])).ToList();

Peut être réécrit comme:

var fooBar = (from DataRow x in fooBarTable.Rows
          select $"{x["foo"]}{x["bar"]}").ToList();

Cordes interpolées réutilisables

Avec string.Format , vous pouvez créer des chaînes de format réutilisables:

public const string ErrorFormat = "Exception caught:\r\n{0}";

// ...

Logger.Log(string.Format(ErrorFormat, ex));

Les chaînes interpolées, cependant, ne seront pas compilées avec les espaces réservés faisant référence à des variables inexistantes. Les éléments suivants ne seront pas compilés:

public const string ErrorFormat = $"Exception caught:\r\n{error}";
// CS0103: The name 'error' does not exist in the current context

Au lieu de cela, créez un Func<> qui consomme des variables et renvoie une String :

public static Func<Exception, string> FormatError =
    error => $"Exception caught:\r\n{error}";

// ...

Logger.Log(FormatError(ex));

Interpolation et localisation de chaînes

Si vous localisez votre application, vous pouvez vous demander s'il est possible d'utiliser l'interpolation de chaînes avec la localisation. En effet, il serait agréable d'avoir la possibilité de stocker dans des fichiers ressources String s comme:

"My name is {name} {middlename} {surname}"
au lieu de beaucoup moins lisible:

"My name is {0} {1} {2}"

String processus d'interpolation de String se produit au moment de la compilation , contrairement à la chaîne de formatage avec string.Format qui se produit au moment de l'exécution . Les expressions dans une chaîne interpolée doivent référencer des noms dans le contexte actuel et doivent être stockées dans des fichiers de ressources. Cela signifie que si vous voulez utiliser la localisation, vous devez le faire comme:

var FirstName = "John";

// method using different resource file "strings"
// for French ("strings.fr.resx"), German ("strings.de.resx"), 
// and English ("strings.en.resx")
void ShowMyNameLocalized(string name, string middlename = "", string surname = "")
{
    // get localized string
    var localizedMyNameIs = Properties.strings.Hello;
    // insert spaces where necessary
    name = (string.IsNullOrWhiteSpace(name) ? "" : name + " ");
    middlename = (string.IsNullOrWhiteSpace(middlename) ? "" : middlename + " ");
    surname = (string.IsNullOrWhiteSpace(surname) ? "" : surname + " ");
    // display it
    Console.WriteLine($"{localizedMyNameIs} {name}{middlename}{surname}".Trim());
}

// switch to French and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
ShowMyNameLocalized(FirstName);

// switch to German and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
ShowMyNameLocalized(FirstName);

// switch to US English and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
ShowMyNameLocalized(FirstName);

Si les chaînes de ressources des langages utilisés ci-dessus sont correctement stockées dans les fichiers de ressources individuels, vous devez obtenir la sortie suivante:

Bonjour, mon nom est John
Bonjour, nommez-vous John
Bonjour je m'appelle John

Notez que cela implique que le nom suit la chaîne localisée dans toutes les langues. Si ce n'est pas le cas, vous devez ajouter des espaces réservés aux chaînes de ressources et modifier la fonction ci-dessus ou vous devez interroger les informations de culture dans la fonction et fournir une instruction de casse contenant les différents cas. Pour plus de détails sur les fichiers de ressources, consultez Comment utiliser la localisation en C # .

Il est recommandé d'utiliser un langage de secours par défaut que la plupart des gens comprendront, au cas où une traduction ne serait pas disponible. Je suggère d'utiliser l'anglais comme langue de secours par défaut.

Interpolation récursive

Bien que ce ne soit pas très utile, il est permis d'utiliser une string interpolée récursivement à l'intérieur des accolades d'un autre:

Console.WriteLine($"String has {$"My class is called {nameof(MyClass)}.".Length} chars:");
Console.WriteLine($"My class is called {nameof(MyClass)}.");

Sortie:

La chaîne a 27 caractères:

Ma classe s'appelle MyClass.