Il metodo ToString() ha il solo scopo di produrre una stringa destinata ad essere letta dall’utente finale e perciò la stringa prodotta varia a seconda della lingua dell’utente corrente e delle sue impostazioni internazionali.
Quando ToString() invece viene usato per produrre una stringa destinata ad uso del programma stesso come ad esempio nei seguenti casi
- stringhe XML
- stringhe di comandi SQL
- stringhe che rappresentano Url
- stringhe che rappresentano path
- stringhe che rappresentano il contenuto di file di configurazione
- stringhe che rappresentano nomi di metodi da usare con la Reflection
- ...
siamo di fronte ad un Errore di programmazione, vediamolo in azione con un esempio.
Questo codice dichiara 2 variabili di tipo date:
DateTime a = new DateTime(2004, 9, 8, 12, 30, 55, 500);
DateTime b = new DateTime(2004, 9, 8, 12, 30, 55, 111);
Queste date sono uguali?
Allora quale sarà il risultato del seguente confronto?
if (a.ToString() == b.ToString())
Console.WriteLine("uguali...");
else
Console.WriteLine("Diverse!");
Morale, il modo giusto di fare il confronto è quello di utilizzare i tipi nativi (magari facendo gli opportuni cast se le variabili che ho sono ad esempio di tipo object come accade quando si prelevano da una DataRow) quindi:
if (a == b)
Console.WriteLine("uguali...");
else
Console.WriteLine("Diverse!");
Se per qualche ragione c'è il bisogno reale di utilizzare ToString() per ottenere stringhe destinata ad uso del programma stesso, allora è necessario specificare la cultura invariante ed il formato desiderato facendo attenzione che non ci sia perdita di informazioni (così come venivano persi i millisecondi nel ToString del primo confronto):
Console.WriteLine(a.ToString(@"dd-MM-yyyy HH\:mm.ss.fffffff",
System.Globalization.CultureInfo.InvariantCulture));
Generalizzando a tutto string
Quanto detto per ToString() vale per tutti i metodi di string che sono sensibili alla cultura corrente che come ToString() variano il loro comportamento a seconda della lingua dell’utente corrente e delle sue impostazioni internazionali. Per comportamento intendo
- l'ordinamento
- l'equivalenza tra stringhe
- la formattazione di numeri e date
- ...
Questo accade sia nelle applicazioni Windows che ASP.NET.
In conclusione i metodi di string che tengono conto della cultura corrente sono:
- ToString (usa la CultureInfo corrente del thread oppure accetta una CultureInfo come parametro)
- CompareTo (usa la CultureInfo corrente del thread)
- StartWith (idem)
- EndWith (idem)
- Compare (accetta una CultureInfo come parametro)
I metodi di string che invece indipendenti dalla cultura corrente sono:
- Operator ==
- Operator !=
- Equals
- CompareOrdinal
Nota che Operator == chiama Equals che chiama CompareOrdinal quindi usa la Cultuta Invariante.
Generalizzando a tutta la BCL
Questa stessa divisione tra i metodi sensibili alla cultura corrente e quelli insensibili si riperquote su tutta la BCL nei metodi destinati a produrre (es. Format) o elaborare stringhe (es. Parse).
Nei casi in cui si usano i metodi sensibili alla cultura corrente per produrre stringhe (come Format) sono tipicamente disponibili più overload:
-
uno che utilizza le formattazione predefinita della cultura corrente (eventualmente personalizzate dall'utente dalle impostazioni internazionali)
-
uno che permette di indicare un formato predefinito (quello indicato con singoli caratteri quali ad esempio "G", "N", "X", "R") oppure una stringa completa di formattazione
-
uno che permette di indicare anche un formato corrispondente ad una cultura diversa da quella corrente attraverso l'interfaccia System.IFormatProvider (con System.Globalization.DateTimeFormatInfo per le date e System.Globalization.NumberFormatInfo per i numeri)
Nei casi in cui si usano i metodi sensibili alla cultura corrente per elaborare stringhe (come Parse) sono tipicamente disponibili più overload:
- uno che utilizza le formattazione predefinita della cultura corrente (eventualmente personalizzate dall'utente dalle impostazioni internazionali)
- uno che permette di indicare anche un formato corrispondente ad una cultura diversa da quella corrente attraverso l'interfaccia System.IFormatProvider (con System.Globalization.DateTimeFormatInfo per le date e System.Globalization.NumberFormatInfo per i numeri)
- uno che permette di specificare i formati accettati in ingresso (combinando i flag definiti dall'enum System.Globalization.DateTimeStyles per le date e da System.Globalization.NumberStyles per i numeri)
In Conclusione
Usare ToString() o i metodi di string o della BCL sensibili alla cultura corrente per produrre od elaborare stringhe destinate non ad essere visualizzater all'utente finale ma destinate ad uso del programma, è un errore di programmazione.
Quando è necessario usare questi metodi sensibili alla cultura corrente per produrre od elaborare stringhe destinate ad uso del programma è indispensabile specificare la cultura invariante ed il formato completo in modo che non ci sia pèerdita di informazione.