Cast object a T

Sto analizzando un file XML con la class XmlReader in .NET e ho pensato che sarebbe stato intelligente scrivere una funzione di analisi generica per leggere genericamente attributi diversi. Ho trovato la seguente funzione:

 private static T ReadData(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; } 

Come ho capito, questo non funziona del tutto come avevo programmato; genera un errore con tipi primitivi come int o double , poiché un cast non può convertire da una string a un tipo numerico. C’è un modo per la mia funzione di prevalere in forma modificata?

Prima controlla se può essere lanciato.

 if (readData is T) { return (T)readData; } try { return (T)Convert.ChangeType(readData, typeof(T)); } catch (InvalidCastException) { return default(T); } 

Hai provato Convert.ChangeType ?

Se il metodo restituisce sempre una stringa, che trovo dispari, ma questo è oltre il punto, allora forse questo codice modificato farebbe quello che vuoi:

 private static T ReadData(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)Convert.ChangeType(readData, typeof(T)); } 

provare

 if (readData is T) return (T)(object)readData; 

Potresti richiedere che il tipo sia un tipo di riferimento:

  private static T ReadData(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; } 

E poi fare un altro che utilizza i tipi di valore e TryParse …

  private static T ReadDataV(XmlReader reader, string value) where T : struct { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); int outInt; if(int.TryParse(readData, out outInt)) return outInt //... } 

Si può presumibilmente passare, come parametro, un delegato che convertirà da stringa a T.

In realtà, il problema qui è l’uso di ReadContentAsObject. Sfortunatamente, questo metodo non è all’altezza delle sue aspettative; mentre dovrebbe rilevare il tipo più appropriato per il valore, in realtà restituisce una stringa, indipendentemente da cosa (ciò può essere verificato usando Reflector).

Tuttavia, nel tuo caso specifico, conosci già il tipo a cui vuoi trasmettere, quindi direi che stai usando il metodo sbagliato.

Prova a utilizzare ReadContentAs invece, è esattamente ciò di cui hai bisogno.

 private static T ReadData(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAs(typeof(T), null); return (T)readData; } 

Aggiungi un vincolo di “class” (o più dettagliato, come una class base o un’interfaccia dei tuoi oggetti T eccetti):

 private static T ReadData(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; } 

o where T : IMyInterface o where T : new() , ecc

In realtà, le risposte sollevano una domanda interessante, che è ciò che vuoi che la tua funzione faccia in caso di errore.

Forse avrebbe più senso costruirlo sotto forma di un metodo TryParse che tenta di leggere in T, ma restituisce false se non può essere fatto?

  private static bool ReadData(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; } 

modifica: ora che ci penso, ho davvero bisogno di fare il test convert.changetype? la linea non ha già provato a farlo? Non sono sicuro che fare questa chiamata aggiuntiva per i changetype abbia effettivamente portato a termine qualsiasi cosa. In realtà, potrebbe solo aumentare il sovraccarico di elaborazione generando un’eccezione. Se qualcuno sa di una differenza che vale la pena fare, per favore posta!