C# Language Interpolazione a stringa

Esempio

L'interpolazione delle stringhe consente allo sviluppatore di combinare variables e testo per formare una stringa.


Esempio di base

Vengono create due variabili int : foo e bar .

int foo = 34;
int bar = 42;

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

Console.WriteLine(resultString);

Uscita :

Il foo è 34 e la barra 42.

Visualizza la demo

Le bretelle all'interno delle stringhe possono ancora essere utilizzate, come questa:

var foo = 34;
var bar = 42;

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

Questo produce il seguente risultato:

Il foo è {pippo} e la barra è {bar}.


Utilizzo dell'interpolazione con letterali stringa letterali

Usando @ prima della stringa, la stringa verrà interpretata letteralmente. Quindi, ad esempio, i caratteri Unicode o le interruzioni di riga rimarranno esattamente come sono stati digitati. Tuttavia, questo non influirà sulle espressioni in una stringa interpolata come mostrato nell'esempio seguente:

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

Nel caso non fosse chiaro:
\ u00B9
Il pippo
è 34,
e il bar
è 42.

Visualizza la demo


espressioni

Con l'interpolazione delle stringhe, è possibile valutare anche le espressioni all'interno di parentesi graffe {} . Il risultato verrà inserito nella posizione corrispondente all'interno della stringa. Ad esempio, per calcolare il massimo di foo e bar e inserirlo, utilizzare Math.Max tra parentesi graffe:

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

Produzione:

E il più grande è: 42

Nota: tutti gli spazi bianchi iniziali o finali (inclusi spazio, scheda e CRLF / nuova riga) tra la parentesi graffa e l'espressione vengono completamente ignorati e non inclusi nell'output

Visualizza la demo

Come altro esempio, le variabili possono essere formattate come valuta:

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

Produzione:

Foo formattato come valuta a 4 cifre decimali: $ 34,0000

Visualizza la demo

Oppure possono essere formattati come date:

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

Produzione:

Oggi è: lunedì 20 luglio 2015

Visualizza la demo

Le dichiarazioni con un operatore condizionale (Ternario) possono anche essere valutate all'interno dell'interpolazione. Tuttavia, questi devono essere racchiusi tra parentesi, in quanto i due punti vengono utilizzati per indicare la formattazione come mostrato sopra:

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

Produzione:

Bar è più grande di foo!

Visualizza la demo

Le espressioni condizionali e gli identificatori di formato possono essere mescolati:

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

Produzione:

Ambiente: processo a 32 bit


Sequenze di fuga

L'escape dei caratteri barra rovesciata ( \ ) e virgola ( " ) funziona esattamente nello stesso modo nelle stringhe interpolate come nelle stringhe non interpolate, sia per i letterali stringa letterale che per quelli non verbali:

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

Produzione:

Foo è 34. In una stringa non-letterale, dobbiamo uscire da "e \ con barre retroverse.
Foo è 34. In una stringa letterale, dobbiamo scappare "con una citazione extra, ma non abbiamo bisogno di scappare \

Per includere una parentesi graffa { o } in una stringa interpolata, utilizzare due parentesi graffe {{ o }} :

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

Produzione:

{foo} è: 34

Visualizza la demo


FormattableString type

Il tipo di $"..." espressione di interpolazione della stringa non è sempre una stringa semplice. Il compilatore decide quale tipo assegnare a seconda del contesto:

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

Questo è anche l'ordine delle preferenze di tipo quando il compilatore deve scegliere quale metodo di overload verrà chiamato.

Un nuovo tipo , System.FormattableString , rappresenta una stringa di formato composita, insieme agli argomenti da formattare. Usalo per scrivere applicazioni che gestiscono in modo specifico gli argomenti di interpolazione:

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();

    // ...
}

Chiama il metodo sopra con:

AddLogItem($"The foo is {foo}, and the bar is {bar}.");
Ad esempio, si potrebbe scegliere di non sostenere il costo delle prestazioni della formattazione della stringa se il livello di registrazione stava già filtrando l'elemento del registro.

Conversioni implicite

Esistono conversioni di tipo implicite da una stringa interpolata:

var s = $"Foo: {foo}";
System.IFormattable s = $"Foo: {foo}";
Puoi anche produrre una variabile IFormattable che ti permette di convertire la stringa con un contesto invariante:
var s = $"Bar: {bar}";
System.FormattableString s = $"Bar: {bar}";

Metodi di coltura attuali e invariabili

Se l'analisi del codice è attivata, tutte le stringhe interpolate generano l'avviso CA1305 (Specifica IFormatProvider ). Un metodo statico può essere utilizzato per applicare la cultura corrente.

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

Quindi, per produrre una stringa corretta per la cultura corrente, basta usare l'espressione:

Culture.Current($"interpolated {typeof(string).Name} string.")
Culture.Invariant($"interpolated {typeof(string).Name} string.")
Nota : Current e Invariant non possono essere creati come metodi di estensione perché, per impostazione predefinita, il compilatore assegna il tipo String all'espressione di stringa interpolata che non riesce a compilare il seguente codice:

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

FormattableString classe FormattableString contiene già il metodo Invariant() , quindi il modo più semplice per passare alla cultura invariante è affidarsi using static :

using static System.FormattableString;

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


Dietro le quinte

Le stringhe interpolate sono solo uno zucchero sintattico per String.Format() . Il compilatore ( Roslyn ) lo trasformerà in un String.Format dietro le quinte:

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

Quanto sopra sarà convertito in qualcosa di simile a questo:

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

Interpolazione a stringa e Linq

È possibile utilizzare stringhe interpolate nelle istruzioni Linq per aumentare ulteriormente la leggibilità.

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

Può essere riscritto come:

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

Stringhe interpolate riutilizzabili

Con string.Format , puoi creare stringhe di formato riutilizzabili:

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

// ...

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

Le stringhe interpolate, tuttavia, non verranno compilate con i segnaposto che fanno riferimento a variabili inesistenti. Quanto segue non verrà compilato:

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

Invece, crea un Func<> che consuma variabili e restituisce una String :

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

// ...

Logger.Log(FormatError(ex));

Interpolazione e localizzazione delle stringhe

Se stai localizzando la tua applicazione, potresti chiederti se è possibile utilizzare l'interpolazione delle stringhe insieme alla localizzazione. In effetti, sarebbe bello avere la possibilità di memorizzare nel file di risorse String s come:

"My name is {name} {middlename} {surname}"
invece del molto meno leggibile:

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

String processo di interpolazione delle String verifica in fase di compilazione , diversamente dalla stringa di formattazione con string.Format che si verifica in fase di runtime . Le espressioni in una stringa interpolata devono fare riferimento a nomi nel contesto corrente e devono essere archiviate in file di risorse. Ciò significa che se vuoi usare la localizzazione devi farlo come:

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

Se le stringhe di risorse per le lingue utilizzate in precedenza sono archiviate correttamente nei singoli file di risorse, è necessario ottenere il seguente output:

Bonjour, mon nom est John
Ciao, mein Nome ist John
Ciao il mio nome è John

Nota che ciò implica che il nome segue la stringa localizzata in ogni lingua. In caso contrario, è necessario aggiungere segnaposti alle stringhe di risorse e modificare la funzione in alto oppure è necessario interrogare le informazioni sulla cultura nella funzione e fornire un'istruzione switch case contenente i diversi casi. Per ulteriori dettagli sui file di risorse, vedi Come utilizzare la localizzazione in C # .

È buona norma utilizzare una lingua di fallback predefinita che la maggior parte delle persone capirà, nel caso in cui una traduzione non sia disponibile. Suggerisco di usare l'inglese come lingua di fallback predefinita.

Interpolazione ricorsiva

Sebbene non sia molto utile, è consentito utilizzare una string interpolata ricorsivamente all'interno delle parentesi graffe di un'altra:

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

Produzione:

La stringa ha 27 caratteri:

La mia classe si chiama MyClass.