我是linq to Xml的新手
我有一个递归方法,它获取参数XElement root
,它应该以一种表示给定递归深度的相关子树根的方式保存XML数据。
void recursiveMethod(XElement root);
更具体地说,还要看一下这个XML示例:
<start>
<Class>
<Worker>
<Name> Dan </Name>
<Phone> 123 </Phone>
<Class>
<Address>
<Street> yellow brick road </Street>
<Zip Code> 123456 </Zip Code>
</Address>
</Class>
</Worker>
</Class>
...
</start>
您可以想象,Name
是值类型,而Address
是类引用
应通过反射动态添加Xml信息(自顶向下方法)。
总而言之,想象一下,我正在调查Worker
班级并达到Address
班级并希望“向下钻取”,所以我想用我的递归方法来调用正确引用当前Worker类的子节点作为新的XElement根,因此我将能够在下面的Address
一级递归深度中添加我通过反射找到的内容。
请注意,此引用应为XElement类型。
我该怎么做?
编辑:如果你有另外想法做所有这些事情而不是XElement
,我会很高兴听到,尽管我更喜欢XElement
参数。
另一个问题:
我已经开始以一种天真的方式实现它,比如遍历所有字段(FieldInfo []的变量),如果我遇到了值类型(IsValueType),我就会做类似的事情
root.Add(new XElement("Field",
new XElement("Type", ...),
new XElement("Variable Name", ...),
new XElement("Value", ...)));
所以,仅仅是为了一般知识:
1.有没有办法只获得一个节点的引用到它的后代,这样在较低的递归级别,我将能够执行另一个root.Add(...),但是这个根将是一个引用以前的孩子? (这意味着在没有Linq语法的情况下进行整个操作)
2.我设法通过反射获得私有字段值而无需使用属性,这有问题吗?我应该总是通过反射中的属性获取值吗?
答案 0 :(得分:5)
此扩展方法将以所需格式构建XElement:
public static class Extensions
{
public static XElement ToXml<T>(this T obj)
{
Type type = typeof(T);
return new XElement("Class",
new XElement(type.Name,
from pi in type.GetProperties()
where !pi.GetIndexParameters().Any()
let value = (dynamic)pi.GetValue(obj, null)
select pi.PropertyType.IsPrimitive ||
pi.PropertyType == typeof(string) ?
new XElement(pi.Name, value) :
Extensions.ToXml(value)
)
);
}
}
这里会发生什么:
dynamic
对象获取。这很重要,否则在递归调用object
方法时,属性值类型将被推断为ToXml<T>
。用法:
Worker worker = new Worker()
{
Name = "Serge",
Phone = "911",
Address = new Address() { Street = "Elm street", ZipCode = 666 }
};
XElement xml = worker.ToXml();
结果:
<Class>
<Worker>
<Name>Serge</Name>
<Phone>911</Phone>
<Class>
<Address>
<Street>Elm street</Street>
<ZipCode>666</ZipCode>
</Address>
</Class>
</Worker>
</Class>
但是 你应该注意两个对象相互引用的情况(在这种情况下会发生无限递归)
在这种情况下,您可以使用类似字典或散列集的内容来存储xml中已存在的所有对象:
Type type = obj.GetType();
if (set.Contains(obj))
return new XElement("Class", new XAttribute("name", type.Name));
set.Add(obj);
return new XElement("Class", ...);