J'analyse un fichier XML avec la classe XmlReader
dans .NET et je pensais qu'il serait intelligent d'écrire une fonction d'analyse générique pour lire différents attributs de manière générique. Je suis venu avec la fonction suivante:
private static T ReadData<T>(XmlReader reader, string value)
{
reader.MoveToAttribute(value);
object readData = reader.ReadContentAsObject();
return (T)readData;
}
Comme je me suis rendu compte, cela ne fonctionne pas entièrement comme je l'avais prévu; il génère une erreur avec les types primitifs tels que int
ou double
, car un transtypage ne peut pas convertir d'un string
en un type numérique. Existe-t-il un moyen de faire prévaloir ma fonction sous une forme modifiée?
Vérifiez d'abord si elle peut être lancée.
if (readData is T) {
return (T)readData;
}
try {
return (T)Convert.ChangeType(readData, typeof(T));
}
catch (InvalidCastException) {
return default(T);
}
Avez-vous essayé Convert.ChangeType ?
Si la méthode renvoie toujours une chaîne, ce que je trouve étrange, mais c'est en plus du point, 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));
}
essayer
if (readData is T)
return (T)(object)readData;
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 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
//...
}
En fait, le problème ici est l'utilisation de ReadContentAsObject. Malheureusement, cette méthode ne répond pas à ses attentes; bien qu'il devrait détecter le type le plus approprié pour la valeur, il retourne en fait une chaîne, quoi qu'il en soit (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 caster, donc je dirais 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;
}
Vous pouvez vraisemblablement transmettre, en tant que paramètre, un délégué qui convertira la chaîne en T.
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
ou where T : new()
, etc.
En fait, les réponses soulèvent une question intéressante, qui 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 renvoie 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, ai-je vraiment besoin de faire le test convert.changetype? la ligne as n'essaye-t-elle pas déjà de le faire? Je ne suis pas sûr que faire cet appel de type de changement 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!