3

我是 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 信息应通过反射动态添加(以自上而下的方法)。

长话短说,想象我正在调查WorkerClass 并到达AddressClass 并且想要“向下钻取”,所以我想用当前 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.我已经设法通过反射获得私有字段值而不使用属性,这有问题吗?我应该总是通过反射中的属性来获取值吗?

4

1 回答 1

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)
                        )
                    );
    }
}

这里会发生什么:

  • 我们获取传递对象的公共属性(您可以添加 BindingFlags 来过滤属性)。
  • 接下来我验证属性是否具有索引参数并跳过这些属性。
  • 接下来我将属性值作为dynamic对象。这很重要,否则将object在递归调用ToXml<T>方法期间推断属性值类型。
  • 我检查属性类型是原始类型(int、byte、long、single、double 等)还是字符串
  • 对于原始类型,我们编写具有属性值的元素。对于其他类型(复杂),我们递归地开始构建 XElement

用法:

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", ...);
于 2012-12-15T16:33:08.573 回答