2010-04-09 57 views
4

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

不要担心“虚幻”的调用,如果它们包含某些单词,它们会略微修改对象的名称。

 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声明为单数对象,所以我无法循环它,因为它没有枚举器。

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

我知道在这一点上,我只会保存空串的列表,但那很好。我很乐意看到结构现在保存。

在此先感谢

回答

4

泛型和反射别混合不错,特别是对于名单。我会强烈建议使用(非通用)IList,或者如果失败(某些通用列表不执行它),IEnumerable(自IEnumerable<T> : IEnumerable)和手动调用Add。我觉得你的痛苦,真的(我维护一个OSS序列化API)。

+0

谢谢你,让我想到了解决问题的其他方法。我将列表切换到ArrayLists,一切都很好。 – DrLazer 2010-04-12 08:58:32

+0

@DrLazer - 说实话,你甚至不应该需要那个;因为'List <>'和'ArrayList'都实现了'IList',所以与'IList'接口谈话并且它不关心具体列表是什么。 – 2010-04-12 09:22:16

+0

噢!这完全是一笔交易。谢谢您的帮助 – DrLazer 2010-04-12 09:54:08

1

在C#3,铸造像List<Object>甚至当你不能施放Lists<T>其他类型的Lists<T>。即使转换为List,它也是不允许的。

在4.0中,与in and out关键字相加的方差会有所变化。

以下是Eric Lippert解释如何以及为何如此的链接。

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

+4

C#3.0。没有C#3.5。 – 2010-04-09 16:11:11

+0

不幸的是,我仅限于C#express 2008 – DrLazer 2010-04-09 16:19:21

+0

@Kevin - 列表接口没有差异,因为它们既不是'in'也不是'out'。 – 2010-04-09 17:39:33

5

我假设的实际值不是List<object>而是像一个List<string>List<int>或一些其他类型的,是不是究竟object

如果是这样,那么演员阵容失败的原因是因为泛型类既不是co-也不是逆变。

但是,在C#4.0中,您将能够通过强制转换为IEnumerable<object>来使foreach循环工作,因为接口可以是co/contravariant。

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


编辑:

关于它的思考,你不需要这里的通用差异。 List<T>实现非泛型IEnumerable。这就是所有你需要的foreach循环来操作,你只需要object类型的元素,所以只需要将它转换为IEnumerable而不是List<object>,一切都应该正常工作。

+0

这将是用户自定义对象的列表。 (这些是顶级类下的唯一列表)我使用“object”的原因是因为它可能是包含不同对象类型的许多不同列表中的任何一个。如果我可以遍历该列表并将对象传递回相同的函数,那么它应该通过“aType.Name”找出它的名称并将其写入XML。 不幸的是,我仅限于C#express 2008 – DrLazer 2010-04-09 16:18:53

0

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

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

更新:

如果要求是不是一个List<object>,这也将工作,不涉及列表项的重复:

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

我的propertyinfo类似乎没有OfType方法。我正在使用c#express 2008 – DrLazer 2010-04-09 16:43:48

+0

您需要引用System.Data.Linq.dll并使用System.Linq添加; – 2010-04-09 16:44:57

+1

我讨厌这么说,但这是一个非常浪费的方法。复制列表只是为了读取它?哎哟。 – 2010-04-09 17:43:28