2009-04-09 15 views
43

Realmente debería ser capaz de conseguir esto, pero estoy en el punto en el que creo que sería más fácil preguntarlo.Conversión de String a <T>

En la función de C#:

public static T GetValue<T>(String value) where T:new() 
{ 
    //Magic happens here 
} 

Qué es una buena aplicación de la magia? La idea detrás de esto es que tengo xml para analizar y los valores deseados son a menudo primitivos (bool, int, string, etc.) y este es el lugar perfecto para usar genéricos ... pero una solución simple me está eludiendo en este momento .

por cierto, aquí está una muestra del xml que había necesidad de analizar

<Items> 
    <item> 
     <ItemType>PIANO</ItemType> 
     <Name>A Yamaha piano</Name> 
     <properties> 
      <allowUpdates>false</allowUpdates> 
      <allowCopy>true</allowCopy> 
     </properties> 
    </item> 
    <item> 
     <ItemType>PIANO_BENCH</ItemType> 
     <Name>A black piano bench</Name> 
     <properties> 
      <allowUpdates>true</allowUpdates> 
      <allowCopy>false</allowCopy> 
      <url>www.yamaha.com</url> 
     </properties> 
    </item> 
    <item> 
     <ItemType>DESK_LAMP</ItemType> 
     <Name>A Verilux desk lamp</Name> 
     <properties> 
      <allowUpdates>true</allowUpdates> 
      <allowCopy>true</allowCopy> 
      <quantity>2</quantity> 
     </properties> 
    </item> 
</Items> 
+0

¿Puede dar una muestra de su XML que usted está tratando de analizar – bendewey

+0

¿Desea proporcionar una muestra de lo que espera obtener? En este contexto, puede haber muchas cosas ... su capacidad para convertirlas en cadenas dependerá de qué tan bien pueda definir lo que está permitido. – Shog9

Respuesta

116

Yo sugeriría lugar de tratar de analizar XML a sí mismo, intenta crear clases que deserializar desde el XML en las clases . Me gustaría fuertemente recomendar siguiendo la respuesta de bendewey.

Pero si no puede hacer esto, hay esperanza. Puede usar Convert.ChangeType.

public static T GetValue<T>(String value) 
{ 
    return (T)Convert.ChangeType(value, typeof(T)); 
} 

Y utilizar como tal

GetValue<int>("12"); // = 2 
GetValue<DateTime>("12/12/98"); 
+0

+1 para Serialización XML a POCO – bendewey

+0

Veré su +1 y le subiré otro +1. Aunque estoy confundido por su elegancia, huele a genéricos por el genérico. – jfar

+0

Discutamos sobre la estética de GetValue () frente a (int) GetValue(): P – Jimmy

5

Puede comenzar con algo más o menos así:

TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 
if (converter != null) 
{ 
    return (T)converter.ConvertFrom(value); 
} 

Si usted tiene que analizar los atributos que son tipos especiales, como los colores o las cadenas de referencia cultural o lo que sea, por supuesto tendrá que crear casos especiales en lo anterior. Pero esto manejará la mayoría de tus tipos primitivos.

+0

si usa GetConverter (typeof (T)) no necesita la variable t ni la nueva() –

+0

Sí, lo reventé muy rápido. Tal vez le dé una edición, gracias. – womp

0

Para que esto funcione correctamente, su método genérico tendrá que delegar su trabajo real en una clase dedicada.

Algo así como

private Dictionary<System.Type, IDeserializer> _Deserializers; 
    public static T GetValue<T>(String value) where T:new() 
    { 
     return _Deserializers[typeof(T)].GetValue(value) as T; 
    } 

donde _Deserializers es una especie de diccionario en el que registrar sus clases. (Obviamente, se requeriría alguna verificación para garantizar que se haya registrado un deserializador en el diccionario).

(En ese caso el que T:. New() es inútil porque el método no necesita crear cualquier objeto

+0

No se puede usar el operador as en tipos genéricos sin la restricción de clase where. – Samuel

+0

woops, no lo conocía. ¿Todavía puedes hacer un cast habitual? Supongo? –

4

Si usted decide ir a la ruta de serialización a POCO (Plain Old CLR Object), entonces hay algunas herramientas que pueden ayudar a generar sus objetos.

  • puede utilizar xsd.exe para generar un archivo .cs en función de su definición XML
  • hay una nueva característica en el WCF REST Starter Kit Preview 2, llamado Pegar como HTML Esta característica es realmente genial y te permite tomar un bloque de HTML que s en su portapapeles, luego cuando lo pega en un archivo cs convierte automáticamente el xml al objeto CLR para la serialización.
+0

La serialización está descartada para el uso previsto de esta función. Consideramos que Xml <-> poco al principio, pero de alguna manera empantana la aplicación cuando el xml llega al rango> 1Mb. El jefe ha dicho que xpath es el camino a seguir –

+0

LINQ to XML es más rápido que xpath. – bendewey

+0

Ver http://en.wikipedia.org/wiki/XML#Processing_files, XPath usa DOM, Linq para XML usa 'pull -rsing' – bendewey

0

de nuevo con la advertencia de que hacer esto es probablemente una mala idea:

class Item 
{ 
    public string ItemType { get; set; } 
    public string Name { get; set; } 
} 

public static T GetValue<T>(string xml) where T : new() 
{ 
    var omgwtf = Activator.CreateInstance<T>(); 
    var xmlElement = XElement.Parse(xml); 
    foreach (var child in xmlElement.Descendants()) 
    { 
     var property = omgwtf.GetType().GetProperty(child.Name.LocalName); 
     if (property != null) 
      property.SetValue(omgwtf, child.Value, null); 
    } 
    return omgwtf; 
} 

prueba de funcionamiento:

static void Main(string[] args) 
{ 
    Item piano = GetValue<Item>(@" 
     <Item> 
      <ItemType /> 
      <Name>A Yamaha Piano</Name> 
      <Moose>asdf</Moose> 
     </Item>"); 
} 
Cuestiones relacionadas