Come sbagliare usando ToString() !

             Critical error

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.

 

Print | posted @ giovedì 16 settembre 2004 03:27

Comments on this entry:

Gravatar # re: Come sbagliare usando ToString() !
by Alessandro Scardova at 16/09/2004 10:51

Sono completamente d'accordo...
per i più pigri consiglio la System.Xml.XmlConvert, che è fatta apposta per produrre stringe culture-indipendent.
ciao
AS
Comments have been closed on this topic.