Formattazione composita

La funzionalità di formattazione composta di .NET consente di usare come input un elenco di oggetti e una stringa di formato composto. Una stringa di formato composto è costituita da testo fisso combinato con segnaposti indicizzati, denominati elementi di formato. Questi elementi di formato corrispondono agli oggetti nell'elenco. L'operazione di formattazione produce una stringa risultato costituita dal testo fisso originale alternato alla rappresentazione di stringa degli oggetti dell'elenco.

Importante

Invece di usare le stringhe di formato composto, è possibile usare stringhe interpolate se il linguaggio e la versione del linguaggio in uso le supportano. Una stringa interpolata contiene espressioni interpolate. Ogni espressione interpolata viene risolta con il valore dell'espressione e inclusa nella stringa di risultato al momento dell'assegnazione della stringa. Per altre informazioni, vedere Interpolazione di stringhe (Riferimenti per C#) e Stringhe interpolate (Riferimenti per Visual Basic).

I metodi seguenti supportano la funzionalità di formattazione composita:

Stringa di formato composto

Una stringa di formato composto e un elenco di oggetti vengono usati come argomenti di metodi che supportano la funzionalità di formattazione composta. Una stringa di formato composto è costituita da zero o più esecuzioni di testo fisso alternate a uno o più elementi di formato. Il testo fisso corrisponde a una stringa di propria scelta e ogni elemento di formato corrisponde a un oggetto o una struttura boxed dell'elenco. La rappresentazione di stringa di ogni oggetto sostituisce l'elemento di formato corrispondente.

Si consideri il frammento di codice Format riportato di seguito:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

Il testo fisso è Name = e , hours = . Gli elementi di formato sono {0}, il cui indice 0 corrisponde all'oggetto name, e {1:hh}, il cui indice 1 corrisponde all'oggetto DateTime.Now.

Sintassi degli elementi di formato

Ogni elemento di formato usa il formato seguente ed è costituito dai componenti riportati di seguito:

{index[,alignment][:formatString]}

Le parentesi graffe corrispondenti ({ e }) sono obbligatorie.

Componente di indice

Il componente obbligatorio index, denominato anche identificatore di parametro, corrisponde a un numero a partire da 0 che identifica un elemento corrispondente nell'elenco di oggetti, ovvero l'elemento di formato il cui identificatore di parametro è 0 formatta il primo oggetto nell'elenco. L'elemento di formato il cui identificatore di parametro è 1 formatta il secondo oggetto nell'elenco e così via. L'esempio seguente include quattro identificatori di parametro, numerati da zero a tre, per rappresentare i numeri primi inferiori a 10:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

Più elementi di formato possono fare riferimento allo stesso elemento dell'elenco di oggetti specificando lo stesso identificatore di parametro. È ad esempio possibile formattare lo stesso valore numerico in formato esadecimale, scientifico e numerico specificando una stringa di formato composto "0x{0:X} {0:E} {0:N}", come nell'esempio seguente:

string multiple = string.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);

// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
                                       Int64.MaxValue)
Console.WriteLine(multiple)

'The example displays the following output
'     0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

Ogni elemento di formato può fare riferimento a un oggetto dell'elenco. Se ad esempio sono presenti tre oggetti, è possibile formattare il secondo, il primo e il terzo oggetto specificando una stringa di formato composto come {1} {0} {2}. Gli oggetti a cui non fa riferimento un elemento di formato vengono ignorati. Se un identificatore di parametro corrisponde a un elemento non incluso nei limiti dell'elenco di oggetti, verrà generata un'eccezione FormatException in fase di esecuzione.

Componente di allineamento

Il componente facoltativo alignment corrisponde a un intero con segno che indica la larghezza preferita del campo formattato. Se il valore di alignment è inferiore alla lunghezza della stringa formattata, il componente alignment verrà ignorato e come larghezza del campo verrà usata la lunghezza della stringa. I dati formattati verranno allineati a destra se il valore di alignment è positivo e a sinistra se il valore di alignment è negativo. Per la spaziatura eventualmente necessaria verranno usati spazi vuoti. Se viene specificato il componente alignment, la virgola è obbligatoria.

L'esempio seguente definisce due matrici, una contenente i nomi dei dipendenti e l'altra contenente il numero di ore in cui hanno lavorato per due settimane. La stringa di formato composto allinea a sinistra i nomi in un campo di 20 caratteri e allinea a destra le ore in un campo di 5 caratteri. La stringa di formato standard "N1" formatta le ore con una cifra frazionaria.

string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
                   "Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82,
                    40.333m, 80, 16.75m };

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");

for (int counter = 0; counter < names.Length; counter++)
    Console.WriteLine("{0,-20} {1,5:N1}", names[counter], hours[counter]);

// The example displays the following output:
//      Name                 Hours
//      
//      Adam                  40.0
//      Bridgette              6.7
//      Carla                 40.4
//      Daniel                82.0
//      Ebenezer              40.3
//      Francine              80.0
//      George                16.8
Dim names As String() = {"Adam", "Bridgette", "Carla", "Daniel",
                         "Ebenezer", "Francine", "George"}

Dim hours As Decimal() = {40, 6.667D, 40.39D, 82,
                          40.333D, 80, 16.75D}

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours")

For counter = 0 To names.Length - 1
    Console.WriteLine("{0,-20} {1,5:N1}", names(counter), hours(counter))
Next

'The example displays the following output
'     Name                 Hours
'     
'     Adam                  40.0
'     Bridgette              6.7
'     Carla                 40.4
'     Daniel                82.0
'     Ebenezer              40.3
'     Francine              80.0
'     George                16.8

Componente della stringa di formato

Il componente formatString facoltativo è una stringa di formato appropriata per il tipo di oggetto formattato. e nello specifico:

  • Stringa di formato numerico standard o personalizzata se l'oggetto corrispondente è un valore numerico.
  • Stringa di formato di data e ora standard o personalizzata se l'oggetto corrispondente è un oggetto DateTime.
  • Stringa di formato di enumerazione se l'oggetto corrispondente è un valore di enumerazione.

Se il componente formatString viene omesso, verrà usato l'identificatore di formato generale "G" per un tipo numerico, di data e ora o di enumerazione. Se viene specificato il componente formatString, i due punti sono obbligatori.

Nella tabella seguente sono elencati i tipi o le categorie di tipi della libreria di classi .NET che supportano un set predefinito di stringhe di formato e vengono forniti collegamenti ad articoli in cui vengono elencate le stringhe di formato supportate. La formattazione delle stringhe è un meccanismo estendibile che consente di definire nuove stringhe di formato per tutti i tipi esistenti e definire un set di stringhe di formato supportate da un tipo definito dall'applicazione.

Per altre informazioni, vedere gli articoli sull'interfaccia IFormattable e ICustomFormatter.

Tipo o categoria di tipo Vedere
Tipi di data e ora (DateTime, DateTimeOffset) Stringhe formato data e ora standard

Stringhe formato data e ora personalizzate
Tipi di enumerazione (tutti derivati da System.Enum) Enumeration Format Strings
Tipi numerici (BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64) Stringhe di formato numerico standard

Stringhe di formato numerico personalizzato
Guid Guid.ToString(String)
TimeSpan Stringhe di formato TimeSpan standard

Stringhe di formato TimeSpan personalizzate

Sequenze di escape delle parentesi graffe

Le parentesi graffe di apertura e di chiusura sono interpretate come l'inizio e la fine di un elemento di formato. Per visualizzare una parentesi graffa di apertura o di chiusura letterale, è necessario usare una sequenza di escape. Specificare due parentesi graffe di apertura ({{) nel testo fisso per visualizzare una parentesi di apertura ({) oppure due parentesi graffe di chiusura (}}) per visualizzare una parentesi graffa di chiusura (}).

Le parentesi graffe con carattere di escape con un elemento di formato vengono analizzate in modo diverso tra .NET e .NET Framework.

.NET

Le parentesi graffe possono essere precedute da un carattere di escape intorno a un elemento di formato. Si consideri, ad esempio, l'elemento di formato {{{0:D}}}, destinato alla visualizzazione di una parentesi graffa di apertura, un valore numerico formattato come numero decimale e una parentesi graffa di chiusura. L'elemento di formato viene interpretato nel modo seguente:

  1. Le prime due parentesi apertura ({{) presentano una sequenza di escape e producono una parentesi graffa di apertura.
  2. I tre caratteri successivi ({0:) sono interpretati come l'inizio di un elemento di formato.
  3. Il carattere successivo (D) viene interpretato come identificatore di formato numerico standard Decimal.
  4. La parentesi graffa successiva (}) viene interpretata come la fine dell'elemento di formato.
  5. Le due parentesi graffe finali vengono precedute da un carattere di escape e producono una parentesi graffa di chiusura.
  6. Il risultato finale visualizzato è la stringa letterale {6324}.
int value = 6324;
string output = string.Format("{{{0:D}}}", value);

Console.WriteLine(output);
// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}", value)

Console.WriteLine(output)

'The example displays the following output
'      {6324}

.NET Framework

Le parentesi graffe in un elemento di formato vengono interpretate sequenzialmente nell'ordine in cui sono rilevate. L'interpretazione delle parentesi graffe annidate non è supportata.

Il tipo di interpretazione delle parentesi graffe in sequenza di escape può produrre risultati imprevisti. Si consideri, ad esempio, l'elemento di formato {{{0:D}}}, destinato alla visualizzazione di una parentesi graffa di apertura, un valore numerico formattato come numero decimale e una parentesi graffa di chiusura. L'elemento di formato viene tuttavia interpretato nel modo seguente:

  1. Le prime due parentesi apertura ({{) presentano una sequenza di escape e producono una parentesi graffa di apertura.
  2. I tre caratteri successivi ({0:) sono interpretati come l'inizio di un elemento di formato.
  3. Il carattere successivo (D) verrebbe interpretato come identificatore del formato numerico standard Decimal, ma le due parentesi graffe successive con sequenza di escape (}}) producono una parentesi graffa singola. Poiché la stringa risultante (D}) non è un identificatore di un formato numerico standard, viene interpretata come una stringa di formato personalizzata che indica la visualizzazione della stringa letterale D}.
  4. L'ultima parentesi graffa (}) viene interpretata come la fine dell'elemento di formato.
  5. Il risultato finale visualizzato è la stringa letterale {D}. Il valore numerico da formattare non viene visualizzato.
int value = 6324;
string output = string.Format("{{{0:D}}}",
                              value);
Console.WriteLine(output);

// The example displays the following output:
//       {D}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}",
                                     value)
Console.WriteLine(output)

'The example displays the following output:
'      {D}

Per evitare di interpretare in modo errato gli elementi di formato e le parentesi graffe con sequenza di escape, è preferibile formattarli separatamente, ovvero nella prima operazione di formato visualizzare una parentesi graffa di apertura letterale. Nell'operazione successiva visualizzare il risultato dell'elemento di formato e nell'operazione finale visualizzare una parentesi graffa di chiusura letterale. Questo approccio viene illustrato nell'esempio seguente:

int value = 6324;
string output = string.Format("{0}{1:D}{2}",
                             "{", value, "}");
Console.WriteLine(output);

// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}",
                                     "{", value, "}")
Console.WriteLine(output)

'The example displays the following output:
'      {6324}

Ordine di elaborazione

Se la chiamata al metodo di formattazione composita include un argomento IFormatProvider il cui valore non è null, il runtime chiama il metodo IFormatProvider.GetFormat per richiedere un'implementazione di ICustomFormatter. Se il metodo può restituire un'implementazione di ICustomFormatter, viene memorizzata nella cache durante la chiamata del metodo di formattazione composita.

Ogni valore nell'elenco di parametri che corrisponde a un elemento di formato viene convertito in una stringa, nel modo seguente:

  1. Se il valore da formattare è null, viene restituita una stringa vuota String.Empty.

  2. Se l'implementazione di ICustomFormatter è disponibile, il runtime chiama il metodo Format. Il runtime passa il valore formatString dell'elemento di formato (o null se non è presente) al metodo. Il runtime passa anche l'implementazione di IFormatProvider al metodo. Se la chiamata al metodo ICustomFormatter.Format restituisce null, l'esecuzione procede con il passaggio successivo. In caso contrario, viene restituito il risultato della chiamata ICustomFormatter.Format.

  3. Se il valore implementa l'interfaccia IFormattable, verrà chiamato il relativo metodo ToString(String, IFormatProvider). Se è presente nell'elemento di formato, il valore formatString viene passato al metodo. In caso contrario, viene passato null. L'argomento IFormatProvider è determinato come segue:

  4. Viene chiamato il metodo senza parametri ToString del tipo, che esegue l'override di Object.ToString() o eredita il comportamento della relativa classe di base. In questo caso la stringa di formato specificata dal componente formatString nell'elemento di formato, se presente, viene ignorata.

L'allineamento viene applicato al termine dei precedenti passaggi.

Esempi di codice

Nell'esempio seguente vengono illustrate una stringa creata con la formattazione composita e un'altra creata mediante il metodo ToString di un oggetto. Entrambi i tipi di formattazione producono risultati equivalenti.

string formatString1 = string.Format("{0:dddd MMMM}", DateTime.Now);
string formatString2 = DateTime.Now.ToString("dddd MMMM");
Dim formatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim formatString2 As String = DateTime.Now.ToString("dddd MMMM")

Presupponendo che il giorno corrente sia un giovedì di maggio, il valore di entrambe le stringhe dell'esempio precedente sarà Thursday May se sono specificate le impostazioni cultura inglesi.

Console.WriteLine espone la stessa funzionalità di String.Format. L'unica differenza tra i due metodi è che String.Format restituisce il risultato come stringa, mentre Console.WriteLine scrive il risultato nel flusso di output associato all'oggetto Console. Nell'esempio seguente viene usato il metodo Console.WriteLine per formattare il valore di myNumber come valore di valuta:

int myNumber = 100;
Console.WriteLine("{0:C}", myNumber);

// The example displays the following output
// if en-US is the current culture:
//        $100.00
Dim myNumber As Integer = 100
Console.WriteLine("{0:C}", myNumber)

'The example displays the following output
'if en-US Is the current culture:
'       $100.00

Nell'esempio riportato di seguito vengono illustrate la formattazione di più oggetti e la formattazione di un oggetto in due modi diversi:

string myName = "Fred";
Console.WriteLine(string.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now));

// Depending on the current time, the example displays output like the following:
//        Name = Fred, hours = 11, minutes = 30
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now))
'Depending on the current time, the example displays output Like the following:
'       Name = Fred, hours = 11, minutes = 30

Nell'esempio seguente viene illustrato l'utilizzo dell'allineamento nella formattazione. Gli argomenti formattati sono inseriti tra barre verticali (|) per evidenziare l'allineamento ottenuto.

string firstName = "Fred";
string lastName = "Opals";
int myNumber = 100;

string formatFirstName = string.Format("First Name = |{0,10}|", firstName);
string formatLastName = string.Format("Last Name =  |{0,10}|", lastName);
string formatPrice = string.Format("Price =      |{0,10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
Console.WriteLine();

formatFirstName = string.Format("First Name = |{0,-10}|", firstName);
formatLastName = string.Format("Last Name =  |{0,-10}|", lastName);
formatPrice = string.Format("Price =      |{0,-10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);

// The example displays the following output on a system whose current
// culture is en-US:
//     First Name = |      Fred|
//     Last Name =  |     Opals|
//     Price =      |   $100.00|
//
//     First Name = |Fred      |
//     Last Name =  |Opals     |
//     Price =      |$100.00   |
Dim firstName As String = "Fred"
Dim lastName As String = "Opals"
Dim myNumber As Integer = 100

Dim formatFirstName As String = String.Format("First Name = |{0,10}|", firstName)
Dim formatLastName As String = String.Format("Last Name =  |{0,10}|", lastName)
Dim formatPrice As String = String.Format("Price =      |{0,10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
Console.WriteLine()

formatFirstName = String.Format("First Name = |{0,-10}|", firstName)
formatLastName = String.Format("Last Name =  |{0,-10}|", lastName)
formatPrice = String.Format("Price =      |{0,-10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)

'The example displays the following output on a system whose current
'culture Is en-US:
'    First Name = |      Fred|
'    Last Name =  |     Opals|
'    Price =      |   $100.00|
'
'    First Name = |Fred      |
'    Last Name =  |Opals     |
'    Price =      |$100.00   |

Vedi anche