Приведение объекта к T
Я анализирую XML-файл с помощью XmlReader
класс в .NET, и я подумал, что было бы разумно написать общую функцию разбора для чтения различных атрибутов в целом. Я придумал следующую функцию:
private static T ReadData<T>(XmlReader reader, string value)
{
reader.MoveToAttribute(value);
object readData = reader.ReadContentAsObject();
return (T)readData;
}
как я понял, это работает не совсем так, как я планировал; он бросает ошибку с примитивными типами, такими как int
или double
, так как приведение не может преобразовать из string
к числовому типу. Есть ли способ, чтобы моя функция возобладала в измененная форма?
8 ответов
сначала проверьте, можно ли его бросить.
if (readData is T) {
return (T)readData;
}
try {
return (T)Convert.ChangeType(readData, typeof(T));
}
catch (InvalidCastException) {
return default(T);
}
ты пробовал преобразовать.Метод changetype?
Если метод всегда возвращает строку, которую я нахожу нечетной, но это помимо точки, то, возможно, этот измененный код будет делать то, что вы хотите:
private static T ReadData<T>(XmlReader reader, string value)
{
reader.MoveToAttribute(value);
object readData = reader.ReadContentAsObject();
return (T)Convert.ChangeType(readData, typeof(T));
}
вы можете потребовать, чтобы тип был ссылочным типом:
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
//...
}
вы можете предположительно передать в качестве параметра делегат, который будет преобразовываться из строки в T.
на самом деле, проблема здесь заключается в использовании 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;
}
добавить ограничение "class" (или более подробно, как базовый класс или интерфейс ваших объектов exepected 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()
, etc
на самом деле ответы вызывают интересный вопрос, который вы хотите, чтобы ваша функция делала в случае ошибки.
может быть, было бы разумнее построить его в виде метода 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;
}
редактировать: теперь, когда я думаю об этом, мне действительно нужно сделать преобразование.метод changetype тест? разве линия as уже не пытается это сделать? Я не уверен, что дополнительные вызов changetype фактически выполняет все. На самом деле, это может только увеличить нагрузку, генерируя исключение. Если кто-нибудь знает о разнице, которая стоит того, пожалуйста, напишите!