Приведение объекта к 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));
}

попробовать

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
     //...
 }

вы можете предположительно передать в качестве параметра делегат, который будет преобразовываться из строки в 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 фактически выполняет все. На самом деле, это может только увеличить нагрузку, генерируя исключение. Если кто-нибудь знает о разнице, которая стоит того, пожалуйста, напишите!