我做了一个小测试实现:
public class DynamicXml : DynamicObject, IEnumerable<XNode>
{
private readonly IEnumerable<XNode> nodes;
public DynamicXml(params XNode[] nodes)
{
this.nodes = nodes;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var children = nodes.OfType<XContainer>().SelectMany(node => node.Elements(binder.Name)).Cast<XNode>().ToArray();
result = new DynamicXml(children);
return true;
}
public IEnumerator<XNode> GetEnumerator()
{
return nodes.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
和例子:
class Program
{
static void Main(string[] args)
{
dynamic dynDoc = new DynamicXml(XDocument.Parse(
@"<foo>
<bar>foobar is here</bar>
<bar>foobar is also here</bar>
<baz>foobar is not here</baz>
</foo>"));
foreach (XElement node in dynDoc.foo.bar)
{
if (node.Value == "foobar is here")
Console.WriteLine("found: {0}", node);
else
Console.WriteLine("not found: {0}", node);
}
Console.ReadKey(true);
}
}
但是,似乎这个和其他一些代码之间的接口不是很好。
例如,如果我们想对节点使用 Linq,我们必须首先显式转换为IEnumerable
... 否则我们Where
将被解释为元素名称。
((DynamicXml)dynXml.foo.bar).Where(x => x.Value == "foobar is here");
您可以Where
直接在动态类型上实现,但您必须像这样限定所有 lambda:
foo.bar.Where((Func<XElement,bool>)(x => x.Value == "foobar is here"))
也就是说,如果您只是从这样的 XML 树中提取值,我认为它可以正常工作。