Я разбираю XML-файл с XmlReader
классом в .NET, и я подумал, что было бы разумно написать общую функцию синтаксического анализа для общего чтения различных атрибутов. Я придумал такую функцию:
private static T ReadData<T>(XmlReader reader, string value)
{
reader.MoveToAttribute(value);
object readData = reader.ReadContentAsObject();
return (T)readData;
}
Как я понял, это работает не совсем так, как я планировал; он выдает ошибку с примитивными типами, такими как int
или double
, поскольку приведение не может преобразовать из a string
в числовой тип. Есть ли способ, чтобы моя функция превалировала в измененной форме?
Вы пробовали Convert.ChangeType ?
Если метод всегда возвращает строку, которую я считаю странной, но помимо этого, возможно, этот измененный код будет делать то, что вы хотите:
private static T ReadData<T>(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)Convert.ChangeType(readData, typeof(T)); }
источник
пытаться
if (readData is T) return (T)(object)readData;
источник
Вы можете потребовать, чтобы тип был ссылочным:
private static T ReadData<T>(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; }
А затем сделайте еще один, который использует типы значений и 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 //... }
источник
Собственно, проблема здесь в использовании ReadContentAsObject. К сожалению, этот метод не оправдывает ожиданий; хотя он должен определять наиболее подходящий тип значения, он фактически возвращает строку, независимо от того, что (это можно проверить с помощью Reflector).
Однако в вашем конкретном случае вы уже знаете тип, к которому хотите применить, поэтому я бы сказал, что вы используете неправильный метод.
Попробуйте вместо этого использовать ReadContentAs, это именно то, что вам нужно.
private static T ReadData<T>(XmlReader reader, string value) { reader.MoveToAttribute(value); object readData = reader.ReadContentAs(typeof(T), null); return (T)readData; }
источник
Предположительно вы можете передать в качестве параметра делегата, который будет преобразовывать из строки в T.
источник
Добавьте ограничение класса (или более подробно, например, базовый класс или интерфейс ваших ожидаемых T-объектов):
private static T ReadData<T>(XmlReader reader, string value) where T : class { reader.MoveToAttribute(value); object readData = reader.ReadContentAsObject(); return (T)readData; }
или
where T : IMyInterface
илиwhere T : new()
и т. д.источник
Собственно, ответы поднимают интересный вопрос: что вы хотите, чтобы ваша функция выполняла в случае ошибки.
Может быть, было бы разумнее построить его в виде метода TryParse, который пытается читать в T, но возвращает false, если это невозможно?
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: теперь, когда я думаю об этом, действительно ли мне нужно проводить тест convert.changetype? Разве строка as уже не пытается это сделать? Я не уверен, что этот дополнительный вызов changetype на самом деле что-то дает. Фактически, это может просто увеличить накладные расходы на обработку, создав исключение. Если кто-то знает разницу, которая стоит того, напишите, пожалуйста!
источник