【问题标题】:Unable to cast lists with Reflection in C#无法在 C# 中使用反射投射列表
【发布时间】:2013-06-20 03:28:23
【问题描述】:

目前我在使用 C# 中的反射时遇到了很多麻烦。我正在编写的应用程序允许用户使用配置文件修改某些对象的属性。我希望能够将对象模型(用户项目)保存为 XML。下面的函数在 foreach 循环的中间被调用,循环遍历包含项目中所有其他对象的对象列表。这个想法是,它递归地工作以将对象模型转换为 XML。

不用担心调用“Unreal”会稍微修改对象的名称(如果它们包含某些单词)。

      private void ReflectToXML(object anObject, XmlElement parentElement)
  {
     Type aType = anObject.GetType();
     XmlElement anXmlElement = m_xml.CreateElement(Unreal(aType.Name));
     parentElement.AppendChild(anXmlElement);
     PropertyInfo[] pinfos = aType.GetProperties();
     //loop through this objects public attributes
     foreach (PropertyInfo aInfo in pinfos)
     {
        //if the attribute is a list
        Type propertyType = aInfo.PropertyType;
        if ((propertyType.IsGenericType)&&(propertyType.GetGenericTypeDefinition() == typeof(List<>)))
        {
           List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>);
           foreach (object aListObject in listObjects)
           {
              ReflectToXML(aListObject, anXmlElement);
           }
        }
        //attribute is not a list
        else
           anXmlElement.SetAttribute(aInfo.Name, "");
     }
  }

如果一个对象的属性只是字符串,那么它应该将它们写成 XML 中的字符串属性。如果一个对象的属性是列表,那么它应该递归调用“ReflectToXML”作为参数传入,从而创建我需要的嵌套结构,它可以很好地反映内存中的对象模型。

我的问题在于线路

List<object> listObjects = (aInfo.GetValue(anObject,null) as List<object>);

强制转换不起作用,它只返回 null。 在调试时,我将行更改为

object temp = aInfo.GetValue(anObject,null);

在其上打断点以查看“GetValue”返回的内容。它返回一个“对象的通用列表”我当然应该能够转换它吗?烦人的是 temp 变成了一个通用的对象列表,但是因为我将 temp 声明为单个对象,所以我不能循环遍历它,因为它没有 Enumerator。

当我只将对象列表作为类的 propertyInfo 时,如何循环访问它?

我知道此时我只会保存一个空字符串列表,但没关系。我很高兴看到结构暂时保存下来。

提前致谢

【问题讨论】:

    标签: c# .net xml reflection


    【解决方案1】:

    我假设实际值不是List&lt;object&gt;,而是类似于List&lt;string&gt;List&lt;int&gt; 或其他一些不是确切 object 的类型?

    如果是这样,那么强制转换失败的原因是因为泛型类既不是协变的也不是逆变的。

    然而,在 C# 4.0 中,您可以通过强制转换为 IEnumerable&lt;object&gt; 来使 foreach 循环工作,因为接口可以是协变/逆变的。

    (更多)这里有更多信息:http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx


    编辑:

    考虑一下,这里不需要泛型变量。 List&lt;T&gt; 实现了非泛型 IEnumerable。这就是foreach 循环运行所需的全部内容,并且您只需要object 类型的元素,因此只需将其转换为IEnumerable 而不是List&lt;object&gt;,一切都会正常工作。

    【讨论】:

    • 它将是用户自定义对象的列表。 (这些是顶级类下的唯一列表)我使用“对象”的原因是因为它可能是包含不同对象类型的许多不同列表中的任何一个。如果我可以遍历该列表并将对象传递回同一个函数,那么它应该用“aType.Name”找出它的名称并将其写入 XML。不幸的是,我仅限于 C# express 2008
    【解决方案2】:

    泛型和反射不能很好地混合,尤其是对于列表。我会强烈建议使用(非通用)IList,或者如果失败(一些通用列表没有实现它),IEnumerable(因为IEnumerable&lt;T&gt; : IEnumerable)并调用@987654324 @手动。

    我真的感受到了你的痛苦(我维护了一个 OSS 序列化 API)。

    【讨论】:

    • 谢谢,这让我想到了解决问题的其他方法。我将列表切换到 ArrayLists,一切都很好。
    • @DrLazer - 老实说,你甚至不应该需要那个;因为List&lt;&gt;ArrayList 都实现了IList,所以与IList 接口对话,具体列表是什么并不重要
    【解决方案3】:

    在 C# 3 中,您不能将 Lists&lt;T&gt; 转换为其他类型的 Lists&lt;T&gt;,即使转换为 List&lt;Object&gt; 之类的东西也是如此。即使在转换为 List 时也明确不允许。

    在 4.0 中,通过添加 in and out 关键字,接口的变化略有变化。

    这里是 Eric Lippert 的链接,解释了这种情况的原因和原因。

    http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

    【讨论】:

    • 不幸的是,我仅限于 C# express 2008
    • @Kevin - 列表接口没有差异,因为它们既不是in 也不是out
    • @Marc,是的,我试图暗示的是,在 3.0 和 4.0 之间,关于接口的差异通常会发生一些变化,尽管这种变化不一定适用于这种情况。
    【解决方案4】:

    你不能用 OfType() 将它们转换为对象吗?

    List<object> listObjects = anObject.OfType<object>().ToList();
    

    更新:

    如果要求不是针对 List&lt;object&gt;,这也可以工作并且不涉及重复列表项:

    var enumerableObjects = anObject.OfType<object>();
    

    【讨论】:

    • 我的 propertyinfo 类似乎没有 OfType 方法。我正在使用 c# express 2008
    • 需要引用 System.Data.Linq.dll 并使用 System.Linq 添加;
    • 我不想这么说,但这是一种非常浪费的方法。复制列表只是为了阅读它?哎哟。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 2019-02-22
    • 1970-01-01
    • 2011-05-27
    • 2012-04-29
    相关资源
    最近更新 更多