J'analyse un fichier XML avec la XmlReader
classe en .NET et j'ai pensé qu'il serait judicieux d'écrire une fonction d'analyse générique pour lire différents attributs de manière générique. J'ai proposé la fonction suivante:
private static T ReadData<T>(XmlReader reader, string value)
{
reader.MoveToAttribute(value);
object readData = reader.ReadContentAsObject();
return (T)readData;
}
Lorsque je me suis rendu compte, cela ne fonctionne pas entièrement comme je l'avais prévu; il renvoie une erreur avec des types primitifs tels que int
ou double
, car une conversion ne peut pas passer d'un type a string
à un type numérique. Y a-t-il un moyen pour ma fonction de prévaloir sous une forme modifiée?
Avez-vous essayé Convert.ChangeType ?
Si la méthode retourne toujours une chaîne, que je trouve étrange, mais que ce n'est pas le problème, alors peut-être que ce code modifié ferait ce que vous voulez:
private static T ReadData<T>(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)Convert.ChangeType(readData, typeof(T)); }
la source
essayer
if (readData is T) return (T)(object)readData;
la source
Vous pouvez exiger que le type soit un type de référence:
private static T ReadData<T>(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; }
Et puis faites-en un autre qui utilise des types de valeur et 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 //... }
la source
En fait, le problème ici est l'utilisation de ReadContentAsObject. Malheureusement, cette méthode ne répond pas à ses attentes; alors qu'il doit détecter le type le plus approprié pour la valeur, il renvoie en fait une chaîne, quoi qu'il arrive (cela peut être vérifié à l'aide de Reflector).
Cependant, dans votre cas spécifique, vous connaissez déjà le type vers lequel vous souhaitez effectuer un cast, je dirais donc que vous utilisez la mauvaise méthode.
Essayez plutôt d'utiliser ReadContentAs, c'est exactement ce dont vous avez besoin.
private static T ReadData<T>(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAs(typeof(T), null); return (T)readData; }
la source
Vous pouvez vraisemblablement transmettre, en tant que paramètre, un délégué qui convertira de chaîne en T.
la source
Ajoutez une contrainte de `` classe '' (ou plus détaillée, comme une classe de base ou une interface de vos objets T attendus):
private static T ReadData<T>(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; }
ou
where T : IMyInterface
ouwhere T : new()
, etc.la source
En fait, les réponses soulèvent une question intéressante, c'est ce que vous voulez que votre fonction fasse en cas d'erreur.
Peut-être qu'il serait plus logique de le construire sous la forme d'une méthode TryParse qui tente de lire dans T, mais retourne false si cela ne peut pas être fait?
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; }
edit: maintenant que j'y pense, dois-je vraiment faire le test convert.changetype? la ligne as essaie-t-elle déjà de le faire? Je ne suis pas sûr que faire cet appel de changement de type supplémentaire accomplisse réellement quelque chose. En fait, cela pourrait simplement augmenter la surcharge de traitement en générant une exception. Si quelqu'un connaît une différence qui en vaut la peine, veuillez poster!
la source