Extending XmlReader Class - IsEndElement()

-

Introduction #

You may find, as I did, the lack of symmetry in the XmlReader Class quite odd. If we look at the NodeType property, which exposes the XmlNodeType enumeration, we find an EndElement, but no StartElement (The Element member actually only identifies opening xml tag elements, but it's not this shortage on which I'd like to elaborate). Only when we look at the methods available to the class do we see an IsStartElement() method for evaluation, but without a corollary method named something like: IsEndElement().

There are dozens of ways of getting around this deficiency, but I'm all for visually appealing code that leaves other coders with a easy and quick understanding of what you are attempting to do. Checking if the reader is on an opening tag with IsStartElement and then finding closing tags by evaluation the reader's NodeType property might work correctly, but just looks wrong to me.

Extension Methods #

What I'd like to do is create a method that looks and feels like the IsStartElement() function, but instead evaluates if the reader is currently on an EndElement node type. This is where extension methods come into play. Extension methods allow you to extend the functionality of a built in class with custom methods that act as if they were native to the class. I think they are best suited for when you are of the sincere belief that method deficit is a slight oversight of the framework designers, and if given the opportunity, they would happily accept your additional coding to improve the underlying code. Since all instances of this type or any derived type will have automatic access to any extension methods written on top of a particular class, you want to be careful with their implementation .

The first step is to open your project, right click on it, click add, then select module:

Add Module

Then give your module a name. I like to create a single Module for all extensions with a name like ExtensionMethods.

IsEndElement Code #

First, you'll need an imports(vb) or using(c#) statement with the extensions Namespace:

Imports System.Runtime.CompilerServices

Then, add the following code to your module:

<Extension()>
Public Function IsEndElement(ByVal xmlReader As XmlReader,
                             Optional ByVal name As String = "") As Boolean
    If xmlReader.NodeType = XmlNodeType.EndElement Then
        If name = "" Then
            'node is end element, name value not set
            Return True
        Else
            If xmlReader.Name = name Then
                'node is end element, AND named the same as parameter
                Return True
            Else
                'node is end element, but name is diff than parameter
                Return False
            End If
        End If
    Else
        'node is not an end element
        Return False
    End If
End Function

And voilà! Now you can call your code on native objects with full IntelliSense:

IntelliSense