Update: The LINQ to XML extensibility story

In a previous post I wrote:

There is no guarantee that XLinq classes can be subclassed effectively, although there are currently no plans to seal them.  The recommended way for applications to add functionality to XLinq is by using the annotation feature  to add application-defined objects to XLinq tree objects.  In other words, internal experience with building on top of XLinq has shown that the aggregation design pattern works better than inheritance to extend its functionality.  This is not firm guidance, just advice that we have a real goal of supporting extensibility via annotations and a non-goal of supporting extensibility via inheritance.  This is, however, an area that is very much in flux and we would be particularly interested in hearing your use cases and experiences.

We didn’t hear from anybody on this topic, but have revisited it a few times and have come to a final (?) conclusion.  In a nutshell, LINQ to XML is not designed with subclassing in mind, but the classes are not sealed to prevent someone from subclassing them.  The preferred extensibility mechanism for those who want to add properties or methods is to annotate nodes in the XML tree with application objects of some appropriate type.  The annotation lookup mechanism is designed for speed, and is used by the forthcoming event and validation APIs, as well as some internal projects that leverage LINQ to XML, so we believe it will prove satisfactory for user extensions as well.

Some Q&A: 

Q: Why didn’t you design with subclassing in mind?
A: It would expose as virtual methods (and hence cast in stone) internal details that we might want to change someday; it would extend the surface area of the API with a bunch of stuff that would be difficult to document, test, and secure; and it wouldn’t address the hard problems — you’d still have to write your own load and save code anyway, which is tricky.

Q: Why not just seal the classes if you don’t want people to subclass them?
A: Because you know your needs better than we do.  Maybe your subclasses work better than annotations for some reason we can’t predict. Apparently this is a long-running debate in the .NET world and it’s clear that sealing the classes will annoy at least as many people as it will protect.

Q: Are there any classes I simply can’t subclass?
A: The compiler will forbid you from subclassing any but the leaf classes in the inheritance hierarchy (i.e., not XContainer or XNode), because they have some private virtual methods.  That’s partly to discourage anyone from extending LINQ to XML to add new node types that won’t behave properly when manipulated with the built-in operations.

Q: Grr, everything is virtual in DOM, why did you mess with that?
System.Xml.XmlDocument was designed to be subclassable, but it didn’t work out very well as far as I can tell (stepping in several years later).  Internal teams that did manage to build usable DOM subclasses required a lot of support from the XML team, as I understand it.  Furthermore, the overhead of the virtual calls creates some performance issues. Overall, this was a “it sounded good at the time” idea, not a success story we want to emulate.

Any other questions or comments?  Also, let us know what design rationales and issues you would like me to discuss here.

Comments (1)

  1. me says:

    Thank you so much for not sealing the XLinq classes. I may not need to subclass them now, but I may in the future. I have had far too many headaches working around currently sealed classes.

    Something else to consider is coding to interfaces. This is something that I wish was more prevalent in the framework… Seal your classes _if_ necessary, but make the API generally expect interface arguments. That way both sides can get what they want.