Estoy analizando un archivo XML con la XmlReader
clase en .NET y pensé que sería inteligente escribir una función de análisis genérico para leer diferentes atributos de forma genérica. Se me ocurrió la siguiente función:
private static T ReadData<T>(XmlReader reader, string value)
{
reader.MoveToAttribute(value);
object readData = reader.ReadContentAsObject();
return (T)readData;
}
Como me di cuenta, esto no funciona del todo como lo había planeado; arroja un error con tipos primitivos como int
o double
, ya que una conversión no puede convertir de un string
tipo a numérico. ¿Existe alguna forma de que mi función prevalezca en forma modificada?
¿Ha probado Convert.ChangeType ?
Si el método siempre devuelve una cadena, lo que me parece extraño, pero eso es más allá del punto, entonces tal vez este código cambiado haría lo que quieres:
private static T ReadData<T>(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)Convert.ChangeType(readData, typeof(T)); }
fuente
tratar
if (readData is T) return (T)(object)readData;
fuente
Podría requerir que el tipo sea un tipo de referencia:
private static T ReadData<T>(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; }
Y luego haz otro que use tipos de valor y TryParse ...
private static T ReadDataV<T>(XmlReader reader, string value) where T : struct { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); int outInt; if(int.TryParse(readData, out outInt)) return outInt //... }
fuente
En realidad, el problema aquí es el uso de ReadContentAsObject. Desafortunadamente, este método no está a la altura de sus expectativas; si bien debería detectar el tipo más apropiado para el valor, en realidad devuelve una cadena, pase lo que pase (esto se puede verificar usando Reflector).
Sin embargo, en su caso específico, ya sabe el tipo al que desea transmitir, por lo tanto, diría que está utilizando el método incorrecto.
Intente usar ReadContentAs en su lugar, es exactamente lo que necesita.
private static T ReadData<T>(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAs(typeof(T), null); return (T)readData; }
fuente
Presumiblemente, puede pasar, como parámetro, un delegado que se convertirá de cadena a T.
fuente
Agregue una restricción de 'clase' (o más detallada, como una clase base o interfaz de sus objetos T esperados):
private static T ReadData<T>(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; }
o
where T : IMyInterface
owhere T : new()
, etc.fuente
En realidad, las respuestas plantean una pregunta interesante, que es qué desea que haga su función en caso de error.
¿Quizás tendría más sentido construirlo en forma de un método TryParse que intenta leer en T, pero devuelve falso si no se puede hacer?
private static bool ReadData<T>(XmlReader reader, string value, out T data) { bool result = false; try { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); data = readData as T; if (data == null) { // see if we can convert to the requested type data = (T)Convert.ChangeType(readData, typeof(T)); } result = (data != null); } catch (InvalidCastException) { } catch (Exception ex) { // add in any other exception handling here, invalid xml or whatnot } // make sure data is set to a default value data = (result) ? data : default(T); return result; }
editar: ahora que lo pienso, ¿realmente necesito hacer la prueba convert.changetype? ¿la línea as ya no intenta hacer eso? No estoy seguro de que hacer esa llamada de tipo de cambio adicional realmente logre algo. En realidad, podría aumentar la sobrecarga de procesamiento generando una excepción. Si alguien sabe de una diferencia que hace que valga la pena hacerla, ¡publíquela!
fuente