2011-09-22 15 views
27

Quando si converte ad esempio un decimal in un string, si utilizza CultureInfo.InvariantCulture e lo si passa come IFormatProvider. Ma perché questo sovraccarico non è in object?Perché l'oggetto non ha un sovraccarico che accetta IFormatProvider?

Un bel implementazione potrebbe essere:

public virtual string ToString() 
{ 
    // yadayada, usual ToString 
} 

public virtual string ToString(IFormatProvider provider) 
{ 
    return ToString(); 
} 

Ciò causerebbe alcun danno o beneficio alla classe object, ma gli oggetti che ne derivano possono invece ignorare il sovraccarico e sarà molto più facile da chiamare quando non sei sicuro del tipo.

Il problema che mi ha fatto imbattersi in questo era quando stavo facendo un metodo che avrebbe ottenuto tutte le proprietà di una classe e scriverlo in xml. Poiché non volevo controllare il tipo di oggetto, ho appena chiamato ToString. Ma questo sarebbe stato un decimale, l'output sarebbe basato sul CurrentCulture del thread, che non è ottimale. L'unica soluzione che riesco a vedere è la modifica di CurrentCulture in InvariantCulture e la successiva modifica a qualsiasi precedente. Ma questo sarebbe solo brutto come avrei dovuto scrivere provare finalmente blocchi ecc

Il mio codice attuale è:

 foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance). 
      Where(c => ValidTypes.Contains(c.PropertyType))) 
     { 
      var value = property.GetValue(order, null); 
      if (value != null) 
      { 
       writer.WriteElementString(property.Name, 
       value.ToString()); 
      } 
     } 

ma vorrei che fosse:

 foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance). 
      Where(c => ValidTypes.Contains(c.PropertyType))) 
     { 
      var value = property.GetValue(order, null); 
      if (value != null) 
      { 
       writer.WriteElementString(property.Name, 
       value.ToString(CultureInfo.InvariantCulture)); 
      } 
     } 

Ogni prestazione di non avere questo sovraccarico su object?

risposta

28

Prova a lanciare la vostra value a IFormattable:

foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance). 
     Where(c => ValidTypes.Contains(c.PropertyType))) 
{ 
    var value = property.GetValue(order, null); 
    if (value != null) 
    { 
     var formattable = value as IFormattable; 
     writer.WriteElementString(property.Name, 
     formattable == null ? value.ToString() : formattable.ToString(null, CultureInfo.InvariantCulture)); 
    } 
} 
+3

'IConvertible' rende effettivamente più senso – dlev

+5

@ dlev: Non sono d'accordo - l'OP vuole specificamente * solo * formattare. Dato che i tipi possono facilmente implementare IFormattable ma non IConvertible, e che il singolo metodo in IFormattable è esattamente quello che l'OP vuole chiamare, penso che IFormattable abbia più senso. –

+0

@Jon Sulla base della domanda dell'OP, sembra che abbia esperienza con l'uso della versione 'IConvertible' di' ToString() ', motivo per cui l'ho menzionata. Il tuo punto è ben preso, però. – dlev

14

metodo di estensione Handy della soluzione di Peter (modificato per testare anche per IConvertible).

public static string ToInvariantString(this object obj) 
{ 
    return obj is IConvertible ? ((IConvertible)obj).ToString(CultureInfo.InvariantCulture) 
     : obj is IFormattable ? ((IFormattable)obj).ToString(null, CultureInfo.InvariantCulture) 
     : obj.ToString(); 
} 
8

Prova uno di questi:

string valueString = XmlConvert.ToString(value); 
string valueString = Convert.ToString(value, CultureInfo.InvariantCulture); 

XmlConvert.ToString() è fatto per XML, in modo che mantenere le cose più da vicino alle specifiche XML, come l'utilizzo di "vero" al posto di "True ". Tuttavia, è anche più fragile di Convert.ToString(). Ad esempio, questo sarà un'eccezione a causa del tempo UTC:

XmlConvert.ToString(DateTime.UtcNow) 

ma questo funziona: (. A meno che non si ha intenzione di formattare il numero)

XmlConvert.ToString(DateTime.UtcNow, "o") 
+2

Convert.ToString esegue in realtà IConvertible e IFormattable (vedere i post precedenti): stringa statica pubblica ToString (valore dell'oggetto, provider IFormatProvider) { IConvertible ic = value as IConvertible; se (ic!= null) return ic.ToString (provider); Formattabile IFormattabile = valore come IFormattable; if (formattabile! = Null) return formattable.ToString (null, provider); valore restituito == null? String.Empty: value.ToString(); } –

Problemi correlati