2009-01-26 14 views
5

Estoy buscando algo equivalente al código a continuación, pero para cualquier tipo de valor sin tener que codificar una declaración de interruptor para cada tipo de datos. El código siguiente no se compila porque XmlConvert.ToString() no tiene una sobrecarga que acepte y objeta.¿Cómo puedo convertir un tipo de valor emitido como un objeto a una cadena usando XmlConvert?

 int intValue = 10; 
     object boxedValue = (object)intValue; 
     string xmlValue = XmlConvert.ToString(boxedValue); 

En otras palabras, hay una manera mejor que esto:

public static string ToXmlString(Type type, object value) { 

     switch(Type.GetTypeCode(type)) { 
      case TypeCode.Int32: 
       return XmlConvert.ToString((int) value); 
      case TypeCode.DateTime: 
       return XmlConvert.ToString((DateTime) value, XmlDateTimeSerializationMode.Unspecified); 
      case TypeCode.Boolean: 
       return XmlConvert.ToString((bool) value); 

      // TODO: Add case for all other value types! 

      default: 
       return value.ToString(); 
     } 
    } 

Respuesta

0

Sólo para tirar esto por ahí, se le intenta convertir un objeto de negocio en XML?

Quizás le interese consultar XmlSerialization. Si marca algunos atributos en su objeto de negocio .Net hará todo el material de XML de lujo para usted :).

Además, ¿hay alguna razón por la que esté encajonando su valor? XmlConvert.ToString() tiene 19 sobrecargas, muchas de las cuales toman primitivas.

+0

Aprecio la información, pero he pasado por XmlSerializer, DataContractSerializer hell. Incluso he jugado con XamlWriter. Mis valores están encasillados porque los estoy accediendo a través de una interfaz que trata con muchos tipos de datos. –

2

Todos los tipos de valores son inherentemente serializables. Entonces solo necesitas usar un XMLSerializer. Algo como esto lo haría (basado en el método):

public static string ToXmlString(Type type, object value) 
{ 
    StringBuilder sb = new StringBuilder(); 
    System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sb); 
    System.Xml.Serialization.XmlSerializer serial = 
     new System.Xml.Serialization.XmlSerializer(type); 
    serial.Serialize(writer, value); 
} 
+0

Lo curioso es que si usas Reflector para rastrear en XmlSerializer.Serialize eventualmente pulsas un método llamado SerializePrimitive que tiene una gran declaración de cambio que se distribuye a métodos que finalmente llaman a XmlConvert.ToString donde asignan el objeto al tipo nativo. –

+0

¿Pero es esto algo malo? Todo lo que sucede es que el interruptor se mueve de su código a código de marco. – DarkwingDuck

+1

El resultado de ToXmlString (typeof (boolean), true) es true que no es el verdadero "exprected". El resultado debe ser mapeado de nuevo para que funcione. Prefiero la forma "dura" propuesta por Darrel. – Lakedaimon

1

Otra opción es utilizar el reflector para mirar a continuación, hacer una copia de System.Xml.Linq.XContainer.GetStringValue (que es interno por desgracia)

1

Tuve que hacer la conversión inversa opuesta (de cadena a tipo) como parte de un serializador que quería escribir (evitando el construido en uno, por Razones). Estaba haciendo la deserialización y esta fue la única publicación para hablar al respecto, así que estoy actualizando con mi respuesta cuando todavía está fresca.

El método que utilicé fue utilizar la reflexión para básicamente resolver lo que tenía que hacer. El tipo de variable en el siguiente ejemplo es el objeto Type del tipo al que estoy convirtiendo, E es un XmlNode cuyo contenido voy a convertir y newVar es una instancia de una plantilla tipo T que devolveré. Este fragmento no asume ninguna fuerza sobre T (que es por qué no hay cadena de asignación/cast directa) y asume objetos/enumeraciones se manejan de forma diferente (objetos y enumeraciones romper este):

MethodInfo convertMethod; 

if(Type.GetTypeCode(type) != TypeCode.String) 
    convertMethod = typeof(XmlConvert).GetMethod ("To" + type.Name); 
else 
    convertMethod = E.InnerText.GetType().GetMethod("Clone"); 

if(convertMethod == null) 
{ 
    //Error 
} 
else 
{ 
    if(Type.GetTypeCode (type)!= TypeCode.String) 
     newVar = (T)convertMethod.Invoke(null, new object[] { E.InnerText }); 
    else 
     newVar = (T)convertMethod.Invoke (E.InnerText, new object[]{}); 
} 

(Cadena precisa ser tratada como un caso especial como ToString() hace algo completamente diferente y lo rompe todo).

El revés (como en el post original) sería algo así (no probado, se actualizará si escribo la función serialize):

MethodInfo convertMethod; 

if(Type.GetTypeCode(type) != TypeCode.String) 
    convertMethod = typeof(XmlConvert).GetMethod ("ToString", new Type[] {typeof(T)}); 
else 
    convertMethod = typeof(string).GetMethod("Clone"); 

if(convertMethod == null) 
{ 
    //Error 
} 
else 
{ 
    string str; 
    if(Type.GetTypeCode (type)!= TypeCode.String) 
     str = (string)convertMethod.Invoke(null, new object[] { Value }); 
    else 
     str = (string)convertMethod.Invoke (Value, new object[]{}); 
} 

En este caso, la conversión es de T a cuerda y Value contiene un tipo T del que estamos convirtiendo. La diferencia es que pedimos ToString pero especificamos la función con un parámetro de tipo T. Esto debería ser lo suficientemente único.

Cuestiones relacionadas