【问题标题】:Cast object to T将对象投射到 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 转换为数字类型。有没有办法让我的功能以修改后的形式占上风?

【问题讨论】:

    标签: c# generics casting


    【解决方案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 调用是否真的能完成任何事情。实际上,它可能只是通过生成异常来增加处理开销。如果有人知道值得做的不同之处,请发布!

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-12-21
              • 2014-02-13
              • 1970-01-01
              • 2012-08-14
              相关资源
              最近更新 更多