Quick follow up to today's earlier gripe about useless exception messages. It's actually worse than I described! Not only is this message useless, but it's actually completely misleading as well. :)
There is a a private method within DataSet, called EnforceConstraints, which actually handles all constraint validation. Well guess what else counts as a constraint in this code? Column length! Now, this is fine and makes complete sense, but it is not mentioned anywhere in the exception message. It mentions only "non-null, unique, or foreign-key constraints".
Joy. Only about four hours later, having intermittently worked with that piece of the code, did I finally realize this. :|
Regarding ResetableIterator, I'd certainly call it a flaw. It kind of defeats the purpose of having those nice abstract classes and interfaces in the first place.
Nothing is more frustrating than being told there's a problem, but not being given enough information to solve it. Such is the case with the ConstraintException class. My scenario happens to be that I'm populating a DataSet, which I built using ReadXmlSchema, using the ReadXml method. There's about three UniqueContraints with ForeignKeyConstraints built on top of those. All of those constraints have names and associated tables, yet when my call to ReadXml fails, I get this utterly useless message:
Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
Ok... great, which one?? Here we have this beautiful abstract model of constraints based off the Constraint class, but this exception does nothing except say a constraint has failed. Hello!? How about at least telling me the ConstraintName and Table of the constraint that failed in the message? While we're at it, it would be even more useful to add a property to the ConstraintException class, perhaps called "FailedConstraint", which is a reference to the Constraint that failed so I could pull even more detail based off of it's concrete type if I needed to.
As far as I can see, nowhere in the .NET XslTransform docs is is explicitly said that you can create extension functions that return a node-set. However, I tried a couple of times and discovered it is possible simply by making sure your function returns an XPathNodeIterator. Cool.
However, after experimenting a bit and tons of debugging, I discovered this isn't exactly true. You see, the XslTransform code doesn't expect just any kind of XPathNodeIterator implementation (it is an abstract class, after all), but instead expects you return an object of a very precise type: ResetableIterator, which is a subclass of XPathNodeIterator implemented internally inside System.Xml.dll. So, basically, I see no way you can provide your own extension function returning a custom XPathNodeIterator, which is something I was interested in doing in order to provide an extension function that could "filter" an existing node-set. [Commonality]
To address the first paragraph, it is documented here, but is very indirect. It's documented under the "XSLT Stylesheet Parameters" section in the table which indicates which .NET types map to which XPath types. Reading this would not lead you to believe that it is also possible to return these types from an script function or an extension object's method, but in fact it is. Microsoft should indicate this more clearly in the documentation.
To address your second paragraph, you're absolutely right. It does not look like you can return a custom XPathNodeIterator implementation due to this design (flaw?). However, it's important to point out that you can return an XPathNodeIterator from the base implementation of XPathNavigator::Select because it returns an XPathSelectionIterator which does derive from ResetableIterator.
Here's the test XSLT that I used to test these theories.