|
using System;
using System.IO;
using System.Xml;
using System.Collections;
namespace CustomerEnumeration
{
/// <summary>
/// Exposes information about customers. This class can be enumerated over in a foreach loop.
/// </summary>
public class Customers : IEnumerable, IDisposable
{
private CustomerEnumerator custEnumerator = null;
#region IEnumerable Members
// When the foreach loop begins, this method is invoked so that the loop gets an enumerator to query.
public IEnumerator GetEnumerator()
{
if( this.custEnumerator == null )
this.custEnumerator = new CustomerEnumerator();
return this.custEnumerator;
}
#endregion IEnumerable Members
#region IDisposable Members
public void Dispose()
{
if( this.custEnumerator != null )
this.custEnumerator.Dispose();
}
#endregion
}
/// <summary>
/// Exposes the customer data found in Customers.xml.
/// </summary>
public class CustomerEnumerator : IEnumerator, IDisposable
{
#region Data
private readonly string fileName = @"..\..\Customers.xml";
private XmlTextReader reader;
#endregion Data
#region IEnumerator Members
public void Reset()
{
if( this.reader != null )
this.reader.Close();
System.Diagnostics.Debug.Assert( File.Exists( this.fileName ), "Customer file does not exist!" );
StreamReader stream = new StreamReader( this.fileName );
this.reader = new XmlTextReader( stream );
}
public bool MoveNext()
{
// Call Reset the first time MoveNext is called instead of in the constructor
// so that we keep the stream open only as long as needed.
if( this.reader == null )
this.Reset();
if( this.FindNextTextElement() )
return true;
this.reader.Close();
return false;
}
public object Current
{
get
{
// No need to call FindNextTextElement here because it was called for us by MoveNext().
string firstName = this.reader.Value;
// Set 'val' to a default value in case the element was empty.
string val = "";
if( this.FindNextTextElement() )
val = this.reader.Value;
string lastName = val;
// Set 'val' to a default value in case the element was empty.
val = "0";
if( this.FindNextTextElement() )
val = this.reader.Value;
int orders;
try { orders = Int32.Parse( val ); }
catch { orders = Int32.MinValue; }
// Set 'val' to a default value in case the element was empty.
val = "0";
if( this.FindNextTextElement() )
val = this.reader.Value;
decimal balance;
try { balance = Decimal.Parse( val ); }
catch { balance = Decimal.MinValue; }
return new Customer( firstName, lastName, orders, balance );
}
}
#endregion
#region Private Helper
/// <summary>
/// Advances the XmlTextReader to the next Text element in the XML stream.
/// Returns true if there is more data to be read from the stream, else false.
/// </summary>
private bool FindNextTextElement()
{
bool readOn = this.reader.Read();
bool prevTagWasElement = false;
while( readOn && this.reader.NodeType != XmlNodeType.Text )
{
// If the current element is empty, stop reading and return false.
if( prevTagWasElement && this.reader.NodeType == XmlNodeType.EndElement )
readOn = false;
prevTagWasElement = this.reader.NodeType == XmlNodeType.Element;
readOn = readOn && this.reader.Read();
}
return readOn;
}
#endregion Private Helper
#region IDisposable Members
public void Dispose()
{
if( this.reader != null )
this.reader.Close();
}
#endregion
#region Finalizer
~CustomerEnumerator()
{
this.Dispose();
}
#endregion // Finalizer
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.