将对象投射到 T

Posted

技术标签:

【中文标题】将对象投射到 T【英文标题】:Cast object to T 【发布时间】:2009-05-22 19:38:04 【问题描述】:

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

private static T ReadData<T>(XmlReader reader, string value)

    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;

我开始意识到,这并没有完全按照我的计划进行;它会抛出诸如intdouble 等基本类型的错误,因为强制转换无法从string 转换为数字类型。有没有办法让我的功能以修改后的形式占上风?

【问题讨论】:

【参考方案1】:

先看看能不能施放。

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

【讨论】:

我将 Convert.ChangeType 的行更改为:'return (T)Convert.ChangeType(readData, typeof(T), System.Globalization.CultureInfo.InstalledUICulture.NumberFormat) 使其适用于各种不同的文化结构。 这是正确答案。但我可以说 try/catch 在这里完全是多余的。特别是考虑到静音异常。我认为 if(readData is T) ... 部分是一个足够的尝试。 您可以在转换之前检查 readDate 是否为空。如果是,则返回默认值(T)。 我得到“对象必须实现 IConvertible。”【参考方案2】:

你试过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));

【讨论】:

我最初确实查看了 Convert.ChangeType,但由于某些奇怪的原因,我认为它对这个操作没有用。您和 Bob 都提供了相同的答案,我决定混合使用您的答案,因此我避免使用 try 语句,但仍尽可能使用“return (T)readData”。【参考方案3】:

试试

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

【参考方案5】:

其实这里的问题是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;

【讨论】:

看起来相当紧凑和优雅。但是,已接受答案中的解决方案使用了与多种不同文化兼容的 ChangeType,因为它接受 IFormatProvider。由于这是该项目的必需品,因此我将继续使用该解决方案。【参考方案6】:

添加“类”约束(或更详细,如预期 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】:

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

【讨论】:

【参考方案8】:

实际上,响应提出了一个有趣的问题,即您希望函数在出现错误时执行的操作。

也许以 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 行不是已经尝试这样做了吗?我不确定做那个额外的 changetype 调用是否真的能完成任何事情。实际上,它可能只是通过生成异常来增加处理开销。如果有人知道值得做的不同之处,请发布!

【讨论】:

以上是关于将对象投射到 T的主要内容,如果未能解决你的问题,请参考以下文章

如何将对象投射到桌子上?

将 activeX 对象投射到我的对象上的问题

将 Firebase 快照投射到 Swift 3 对象

将对象投射到父级

将数组投射到对象

将一组指针投射到其他对象?