2011-09-22 9 views
27

Al convertir, por ejemplo, un decimal en un string, utiliza el CultureInfo.InvariantCulture y lo pasa como IFormatProvider. ¿Pero por qué esta sobrecarga no está en object?¿Por qué el objeto no tiene una sobrecarga que acepta IFormatProvider?

Una aplicación agradable sería:

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

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

Esto causaría ningún daño o beneficio para la clase object, pero los objetos que se derivan de ella en lugar puede anular la sobrecarga y será mucho más fácil llamarlo cuando no está seguro del tipo.

El problema que me hizo tropezar con esto fue cuando estaba haciendo un método que sería obtener todas las propiedades de una clase y escribirla en xml. Como no quería verificar el tipo de objeto, acabo de llamar al ToString. Pero si esto hubiera sido un decimal, la salida se basaría en el CurrentCulture del subproceso, que no es óptimo. La única solución que puedo ver es cambiar el CurrentCulture al InvariantCulture y luego volver a cambiarlo a lo que era antes. Pero eso sería feo como yo tendría que escribir probar finalmente se hace etc.

Mi código actual es:

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

pero yo quiero que sea:

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

Cualquier beneficio de no tener esta sobrecarga en object?

Respuesta

28

intenta convertir su 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' realidad tiene más sentido – dlev

+5

@ dlev: No estoy de acuerdo: el OP específicamente quiere * solo * formatear. Dado que los tipos pueden implementar fácilmente IFormattable pero no IConvertible, y que el único método en IFormattable es exactamente el que OP desea llamar, creo que IFormattable tiene más sentido. –

+0

@Jon Basado en la pregunta de OP, parece que tiene experiencia con el uso de la versión 'IConvertible' de' ToString() ', que es la razón por la que lo mencioné. Sin embargo, tu punto está bien tomado. – dlev

14

método de extensión práctica de la solución de Pedro (modificado para probar también para 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

Pruebe uno de estos:

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

XmlConvert.ToString() se hace para XML, por lo que mantener las cosas más cerca de la especificación XML, tales como el uso de "verdad" en lugar de "True ". Sin embargo, también es más frágil que Convert.ToString(). Por ejemplo, esto va a lanzar una excepción debido a la hora UTC:

XmlConvert.ToString(DateTime.UtcNow) 

pero esto funciona: (. A menos que pretenda dar formato al número)

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

Convert.ToString realmente arroja a IConvertible e IFormattable (ver publicaciones anteriores): cadena estática pública ToString (valor del objeto, proveedor IFormatProvider) { IConvertible ic = valor como IConvertible; if (ic!= nulo) return ic.ToString (proveedor); IFormattable formattable = value como IFormattable; if (formattable! = Null) return formattable.ToString (null, provider); valor de retorno == nulo? String.Empty: value.ToString(); } –

Cuestiones relacionadas