tags:

views:

250

answers:

4

One of the areas where I would like to see the use of dynamic is XML. I think it would make XML processing code simpler to write and I believe I saw some examples on that before C# 4 came out and it's mentioned in this answer as one of the uses of this feature.

So, my question is this: why wasn't the XmlDocument (or XDocument) made dynamic, or why isn't there some new class for dynamic XML manipulation in C# 4?

This is even more strange to me, when I consider that in PowerShell, XmlDocument is dynamic, code like $xmlDoc.root.subnode.subsubnode works there.

A: 

Most probably they haven't thought about it, and, programmers are usually not trigger-happy with putting dynamics all over the place: dynamic is a time-bomb. Catch as much as you can at compile time...

Pavel Radzivilovsky
The thing is, you never know what XML you will get and whether it will be what you expect. And if it's not, you have to handle that at runtime, whether you use dynymics or not.
svick
@svick: that's what schema validation is for.
Ben M
A: 

Because XmlDocument predates genereics and fixing it would break old code.

Also, XmlDocument is listed as semi-obsolete.

Joshua
How would it break existing code if a class supported a new interface that wasn't there when the code was written?
nikie
+4  A: 

Given some of the comments, let me provide an alternative answer. The original question asked why XmlDocument was not dynamic in .NET 4. While it may be possible to add "expando" property capability to the existing xml document classes via IDynamicMetaObjectProvider, doing so is likely a non-trivial endeavor. Making the original Xml object model from System.Xml fully dynamic would require some extensive modification of the Xml framework, and would require that IDynamicMetaObjectProvider be added to every object that is involved. That includes XmlDocument, XmlElement, XmlAttribute, XmlNode, and all of the other xml content types like comments, text nodes, etc. In addition, a considerable amount of support infrastructure, internal types, etc. that are involved in the lookup and processing of elements and attributes and values would also need to be modified (open up Reflector, and take a look at System.Xml...more than half of the types are internal, and they are all highly interdependent with each other and the available public types.)

It is also important to consider the proper scope of implementing expando properties for Xml in .NET. Would you stop at just the XmlDocument and related types? Or would it be more appropriate to include XPath, Xml Schema, etc.?

To answer the original question, "Why isn’t XmlDocument dynamic in .NET 4?", I think the simple answer is this: Implementing fully 'dynamic' API's, or in the case of Xml here, API's that provide property expansion of arbitrary xml documents, is far from a trivial task. Given Microsoft's work ethic, it makes logical sense that they would not approach such a task lightly, and if they attempt to implement expando properties for the Xml framework, I would hope and expect it to be done with the same level of careful attention and care they give to the rest of .NET.

jrista
Interesting answer, but my question is, why isn't there any type that could handle the `xmlDoc.root.subnode.subsubnode` syntax in C#? (Probably by implementing `IDynamicMetaObjectProvider`, if I understand it correctly.)
svick
But you can do that in C# 4, you can manage member lookup by yourself, see e.g. http://channel9.msdn.com/posts/RobBagby/deCast-Dynamic-Xml-with-C-40/.
svick
Yes, objects can be truly dynamic. See `DynamicObject` and `ExpandoObject` classes on MSDN, and the interfaces they implement. As such, the answer is effectively incorrect, and it is quite possible for e.g. `XmlDocument` to add the ability to be accessed as `((dynamic)root).foo.bar.baz` in future releases.
Pavel Minaev
@Pavel: Sure, I've read about DynamicObject and ExpandoObject. However, it would be considerably more difficult to make an XmlDocument truly navigable via runtime-dynamic "expando" properties than simply adding IDynamicMetaObjectProvider to XmlDocument. You would need to add 'dynamic' capability to every xml object in the tree, such as elements, attributes, text nodes, etc. I guess I see it more of a way of implementing sugary syntax translation than dynamic objects. The type itself is still concrete, although I guess you could add property-style accessors for an Xml document.
jrista
@svick: I did view that video, and I have also read a few articles on implementing expando properteis with IDynamicMetaObjectProvider in .NET. In most (perhapse all) of the examples I have seen so far seemed to be rather specific to the application at hand. I gave it some thought, and updated my answer to more directly answer your original question. It occurred to me that supporting property expansion of an xml document is far from a trivial task...and riddled with issues.
jrista
As a simple example...how does one expand this: <root><person-info><first-name>Jon</first-name><last-name>Rista</last-name></person-info></root>. Using expando properties via `IDynamicMetaObjectProvider` on an XmlDocument...the resulting code to retrieve my first name would be: xmlDoc.root.person-info.first-name. Despite the fact that those element names are perfectly valid XML identifiers...they are invalid in the context of C# (and many other languages.) Reference: http://www.w3.org/TR/2000/REC-xml-20001006#NT-Nmtoken
jrista
+6  A: 

I'm surprised at the amount of seemingly authoritative discussion without an answer. Your question is FANTASTIC. It addresses EXACTLY what the dynamic keyword was intended for. The trouble is, not a lot of people really know how to use it to its fullest.

While MS didn't build the dynamic XML objects for us, they did give us the tools to do it ourselves with the DynamicObject class. Here's one way to do what you're asking for with the old XmlDocument class.

public class DynamicXmlElement : DynamicObject {
   XmlElement _xmlEl;

   public DynamicXmlElement(string xml) {
      var xmldoc = new XmlDocument();
      xmldoc.LoadXml(xml);
      _xmlEl = xmldoc.DocumentElement;
   }

   public DynamicXmlElement(XmlElement el) {
      _xmlEl = el;
   }

   public override bool TrySetMember(SetMemberBinder binder, object value) {
      return false;
   }

   public override bool TryGetMember(GetMemberBinder binder, out object result) {
      XmlElement el = (XmlElement)_xmlEl.SelectSingleNode(binder.Name);
      if (el != null) {
         result = new DynamicXmlElement(el);
         return true;
      }
      else if (binder.Name == "root") {
         result = new DynamicXmlElement(_xmlEl.OwnerDocument.DocumentElement);
         return true;
      }
      else {
         result = null;
         return false;
      }
   }

   public override string ToString() {
      return _xmlEl.InnerText;
   }
}

And here's how you would call the code. Note that this compiles in C# 4.0 only.

namespace ConsoleApplication4 {
   class Program {
      static void Main(string[] args) {
         var xmlstr = "<r><subnode><subsubnode>ABCs of dynamic classes</subsubnode></subnode></r>";
         dynamic xml = new DynamicXmlElement(xmlstr);
         Console.WriteLine(xml.subnode.root.subnode.subsubnode); // take the long way around...
         Console.ReadKey(true);
      }
   }
}

I can't take all the credit for this. Bamboo wrote this code for Boo back in 2003. C# has slowly been getting the features that Boo has had in .NET for years... first type inference, and now the IQuackFu style DynamicObject. Once they implement language macros so that you can make DSLs, I think they'll have caught up.

I'll leave writing the newer style XElement version of this code to the reader.

mattmc3
"It addresses EXACTLY what the dynamic keyword was intended for" - what the `dynamic` keyword was _intended_ for is something only the designers of the language, and the related part of the runtime library, can authoritatively answer. In this case, it was repeatedly stated that the #1 use case for `dynamic` is in fact working with Office APIs, and #2 is working with objects exposed from dynamic languages. This isn't to say that there aren't other valid uses, but me thinks the "intended for" claim is a tad too assertive.
Pavel Minaev
Fair enough. I suppose I should have said "It addresses what the DynamicObject class in conjunction with the dynamic keyword was MOST LIKELY intended for".Even the bloggers over at Microsoft are using it for this very purpose: http://blogs.msdn.com/b/csharpfaq/archive/2009/10/19/dynamic-in-c-4-0-creating-wrappers-with-dynamicobject.aspx
mattmc3