将对象转换为T

时间:2009-05-22 19:38:04

标签: c# generics casting

我正在使用.NET中的XmlReader类解析XML文件,我认为编写通用解析函数来一般性地读取不同的属性会很聪明。我提出了以下功能:

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;
}

当我意识到,这并不像我原先计划的那样完全有效;它会导致intdouble等基本类型出错,因为强制转换无法从string转换为数字类型。有没有办法让我的功能以修改后的形式占上风?

8 个答案:

答案 0 :(得分:178)

首先检查是否可以施放。

if (readData is T) {
    return (T)readData;
} 
try {
   return (T)Convert.ChangeType(readData, typeof(T));
} 
catch (InvalidCastException) {
   return default(T);
}

答案 1 :(得分:15)

您是否尝试过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));
}

答案 2 :(得分:7)

if (readData is T)
    return (T)(object)readData;

答案 3 :(得分:3)

您可以要求类型为引用类型:

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

答案 4 :(得分:3)

实际上,这里的问题是使用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;
}

答案 5 :(得分:2)

您可以将参数作为参数传入一个将从字符串转换为T的委托。

答案 6 :(得分:1)

添加一个'class'约束(或更详细的约束,比如你预期的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 : IMyInterfacewhere T : new()

答案 7 :(得分:1)

实际上,这些回复会提出一个有趣的问题,这就是你希望你的函数在出错的情况下做的事情。

以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;
    }

编辑:现在我考虑一下,我真的需要做convert.changetype测试吗? as line是不是已经尝试过这样做了?我不确定做那个额外的changetype调用实际上完成了什么。实际上,它可能只是通过生成异常来增加处理开销。如果有人知道值得做的差异,请发帖!