When developing custom XmlReader or XmlWriter in .NET 2.0 there is at least three options:
First way is a for full-blown XmlReader/XmlWriters, which need to implement each aspects of XML reading/writing in a different way, e.g. XmlCsvReader, which reads CSV as XML or XslReader, which streamlines XSLT output. This is the most clean while the hardest way - XmlReader has 26 (and XmlWriter - 24) abstract members you would have to implement. Second and third options are for override-style custom readers/writers. When you only need to partially modify XmlReader/XmlWriter behavior it's an overkill to reimplement it from scratch. As this is the most usual scenario I'll concentrate on these two options.
OOP taught us - inherit the class whose behaviour you want to modify and override its virtual members. That's the easiest and most popular way of writing custom XmlReader/XmlWriter. For example let's say you are receiving XML documents from your business partners and one particularly annoying one keeps sending element <value>, while according to the schema you expect it to be <price>. So you need renaming plumbing - XmlReader that reads <value> as <price> and XmlWriter that writes <price> as <value>. Here are implementations extending standard XmlTextReader and XmlTextWriter classes:
public class RenamingXmlReader : XmlTextReader { //Provide as many constructors as you need public RenamingXmlReader(string file) : base(file) { } public override string Name { get { return (NodeType == XmlNodeType.Element && base.Name == "value") ? "price" : base.Name; } } public override string LocalName { get { return (NodeType == XmlNodeType.Element && base.LocalName == "value") ? "price" : base.LocalName; } } } public class RenamingXmlWriter : XmlTextWriter { //Provide as many constructors as you need public RenamingXmlWriter(TextWriter output) : base(output) { } public override void WriteStartElement(string prefix, string localName, string ns) { if (string.IsNullOrEmpty(prefix) && localName == "price") { localName = "value"; } base.WriteStartElement(prefix, localName, ns); } }Looks nice, but there is a couple of serious drawbacks in this approach though:
So beware that when deriving from XmlTextReader/XmlTextWriter you are gonna inherit all their crappy legacy weirdnesses too.
A third approach is to wrap XmlReader/XmlWriter created via Create() method and override methods you need. This approach is used by .NET itself. This requires a little bit more code, but as a result you get clean design and easily composable implementation. I'll cover it tomorrow 'cause Tel-Aviv traffic jams are waiting for me now.