Implementing a Collection Class Using .NET
Implementing a Collection Class Using .NET
Common Behaviors of Collections
Introduction
Although you can create a collection class from scratch, most collections classes share some fundamental behaviors and characteristics that you can apply when creating a collection class. To give a skeleton of these default requirements, the .NET Framework provides a few interfaces that you can implement.
Practical Learning: Introducing .NET Collection Classes
Introduction to the ICollection Interface
One of the primary pieces of information you should provide about the values in a collection is the number of items a list is (currently) holding. When creating a collection class, to prepare it to provide this valuable information, you can (should) implement an interface named ICollection. The ICollection interface is defined in the System.Collections namespace. The ICollection interface derives from the IEnumerable initerface:
public interface ICollection : IEnumerable
The generic equivalent of the ICollection interface is defined in the System.Collections.Generic namespace. The ICollection<> interface inherits from the IEnumerable<> and the IEnumerable interfaces:
public interface ICollection<T> : IEnumerable<T>, IEnumerable
Therefore, to start a collection class, you can first implement one of these interfaces. Here is an example for the System.Collections.ICollection<> interface:
using System.Collections.generic; public class Itemization<T> : ICollection<T> { }
Thanks to the flexibility of arrays in the .NET Framework, you can create the items of the collection as an array and give it an initial size. Here is an example:
using System.Collections.Generic; public class Itemization<T> : ICollection<T> { private int size; private T[] items; public Itemization() { size = 0; items = new T[10]; } }
Implementing ICollection
To assist you with keeping track of the number of items in a collection, the ICollection<T> interface is equipped with an integral property named Count, which you must implement. To do this, you can create a private member variable that will actually keep a count of the number of items. The Count property can then be used to communicate this information to the clients of the class. Here is an example:
using System.Collections.Generic;
public class Itemization<T> : ICollection<T>
{
private int size;
public Itemization()
{
size = 0;
}
public virtual int Count
{
get { return size; }
}
}
The ICollection<> interface also allows its implementer to copy some of its items to an array. To provide this functionality, the interface is equipped with a method named CopyTo, which you must implement. The syntax of this method is:
void CopyTo(T[] array, int arrayIndex);
This method takes two arguments. The first argument is the array that will receive the items. The second argument is the index of the item from where the copying operation will begin. Here is an example:
public class Itemization<T> : ICollection<T>
{
private int size;
private T[] items;
public Itemization()
{
size = 0;
items = new T[10];
}
public virtual int Count
{
get { return size; }
}
public void CopyTo(T[] array, int index)
{
T[] values = new T[size];
for (int i = 0; i < size; i++)
values[i] = items[i];
array = values;
}
}
The System.Collections.ICollection interface extends the IEnumerable interface. The System.Collections.Generic.ICollection<T> interface extends the IEnumerable and the IEnumerable<> interfaces. In the previous lesson, we saw that this means that you should be able to use foreach in your ICollection<>-based collections but you must create the functionality yourself, which is done by implementing the GetEnumerator() method. Because the ICollection<> interface inherits from IEnumerable<> that itself inherits from IEnumerable, you must implement two versions of the GetEnumerator() methods. As we saw already, their syntaxes are:
IEnumerator<T> GetEnumerator(); IEnumerator GetEnumerator();
Even if you don't want to support this feature, you still must provide at least a skeleton for these methods. Here is an example:
public class Itemization<T> : ICollection<T>
{
private int size;
private T[] items;
public Itemization()
{
size = 0;
items = new T[10];
}
public virtual int Count
{
get { return size; }
}
public void CopyTo(T[] array, int index)
{
T[] values = new T[size];
for (int i = 0; i < size; i++)
values[i] = items[i];
array = values;
}
public IEnumerator<T> GetEnumerator()
{
int counter = 0;
while (counter < Count)
{
yield return items[counter];
counter++;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
int counter = 0;
while (counter < Count)
{
yield return items[counter];
counter++;
}
}
}
Introduction to the IList Interface
Overview
While the System.Collections.Generic.ICollection<> (and the System.Collections.ICollection) interface provides basic functionality, to assist you in laying out a foundation of a collection class as complete as possible, the .NET Framework provides an interface named IList<> (and its accompanying IList interface). The IList<> interface is defined in the System.Collections.Generic namespace and its non-generic equivalent of the same name is defined in the System.Collections namespace. To use the functionalities of the System.Collections.Generic.IList<> interface necessary to add, insert, get, and delete items from a collection, you must create a class that implements them.
Implementing IList
The System.Collections.IList interface starts as follows:
public interface IList : ICollection, IEnumerable
The System.Collections.Generic.IList<> interface starts as follows:
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
As mentioned above, to create a collection, you can implement the IList<> interface. Here is an example of starting it:
using System.Collections.Generic; public class Itemization<T> : IList<T> { }
This means that the IList<> interface extends the ICollection<>, the IEnumerable<>, and the IEnumerable interfaces. This also implies that you must implement the members of all these parent interfaces, including the Count, the IsReadOnly properties, the CopyTo(), and the GetEnumerator() methods as we saw above. From what we learned with the ICollection interface, here are examples of implementing these members for the System.Collections.IList<T> interface:
public class Itemization<T> : IList<T>
{
private int size;
private T[] items;
public Itemization()
{
size = 0;
items = new T[10];
}
public void CopyTo(T[] array, int arrayIndex)
{
T[] values = new T[size];
for (int i = 0; i < size; i++)
values[i] = items[i];
array = values;
}
public int Count
{
get { return size; }
}
public IEnumerator<T> GetEnumerator()
{
int counter = 0;
while (counter < Count)
{
yield return items[counter];
counter++;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
int counter = 0;
while (counter < Count)
{
yield return items[counter];
counter++;
}
}
}
As you may know already, while you are implementing an interface, if you are working in Microsoft Visual Studio, it would keep displaying some warnings to remind you about some member(s) you haven't implemented yet. Microsoft Visual Studion can generate skeleton code for your implementation. This would accomplish two goals: 1) it would eliminate the warnings (and errors), 2) it would provide a type of default implementation or a member.
To ask Microsoft Visual Studio to generate code for your interface implementation, start the class in the Code Editor and specify its interface(s). Then:
Practical Learning: Starting an IList Implementation
using System; using System.Collections.Generic; namespace WaterDistributionCompany2 { [Serializable] public class Collection<T> : IList<T> { } }
using System; using System.Collections; using System.Collections.Generic; namespace WaterDistributionCompany2 { [Serializable] public class Collection<T> : IList<T> { // This field will hold the number of items as they are added or removed private int counter; // This array holds the items of the collection private T[] items; // The default constructor is used to initialize a constructor with some default values. public Collection() { counter = 0; // We will start the collection with a capacity for 10 items items = new T[10]; } /* IList<T>: This indexed property makes it possible to access each item as done in an array. */ public T this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } /* ICollection<T>: This read-only property holds the total number of items in the collection*/ public int Count => counter; /* ICollection<T>: This property would prevent new item addition.*/ public bool IsReadOnly => throw new NotImplementedException(); /* ICollection<T>: This method is used to add a new item to the collection.*/ public void Add(T item) { throw new NotImplementedException(); } // ICollection<T>: This method deletes all items from the collection public void Clear() { throw new NotImplementedException(); } /* ICollection<T>: This method is used to find out whether * the collection contains the item passed as argument. */ public bool Contains(T item) { throw new NotImplementedException(); } /* ICollection<T>: This method is used to copy * the items of this collection to an array passed as argument. */ public void CopyTo(T[] array, int arrayIndex) { throw new NotImplementedException(); } /* IEnumerable<T>: Used for iteration */ public IEnumerator<T> GetEnumerator() { throw new NotImplementedException(); } /* IList<T>: This method checks whether the item * passed as argument exists in the collection. If so, it returns its index. */ public int IndexOf(T item) { throw new NotImplementedException(); } /* IList<T>: This method can be used to insert an item at a certain position inside the collection. */ public void Insert(int index, T item) { throw new NotImplementedException(); } /* ICollection<T>: This method first checks the existence of * the item passed as argument. If the item exists, the method deletes it. */ public bool Remove(T item) { throw new NotImplementedException(); } /* IList<T>: This method can be used to delete the item positioned at the index passed as argument. */ public void RemoveAt(int index) { throw new NotImplementedException(); } /* IEnumerable: Used for iteration */ IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } } }
Populating a Collection
A Read-Only Collection
Most collections are made to receive new values. If you want, you can create a list that cannot receive new values. To support this, the IList interface is equipped with a Boolean property named IsReadOnly. If a list is read-only, it would prevent the clients from adding items to it.
Here is an example of implementing the IsReadOnly property for the System.Collections.IList<T> interface:
public class Itemization<T> : IList<T>
{
private int size;
private T[] items;
public Itemization()
{
size = 0;
items = new T[10];
}
public void CopyTo(T[] array, int arrayIndex)
{
T[] values = new T[size];
for (int i = 0; i < size; i++)
values[i] = items[i];
array = values;
}
public int Count
{
get { return size; }
}
public bool IsReadOnly
{
get { return false; }
}
public IEnumerator<T> GetEnumerator()
{
int counter = 0;
while (counter < Count)
{
yield return items[counter];
counter++;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
int counter = 0;
while (counter < Count)
{
yield return items[counter];
counter++;
}
}
}
Practical Learning: Setting the Read-Only Effect
. . .
[Serializable]
public class Collection<T> : IList<T>
{
. . . No Change
/* ICollection<T>: This property would prevent new item addition.*/
public bool IsReadOnly => false;
. . . Change
}
}
Adding an Item
As it should be obvious, the primary operation to perform on a list is to populate it with at least one value or object. To support this operation, the IList<> interface is equipped with a method named Add. Its syntax is:
void Add(T item);
This method takes one argument as the value to add to the collection. If your collection is an array, you can first check that there is still enough room to add a new item. In reality, this is never an issue with the System.Collections.IList interface:
We saw that the Add() method could be defined as follows::
public class Itemization<T> : IList<T>
{
private int size;
private T[] items;
. . .
public int Add(T item)
{
this.items[this.size] = item;
this.size++;
return size;
}
}
By default, an array has a fixed size. If you try adding an item in a position higher than the maximum number of items, the compiler would throw an IndexOutOfRangeException exception. Fortunately, we saw that the Array class is equipped with a method named Resize. This allows you to increase the size of an array when you judge it necessary. As a consequence, you can have an array as big as possible.
Practical Learning: Adding an Item to the Collection
. . . [Serializable] public class Collection<T> : IList<T> { . . . No Change private void CheckAndIncreaseIfNecessary() { // If there is not enough room to add a new item (low capacity), create room for 5 additional items. if (counter >= items.Length) Array.Resize<T>(ref items, items.Length + 5); } /* ICollection<T>: This method is used to add a new item to the collection.*/ public void Add(T item) { // Check whether there is still room in the array. // If there is not enough room, then increase the capacity CheckAndIncreaseIfNecessary(); // Add the item at the end items[counter] = item; // Increase the current number of items counter++; } . . . No Change } }
Inserting an Item
When you call the Add() method, it adds the new value to the end of the list. Sometimes, you will want the new value to be inserted somewhere inside the list. To support this operation, both the System.Collections.IList and the System.Collections.Generic.IList interfaces provide a method named Insert. The syntax of the System.Collections.IList.Insert() method is:
void Insert(int index, object value);
The syntax of the System.Collections.Generic.IList.Insert() method is:
void Insert(int index, T value);
This method takes two arguments. The second argument is the value or object that will be inserted into the list. The argument must hold a valid value or object. Because the System.Collections.IList.Insert() method takes an object value, if your collection is using a different type of value, you may have to cast it to object. The first argument is the index of the item that will precede the new one.
As mentioned for the System.Collections.IList.Add() method, there are a few things you should know about this operation's success or failure:
When calling the IList<>.Insert() method, if you pass an invalid index, the compiler would throw an ArgumentOutOfRangeException.
Practical Learning: Inserting a Record
using System; using System.Collections; using System.Collections.Generic; namespace WaterDistributionCompany21 { [Serializable] public class Collection<T> : IList<T> { . . . No Change /* IList<T>: This method can be used to insert an item at a certain position inside the collection. */ public void Insert(int index, T item) { // If the index is the same as the current number of items // then call Add() and proceed as if we want to add a new item if (index >= counter) { Add(item); } // If the index is positive but less than the current size, // then you need to insert the item inside the collection. if ((index >= 0) && (index < counter)) { // First, push each item one position up to create // an empty space for (int i = (counter - 1); i > index - 1; i--) items[i + 1] = items[i]; // Then put the new item in the indicated position items[index] = item; // Since the new item has been added, increase the // current number of items counter++; } } . . . No Change } }
Locating an Item in the Collection
this Item of a Collection
While using a list, various operations require that you know the object you are currently accessing. To support this operation, the IList and the IList<> interfaces are equipped with an indexed property named Item that you must implement. The Item property of the System.Collection.Generic.IList interface is declared as follows:
T this[int index] { get; set; }
If you implement it right, this property can perform one of three operations:
Here is an example of implementing the indexed property of the IList<> interface:
public class Itemization<T> : IList<T>
{
private int size;
private T[] items;
. . .
// The index property can be used to add an item to a collection,
// or to get an item from the collection
public T this[int index]
{
get
{
return this.items[index];
}
set
{
this.items[index] = value;
}
}
}
After creating this property, you can then access an item using its index and applying the [] operator on its instance.
Practical Learning: Identifying this Item in the Collection
using System; using System.Collections; using System.Collections.Generic; namespace WaterDistributionCompany4.Models { [Serializable] public class Collection<T> : IList<T> { . . . No Change /* IList<T>: This indexed property makes it possible to access EACH item as done in an array. */ public T this[int index] { get { return items[index]; } set { items[index] = value; } } . . . No Change } }
Iterating Through a Collection
One of the most valuable operations to make available to a collection is the abilite to visit each one of its members. As we saw already, this operation is supported by the GetEnumerator() method provided by the IEnumerable<T> interface that each collection class implements.
Practical Learning: Iterating Through a Collection
using System; using System.Collections; using System.Collections.Generic; namespace WaterDistributionCompany21 { . . . /* IEnumerable<T>: Used for iteration */ public IEnumerator<T> GetEnumerator() { int number = 0; while (number < Count) { yield return items[number]; number++; } } . . . /* IEnumerable: Used for iteration */ IEnumerator IEnumerable.GetEnumerator() { int number = 0; while (number < Count) { yield return items[number]; number++; } } } }
Checking Whether a Collection Contains a Certain Item
One of the routine operations you can perform on a list is to find out whether it contains a certain value. To assist you with this operation, the IList<> interface is equipped with a method named Contains. Its syntax is:
bool Contains(T item);
This method takes as argument the value to look for. If the value is found in the collection, the method returns true. If the value is not found in the collection, this method returns false. Here is an example of implementing this method:
public class Itemization<T> : IList<T>
{
private int size;
private T[] items;
. . .
public bool Contains(T value)
{
for (int i = 0; i < Count; i++)
if (items[i].Equals(value))
return true;
return false;
}
}
This method calls the Equals() method of the objects that make up the list to find out whether the value argument exists in the collection. If this method produces a wrong result, especially if you are using your own class to represent the item, you should (must) override the Equals() method. Here is an example of a class that indicates that two Employee objects are the same if they have the same employee number (because two employees in the same company/collection should not have the same employee number:
using System.Collections.Generic;
public class Itemization<T> : IList<T>
{
. . . No Change
}
public class Employee
{
public long EmployeeNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public double HourlySalary { get; set; }
public override bool Equals(object obj)
{
Employee empl = (Employee)obj;
if (this.EmployeeNumber == empl.EmployeeNumber)
return true;
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
Practical Learning: Checking Whether a Collection Contains a Certain Item
using System;
using System.Collections;
using System.Collections.Generic;
namespace WaterDistributionCompany2
{
[Serializable]
public class Collection<T> : IList<T>
{
. . . No Change
/* ICollection<T>: This method is used to find out whether
* the collection contains the item passed as argument. */
public bool Contains(T item)
{
for (int i = 0; i < counter; i++)
if (items[i].Equals(item))
return true;
return false;
}
. . . No Change
}
}
Getting the Index of an Item
The Contains() method is used to check whether a particular value (already) exists in the collection. If you know that a certain item exists but you don't know its index inside the list, the IList<> interface can assist you through a method named IndexOf. Its syntax is:
int IndexOf(T item);
This method takes as argument the value to look for in the list. If the value is found in the collection, the method returns its index. If there is no value defined like that, the method returns -1. Here is an example of implementing this method:
public class Itemization<T> : IList<T>
{
private int size;
private T[] items;
. . .
public int IndexOf(T value)
{
for (int i = 0; i < Count; i++)
if (items[i].Equals(value))
return i;
return -1;
}
}
Once again, this method calls the Equals() method of the objects that make up the collection. In most cases, you should make sure you override the Equals() method in the class that T represents.
Practical Learning: Getting the Index of an Item
using System;
using System.Collections;
using System.Collections.Generic;
namespace WaterDistributionCompany2
{
[Serializable]
public class Collection<T> : IList<T>
{
. . . No Change
/* IList<T>: This method checks whether the item
* passed as argument exists in the collection. If so, it returns its index. */
public int IndexOf(T item)
{
for (int i = 0; i < counter; i++)
if (items[i].Equals(item))
return i;
return -1;
}
. . . No Change
}
}
Items Maintenance in a Collection
Editting an Item
Editing an item consists of changing its value or one of its details. The IList interface doesn't provide its own method to do this. The reason is that it depends on the item and what you are trying to do. For example, if the collection is made of value types or strings, it is easy to change the value. If the collection is made of objects, then you must decide what value of a property you want to change, and this can be unpredictable. As done in formal database, the best steps to follow are:
Deleting a Value by its Index
If a value is not necessary in your collection, you can delete it. Probably the simplest way to delete a value is to specify its position in the list. To support this operation, both the System.Collections.IList and the System.Collections.Generic.IList interfaces are equipped with a method named RemoveAt. The syntax of the RemoveAt() method is the same for both interfaces and it is:
void RemoveAt(int index);
This method takes as argument the index of the value to be removed. If the index is valid, the method removes the item at that position. If the index is not valid, the compiler would throw an ArgumentOutOfRangeException exception. If the item cannot be deleted for another reason, the compiler would throw a NotSupportedException exception.
Practical Learning: Deleting a Value by its Index
using System; using System.Collections; using System.Collections.Generic; namespace WaterDistributionCompany21 { . . . /* IList<T>: This method can be used to delete the item positioned at the index passed as argument. */ public void RemoveAt(int index) { // First check that the user provided a positive index that // is lower than the current total number of items if ((index >= 0) && (index < counter)) { // If so, starting at that index, get the item ahead of // each position and assign it to the current item for (int i = index; i < counter - 1; i++) items[i] = items[i + 1]; // Since the last item is not useful anymore, // decrease the number of items counter--; } } /* IEnumerable: Used for iteration */ IEnumerator IEnumerable.GetEnumerator() { int number = 0; while (number < Count) { yield return items[number]; number++; } } } }
Deleting an Item by its Value
The above method could deleting the wrong value or object if you provide the wrong index. An alternative is to first precisely define the value or the object you want to get rid of, and then hand the value or object to the compiler that would remove it. To support this approach, the System.Collections.IList interface is equipped with a method named Remove. Its syntax is:
bool Remove(T item);
This method takes as argument the value to be deleted. This means that the compiler will first look for the value in the list. If it finds that value, it removes it. If there is no value like that, nothing would happen.
Practical Learning: Creating a Boolean Conditions
using System; using System.Collections; using System.Collections.Generic; namespace WaterDistributionCompany2 { . . . /* ICollection<T>: This method first checks the existence of * the item passed as argument. If the item exists, the method deletes it. */ public bool Remove(T item) { // First try to get the index of the item to find out if it exists int index = IndexOf(item); // If the item was found ... if (index >= 0) { // ... delete it, using its index RemoveAt(index); // Since the item has been removed, return true return true; } // If the item was not removed (for any reason), return false return false; } . . . } }
Clearing a Collection
To let you remove all values or objects from a list, the IList<> interface is equipped with a method named Clear. Its syntax is:
void Clear();
Practical Learning: Clearing a Collection
using System; using System.Collections; using System.Collections.Generic; namespace WaterDistributionCompany21 { [Serializable] public class Collection<T> : IList<T> { // This field will hold the number of items as they are added or removed private int counter; // This array holds the items of the collection private T[] items; // The default constructor is used to initialize a constructor with some default values. public Collection() { counter = 0; // We will start the collection with a capacity for 10 items items = new T[10]; } /* IList<T>: This indexed property makes it possible to access EACH item as done in an array. */ public T this[int index] { get => items[index]; set => items[index] = value; } /* ICollection<T>: This read-only property holds the total number of items in the collection*/ public int Count => counter; /* ICollection<T>: This property would prevent new item addition.*/ public bool IsReadOnly => false; private void CheckAndIncreaseIfNecessary() { // If there is not enough room to add a new item (low capacity), create room for 5 additional items. if (counter >= items.Length) Array.Resize<T>(ref items, items.Length + 5); } /* ICollection<T>: This method is used to add a new item to the collection.*/ public void Add(T item) { // Check whether there is still room in the array. // If there is not enough room, then increase the capacity CheckAndIncreaseIfNecessary(); // Add the item at the end items[counter] = item; // Increase the current number of items counter++; } // ICollection<T>: This method deletes all items from the collection public void Clear() { // Visit each item in the collection and set it to the default value // (This is not really necessary) for (int i = 0; i < counter; i++) items[i] = default(T); // Reset the number of items of the collection to 0 counter = 0; } /* ICollection<T>: This method is used to find out whether * the collection contains the item passed as argument. */ public bool Contains(T item) { for (int i = 0; i < counter; i++) if (items[i].Equals(item)) return true; return false; } /* ICollection<T>: This method is used to copy * the items of this collection to an array passed as argument. */ public void CopyTo(T[] array, int arrayIndex) { throw new NotImplementedException(); } /* IEnumerable<T>: Used for iteration */ public IEnumerator<T> GetEnumerator() { int number = 0; while (number < Count) { yield return items[number]; number++; } } /* IList<T>: This method checks whether the item * passed as argument exists in the collection. If so, it returns its index. */ public int IndexOf(T item) { for (int i = 0; i < counter; i++) if (items[i].Equals(item)) return i; return -1; } /* IList<T>: This method can be used to insert an item at a certain position inside the collection. */ public void Insert(int index, T item) { // If the index is the same as the current number of items // then call Add() and proceed as if we want to add a new item if (index >= counter) { Add(item); } // If the index is positive but less than the current size, // then you need to insert the item inside the collection. if ((index >= 0) && (index < counter)) { // First, push each item one position up to create // an empty space for (int i = (counter - 1); i > index - 1; i--) items[i + 1] = items[i]; // Then put the new item in the indicated position items[index] = item; // Since the new item has been added, increase the // current number of items counter++; } } /* ICollection<T>: This method first checks the existence of * the item passed as argument. If the item exists, the method deletes it. */ public bool Remove(T item) { // First try to get the index of the item to find out if it exists int index = IndexOf(item); // If the item was found ... if (index >= 0) { // ... delete it, using its index RemoveAt(index); // Since the item has been removed, return true return true; } // If the item was not removed (for any reason), return false return false; } /* IList<T>: This method can be used to delete the item positioned at the index passed as argument. */ public void RemoveAt(int index) { // First check that the user provided a positive index that // is lower than the current total number of items if ((index >= 0) && (index < counter)) { // If so, starting at that index, get the item ahead of // each position and assign it to the current item for (int i = index; i < counter - 1; i++) items[i] = items[i + 1]; // Since the last item is not useful anymore, // decrease the number of items counter--; } } /* IEnumerable: Used for iteration */ IEnumerator IEnumerable.GetEnumerator() { int number = 0; while (number < Count) { yield return items[number]; number++; } } } }
using System; namespace WaterDistributionCompany2 { [Serializable] public class WaterMeter { public string MeterNumber { get; set; } public string Make { get; set; } public string Model { get; set; } public string MeterSize { get; set; } public override bool Equals(object obj) { WaterMeter meter = (WaterMeter)obj; if (meter.MeterNumber == MeterNumber) return true; return false; } public override int GetHashCode() { return base.GetHashCode(); } } }
using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace WaterDistributionCompany2 { public class WaterMeters { public void Create() { FileStream fsWaterMeters = null; BinaryFormatter bfWaterMeters = new BinaryFormatter(); string strFileWaterMeters = @"C:\Water Distribution Company\WaterMeters.wdc"; // Create a list of water meters. Since we don't know whether a list of meter waters exists already, let's start with an empty one Collection<WaterMeter> waterMeters = new Collection<WaterMeter>(); Console.WriteLine("Provide the following information"); Console.WriteLine("------------------------------------------------"); Console.Write("Meter #: "); string meterNumber = Console.ReadLine(); if (meterNumber.Length == 0) { Console.Clear(); Console.WriteLine("You should enter a meter number, otherwise, the water meter account cannot be created."); Console.Write("Press any key to return to the main menu: "); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } else { Console.Write("Make: "); string make = Console.ReadLine(); Console.Write("Model: "); string model = Console.ReadLine(); Console.Write("Meter Size: "); string meterSize = Console.ReadLine(); Console.Write("Date Last Update (mm/dd/yyyy): "); DateTime dlu = DateTime.Parse(Console.ReadLine()); Console.Write("Counter Value: "); int counter = int.Parse(Console.ReadLine()); // Make sure a meter number was provided. If not, don't do nothing if (meterNumber.Length == 0) { throw new FormatException("You must enter a meter number. Otherwise, the water meter account cannot be created."); } else { WaterMeter meter = new WaterMeter() { MeterNumber = meterNumber, Make = make, Model = model, MeterSize = meterSize, DateLastUpdate = dlu, CounterValue = counter }; // If a list of water meters was previously created and saved to a file... if (File.Exists(strFileWaterMeters)) { // ... open that file ... using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open, FileAccess.Read, FileShare.Read)) { // ... get the list of water meters waterMeters = (Collection<WaterMeter>)bfWaterMeters.Deserialize(fsWaterMeters); } } // Whether the list of water meters is empty or not, add the new water meter to the list waterMeters.Add(meter); // Save the new list of water meters to a file using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Create, FileAccess.Write, FileShare.Write)) { bfWaterMeters.Serialize(fsWaterMeters, waterMeters); } Console.Clear(); } } } public void Display() { BinaryFormatter bfWaterMeters = new BinaryFormatter(); Collection<WaterMeter> waterMeters = new Collection<WaterMeter>(); string strFileWaterMeters = @"C:\Water Distribution Company\WaterMeters.wdc"; Console.Clear(); if (File.Exists(strFileWaterMeters)) { using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterMeters = (Collection<WaterMeter>)bfWaterMeters.Deserialize(fsWaterMeters); Console.WriteLine(" Meter # Make Model Meter Size Date Last Update Counter"); Console.WriteLine("-------------------------------------------------------------------------------"); foreach (WaterMeter meter in waterMeters) { Console.WriteLine("{0} {1,-22} {2,-8}{3,-13} {4,8} {5,8}", meter.MeterNumber, meter.Make, meter.Model, meter.MeterSize, meter.DateLastUpdate.ToShortDateString(), meter.CounterValue); Console.WriteLine("-------------------------------------------------------------------------------"); } } } else { Console.WriteLine("There is no water meter record to display."); } Console.Write("Press any key to return to the main menu..."); Console.ReadKey(); Console.Clear(); } public void Insert() { FileStream fsWaterMeters = null; BinaryFormatter bfWaterMeters = new BinaryFormatter(); string strFileWaterMeters = @"C:\Water Distribution Company\WaterMeters.wdc"; // Create a list of water meters. Since we don't know whether a list of meter waters exists already, let's start with an empty one Collection<WaterMeter> waterMeters = new Collection<WaterMeter>(); WaterMeter meter = new WaterMeter() { MeterNumber = "9374-9307", Make = "Fogue Shop", Model = "PG-8080", MeterSize = "3.25 Inches", DateLastUpdate = new DateTime(2012, 08, 15), CounterValue = 23937 }; if (File.Exists(strFileWaterMeters)) { using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterMeters = (Collection<WaterMeter>)bfWaterMeters.Deserialize(fsWaterMeters); } waterMeters.Insert(4, meter); using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Create, FileAccess.Write, FileShare.Write)) { bfWaterMeters.Serialize(fsWaterMeters, waterMeters); } } Display(); } public void Delete(int index) { FileStream fsWaterMeters = null; BinaryFormatter bfWaterMeters = new BinaryFormatter(); string strFileWaterMeters = @"C:\Water Distribution Company\WaterMeters.wdc"; Collection<WaterMeter> waterMeters = new Collection<WaterMeter>(); if (File.Exists(strFileWaterMeters)) { using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterMeters = (Collection<WaterMeter>)bfWaterMeters.Deserialize(fsWaterMeters); } waterMeters.RemoveAt(index); using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Create, FileAccess.Write, FileShare.Write)) { bfWaterMeters.Serialize(fsWaterMeters, waterMeters); } } Display(); } public void Delete() { FileStream fsWaterMeters = null; BinaryFormatter bfWaterMeters = new BinaryFormatter(); string strFileWaterMeters = @"C:\Water Distribution Company\WaterMeters.wdc"; // Create a list of water meters. Since we don't know whether a list of meter waters exists already, let's start with an empty one Collection<WaterMeter> waterMeters = new Collection<WaterMeter>(); if (File.Exists(strFileWaterMeters)) { using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterMeters = (Collection<WaterMeter>)bfWaterMeters.Deserialize(fsWaterMeters); } waterMeters.Remove(waterMeters[2]); using (fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Create, FileAccess.Write, FileShare.Write)) { bfWaterMeters.Serialize(fsWaterMeters, waterMeters); } } Display(); } } }
using System; namespace WaterDistributionCompany4.Models { [Serializable] public class Customer { public string AccountNumber { get; set; } public string MeterNumber { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } public string City { get; set; } public string County { get; set; } public string State { get; set; } public string ZIPCode { get; set; } public override bool Equals(object obj) { Customer client = (Customer)obj; if (client.AccountNumber == AccountNumber) return true; return false; } public override int GetHashCode() { return base.GetHashCode(); } } }
using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace WaterDistributionCompany2 { public class Customers { public void Create() { bool waterMeterFound = false; string mtrNbr = string.Empty; string acntNumber = string.Empty; BinaryFormatter bfCustomers = new BinaryFormatter(); BinaryFormatter bfWaterMeters = new BinaryFormatter(); Collection<WaterMeter> waterMeters = new Collection<WaterMeter>(); string strFileCustomers = @"C:\Water Distribution Company\Customers.cts"; string strFileWaterMeters = @"C:\Water Distribution Company\WaterMeters.wdc"; Collection<Customer> customers = new Collection<Customer>(); Console.WriteLine("Provide the following information"); Console.WriteLine("---------------------------------"); try { Console.Write("Account #: "); acntNumber = Console.ReadLine(); } catch (FormatException) { Console.WriteLine("You must enter an account number. Otherwise, the customer account cannot be created."); } if (acntNumber.Length == 0) { Console.Clear(); Console.WriteLine("You should enter an account number. Otherwise, the customer account cannot be created."); Console.Write("Press any key to return to the main menu: "); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } try { Console.Write("Meter #: "); mtrNbr = Console.ReadLine(); } catch (FormatException) { Console.WriteLine("You must enter a valid meter number for an existing water meter. Otherwise, the customer account cannot be created."); } if (mtrNbr.Length == 0) { Console.Clear(); Console.WriteLine("You should enter a water meter number. Otherwise, the customer account number is not valid."); Console.Write("Press any key to return to the main menu: "); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } if (File.Exists(strFileWaterMeters)) { using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterMeters = (Collection<WaterMeter>)bfWaterMeters.Deserialize(fsWaterMeters); foreach (WaterMeter meter in waterMeters) { if (meter.MeterNumber.Equals(mtrNbr)) { waterMeterFound = true; break; } } } } if (waterMeterFound == true) { Console.Write("First Name: "); string fName = Console.ReadLine(); Console.Write("Last Name: "); string lName = Console.ReadLine(); Console.Write("Address: "); string adrs = Console.ReadLine(); Console.Write("City: "); string city = Console.ReadLine(); Console.Write("County: "); string county = Console.ReadLine(); Console.Write("State: "); string state = Console.ReadLine(); Console.Write("ZIP-Code: "); string zip = Console.ReadLine(); Customer client = new Customer() { AccountNumber = acntNumber, MeterNumber = mtrNbr, FirstName = fName, LastName = lName, Address = adrs, City = city, County = county, State = state, ZIPCode = zip }; if (File.Exists(strFileCustomers)) { using (FileStream fsCustomers = new FileStream(strFileCustomers, FileMode.Open, FileAccess.Read, FileShare.Read)) { customers = (Collection<Customer>)bfCustomers.Deserialize(fsCustomers); } } customers.Add(client); using (FileStream fsCustomers = new FileStream(strFileCustomers, FileMode.Create, FileAccess.Write, FileShare.Write)) { bfCustomers.Serialize(fsCustomers, customers); } Console.Clear(); } else { Console.Clear(); Console.WriteLine("You must type a meter number of a water meter that exists."); Console.Write("Press any key to return to the main menu: "); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } } public void Display() { BinaryFormatter bfCustomers = new BinaryFormatter(); Collection<Customer> customers = new Collection<Customer>(); string strFileCustomers = @"C:\Water Distribution Company\Customers.wdc"; Console.Clear(); if (File.Exists(strFileCustomers)) { using (FileStream fsCustomers = new FileStream(strFileCustomers, FileMode.Open, FileAccess.Read, FileShare.Read)) { customers = (Collection<Customer>)bfCustomers.Deserialize(fsCustomers); Console.WriteLine(" Account # Meter # First Name Last Name City State"); Console.WriteLine("============================================================================"); foreach (Customer client in customers) { Console.WriteLine("{0} {1} {2,-11} {3,-11}{4,-12} {5}", client.AccountNumber, client.MeterNumber, client.FirstName, client.LastName, client.City, client.State); Console.WriteLine("----------------------------------------------------------------------------"); } } } else { Console.WriteLine("There is no customer record to display."); } Console.Write("Press any key to return to the main menu..."); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } } }
using System; namespace WaterDistributionCompany2 { [Serializable] public class WaterBill { public int InvoiceNumber { get; set; } public string AccountNumber { get; set; } public DateTime MeterReadingStartDate { get; set; } public DateTime MeterReadingEndDate { get; set; } public int NumberOfDays { get; set; } public float CounterReadingStart { get; set; } public float CounterReadingEnd { get; set; } public float TotalHCF { get; set; } public int TotalGallons { get; set; } public double First15HCF { get; set; } public double Next10HCF { get; set; } public double RemainingHCF { get; set; } public double SewerCharges { get; set; } public double StormCharges { get; set; } public double WaterUsageCharges { get; set; } public double TotalCharges { get; set; } public double CountyTaxes { get; set; } public double StateTaxes { get; set; } public DateTime PaymentDueDate { get; set; } public double AmountDue { get; set; } public DateTime LatePaymentDueDate { get; set; } public double LateAmountDue { get; set; } public override bool Equals(object obj) { WaterBill bill = (WaterBill)obj; if (bill.InvoiceNumber == InvoiceNumber) return true; return false; } public override int GetHashCode() { return base.GetHashCode(); } } }
using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace WaterDistributionCompany2 { public class WaterBills { public void Create() { int crs = 0, cre = 0; bool customerFound = false; string mtrNbr = string.Empty; DateTime mrsd = new DateTime(); Random rndNumber = new Random(); string acntNumber = string.Empty; BinaryFormatter bfCustomers = new BinaryFormatter(); BinaryFormatter bfWaterBills = new BinaryFormatter(); BinaryFormatter bfWaterMeters = new BinaryFormatter(); Collection<Customer> customers = new Collection<Customer>(); Collection<WaterBill> waterBills = new Collection<WaterBill>(); Collection<WaterMeter> waterMeters = new Collection<WaterMeter>(); string strFileCustomers = @"C:\Water Distribution Company\Customers.wdc"; string strFileWaterBills = @"C:\Water Distribution Company\WaterBills.wdc"; string strFileWaterMeters = @"C:\Water Distribution Company\WaterMeters.wdc"; int billNbr = rndNumber.Next(100001, 999999); Console.WriteLine("Provide the following information"); Console.WriteLine("---------------------------------"); Console.WriteLine("Invoice #: " + billNbr); try { Console.Write("Account #: "); acntNumber = Console.ReadLine(); } catch (FormatException) { Console.WriteLine("You must enter the account number of the customer whose bill this is, otherwise, the water bill cannot be created."); } if (acntNumber.Length == 0) { Console.Clear(); Console.WriteLine("In order to issue a water bill, you must specify a customer's account number."); Console.Write("Press any key to return to the main menu: "); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } Console.WriteLine("==========================================================="); if (File.Exists(strFileCustomers)) { using (FileStream fsCustomers = new FileStream(strFileCustomers, FileMode.Open, FileAccess.Read, FileShare.Read)) { customers = (Collection<Customer>)bfCustomers.Deserialize(fsCustomers); foreach(Customer client in customers) { if(client.AccountNumber.Equals(acntNumber)) { Console.WriteLine("Customer Information"); Console.WriteLine("Account #: " + client.AccountNumber); Console.WriteLine("Customer Name: {0} {1}", client.FirstName, client.LastName); Console.WriteLine("Address: " + client.Address); Console.WriteLine(" {0}, {1} {2} {3}", client.City, client.County, client.State, client.ZIPCode); mtrNbr = client.MeterNumber; customerFound = true; break; } } } } Console.WriteLine("---------------------------------------------------------"); if ( customerFound == true) { using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterMeters = (Collection<WaterMeter>)bfWaterMeters.Deserialize(fsWaterMeters); foreach (WaterMeter meter in waterMeters) { if (meter.MeterNumber.Equals(mtrNbr)) { Console.WriteLine("Water Meter: {0} {1} - {2}", meter.Make, meter.Model, mtrNbr); mrsd = meter.DateLastUpdate; crs = meter.CounterValue; break; } } } Console.WriteLine("==========================================================="); double next10HCF = 0.00; double first15HCF = 0.00; double remainingHCF = 0.00; Console.Write("Meter Reading End Date (mm/dd/yyyy): "); DateTime mred = DateTime.Parse(Console.ReadLine()); if (File.Exists(strFileWaterBills)) { using (FileStream fsWaterBills = new FileStream(strFileWaterBills, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterBills = (Collection<WaterBill>)bfWaterBills.Deserialize(fsWaterBills); foreach(WaterBill wb in waterBills) { if(wb.AccountNumber == acntNumber) { mrsd = wb.MeterReadingEndDate; crs = wb.CounterReadingEnd; } } } } Console.Write("Counter Reading End: "); cre = int.Parse(Console.ReadLine()); TimeSpan tsDays = new TimeSpan(); tsDays = mred - mrsd; double totalHCF = cre - crs; int totalGallons = (int)(totalHCF * 748.05); if (totalHCF <= 15) { first15HCF = totalHCF * 3.612; next10HCF = 0; remainingHCF = 0; } else if (totalHCF <= 25.00) { first15HCF = 15.00 * 3.612; next10HCF = (totalHCF - 15.00) * 3.918; remainingHCF = 0.00; } else { first15HCF = 15 * 3.612; next10HCF = 10 * 3.918; remainingHCF = (totalHCF - 25) * 2.2763; } double waterUsageCharges = first15HCF + next10HCF + remainingHCF; double sewerCharges = waterUsageCharges * 0.252; double stormCharges = waterUsageCharges * 0.0025; double totalCharges = waterUsageCharges + sewerCharges + stormCharges; double localTaxes = totalCharges * 0.005; double stateTaxes = totalCharges * 0.0152; double amountDue = totalCharges + localTaxes + stateTaxes; WaterBill bill = new WaterBill() { InvoiceNumber = rndNumber.Next(100001, 999999), AccountNumber = acntNumber, MeterReadingStartDate = mrsd, MeterReadingEndDate = mred, NumberOfDays = tsDays.Days, CounterReadingStart = crs, CounterReadingEnd = cre, TotalHCF = totalHCF, TotalGallons = totalGallons, First15HCF = first15HCF, Next10HCF = next10HCF, RemainingHCF = remainingHCF, SewerCharges = sewerCharges, StormCharges = stormCharges, WaterUsageCharges = waterUsageCharges, TotalCharges = totalCharges, LocalTaxes = localTaxes, StateTaxes = stateTaxes, AmountDue = amountDue, PaymentDueDate = mred.AddDays(28), LatePaymentDueDate = mred.AddDays(45), LateAmountDue = amountDue + 8.95 }; Console.Clear(); Console.WriteLine("==============================================="); Console.WriteLine("Water Bill Summary"); Console.WriteLine("-----------------------------------------------"); Console.WriteLine("Invoice #: {0}", billNbr); Console.WriteLine("Account #: {0}", acntNumber); Console.WriteLine("Meter Reading Start Date: {0}", mrsd.ToShortDateString()); Console.WriteLine("Meter Reading End Date: {0}", mred.ToShortDateString()); Console.WriteLine("Number of Days: {0}", tsDays.Days); Console.WriteLine("Counter Reading Start: {0}", bill.CounterReadingStart); Console.WriteLine("Counter Reading End: {0}", bill.CounterReadingEnd); Console.WriteLine("Total HCF: {0}", bill.TotalHCF); Console.WriteLine("Total Gallons: {0}", bill.TotalGallons); Console.WriteLine("First 15 HCF: {0}", bill.First15HCF.ToString("F")); Console.WriteLine("Next 10 HCF: {0}", bill.Next10HCF.ToString("F")); Console.WriteLine("Remaining HCF: {0}", bill.RemainingHCF.ToString("F")); Console.WriteLine("Sewer Charges: {0}", bill.SewerCharges.ToString("F")); Console.WriteLine("Storm Charges: {0}", bill.StormCharges.ToString("F")); Console.WriteLine("Water Usage Charges: {0}", bill.WaterUsageCharges.ToString("F")); Console.WriteLine("Total Charges: {0}", bill.TotalCharges.ToString("F")); Console.WriteLine("Local Taxes: {0}", bill.LocalTaxes.ToString("F")); Console.WriteLine("State Taxes: {0}", bill.StateTaxes.ToString("F")); Console.WriteLine("Amount Due: {0}", bill.AmountDue.ToString("F")); Console.WriteLine("Payment Due Date: {0}", bill.PaymentDueDate.ToShortDateString()); Console.WriteLine("Late Payment Due Date: {0}", bill.LatePaymentDueDate.ToShortDateString()); Console.WriteLine("Late Amount Due: {0}", bill.LateAmountDue.ToString("F")); Console.WriteLine("Payment Date: {0}", bill.PaymentDate.ToShortDateString()); Console.WriteLine("Amount Paid: {0}", bill.AmountPaid.ToString("F")); Console.WriteLine("==============================================="); waterBills.Add(bill); Console.Write("Do you want to save the water bill (y/n)? "); string answer = Console.ReadLine(); if (answer.ToLower().Equals("y")) { using (FileStream fsWaterBills = new FileStream(strFileWaterBills, FileMode.Create, FileAccess.Write, FileShare.Write)) { bfWaterBills.Serialize(fsWaterBills, waterBills); } } Console.Clear(); } else { Console.Clear(); Console.WriteLine("You must type an account number of a customer that exists."); Console.Write("Press any key to return to the main menu: "); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } } public void Display() { BinaryFormatter bfWaterBills = new BinaryFormatter(); Collection<WaterBill> waterBills = new Collection<WaterBill>(); string strFileWaterBills = @"C:\Water Distribution Company\WaterBills.wdc"; Console.Clear(); if (File.Exists(strFileWaterBills)) { using (FileStream fsWaterBills = new FileStream(strFileWaterBills, FileMode.Open, FileAccess.Read, FileShare.Read)) { waterBills = (Collection<WaterBill>)bfWaterBills.Deserialize(fsWaterBills); Console.WriteLine("Invoice # Account # Total Gallons Amount Due Pmt Due Date"); Console.WriteLine("======================================================================"); foreach (WaterBill bill in waterBills) { Console.WriteLine("{0} {1} {2,-11} {3,-11} {4,-12}", bill.InvoiceNumber, bill.AccountNumber, bill.TotalGallons, bill.AmountDue.ToString("F"), bill.PaymentDueDate.ToShortDateString()); Console.WriteLine("----------------------------------------------------------------------"); } } } else { Console.WriteLine("There is no water bill to display."); } Console.Write("Press any key to return to the main menu..."); Console.ReadKey(); Console.Clear(); BusinessManagement.ProcessApplication(); } } }
using System.IO; using static System.Console; namespace WaterDistributionCompany2 { public class BusinessManagement { public static string ShowMainMenu() { WriteLine("Water Distribution Company"); WriteLine("============================="); WriteLine("Main Menu"); WriteLine("-----------------------------"); WriteLine(" 1 - Water Meters"); WriteLine(" 2 - Customers"); WriteLine(" 3 - Water Bills"); WriteLine(" 0 - Exit the Application"); Write("Enter your selection: "); string menu = ReadLine(); Clear(); if ((menu == "1") || (menu == "2") || (menu == "3")) return menu; else { WriteLine("====================================="); System.Environment.Exit(0); return "0"; } } public static void ProcessApplication() { int counter = 0; // Display the main menu of this application string menu = ShowMainMenu(); Clear(); do { switch (menu) { case "1": WaterMeters wms = new WaterMeters(); WriteLine("Water Distribution Company"); WriteLine("============================="); WriteLine("Water Meter Menu"); WriteLine("-----------------------------"); WriteLine(" 1 - Create New Water Meter"); WriteLine(" 2 - Display Water Meters"); WriteLine(" 0 - Return to the Main Menu"); Write("Enter your selection: "); string wmMenu = ReadLine(); Clear(); if (wmMenu == "1") wms.Create(); else if (wmMenu == "2") wms.Display(); else menu = ShowMainMenu(); break; case "2": Customers clients = new Customers(); WriteLine("Water Distribution Company"); WriteLine("============================="); WriteLine("Customer Menu"); WriteLine("-----------------------------"); WriteLine(" 1 - Create New Customer Account"); WriteLine(" 2 - Display Customers"); WriteLine(" 0 - Return to the Main Menu"); Write("Enter your selection: "); string custMenu = ReadLine(); Clear(); if (custMenu == "1") clients.Create(); else if (custMenu == "2") clients.Display(); else menu = ShowMainMenu(); break; case "3": WaterBills waterBills = new WaterBills(); WriteLine("Water Distribution Company"); WriteLine("============================="); WriteLine("Water Bill Menu"); WriteLine("-----------------------------"); WriteLine(" 1 - Prepare New Water Bill"); WriteLine(" 2 - Display Water Bills"); WriteLine(" 0 - Return to the Main Menu"); Write("Enter your selection: "); string wbMenu = ReadLine(); Clear(); if (wbMenu == "1") waterBills.Create(); else if (wbMenu == "2") waterBills.Display(); else menu = ShowMainMenu(); break; default: menu = ShowMainMenu(); break; } counter++; } while (counter <= 100); } public static int Main(string[] args) { /* If there ain't no Water Distribution Company folder on the C:\ drive, create it. * If that folder exists already, don't do nothing. */ Directory.CreateDirectory(@"C:\Water Distribution Company"); ProcessApplication(); WriteLine("====================================="); return 0; } } }
Water Distribution Company ============================= Main Menu ----------------------------- 1 - Water Meters 2 - Customers 3 - Water Bills 0 - Exit the Application Enter your selection:
Water Distribution Company ============================= Water Meter Menu ----------------------------- 1 - Create New Water Meter 2 - Display Water Meters 0 - Return to the Main Menu Enter your selection:
Provide the following information ------------------------------------------------ Meter #:
Provide the following information ------------------------------------------------ Meter #: 392-44-572 Make: Constance Technologies Model: TG-4822 Meter Size: 5/8 Inches Date Last Update (mm/dd/yyyy): 03/31/2018 Counter Value: 109992
Meter # | Make | Model | Meter Size | Date Last Update | Counter Value |
938-75-869 | Standard Trend | 266G | 1 1/2 Inches | 10/22/2017 | 137926 |
799-28-461 | Constance Technologies | BD-7000 | 3/4 Inches | 05/05/2018 | 6268 |
207-94-835 | Constance Technologies | TG-6220 | 5/8 Inches | 2/17/2018 | 96 |
592-84-957 | Standard Trend | 428T | 3/4 Inches | 12/7/2017 | 49 |
Water Distribution Company ============================= Water Meter Menu ----------------------------- 1 - Create New Water Meter 2 - Display Water Meters 0 - Return to the Main Menu Enter your selection:
Meter # Make Model Meter Size Date Last Update Counter ------------------------------------------------------------------------------- 392-44-572 Constance Technologies TG-4822 5/8 Inches 3/31/2018 109992 ------------------------------------------------------------------------------- 938-75-869 Standard Trend 266G 1 1/2 Inches 10/22/2017 137926 ------------------------------------------------------------------------------- 799-28-461 Constance Technologies BD-7000 3/4 Inches 5/5/2018 6268 ------------------------------------------------------------------------------- 207-94-835 Constance Technologies TG-6220 5/8 Inches 2/17/2018 96 ------------------------------------------------------------------------------- 592-84-957 Standard Trend 428T 3/4 Inches 12/7/2017 49 ------------------------------------------------------------------------------- Press any key to return to the main menu...
Water Distribution Company ============================= Main Menu ----------------------------- 1 - Water Meters 2 - Customers 3 - Water Bills 0 - Exit the Application Enter your selection:
Water Distribution Company ============================= Customer Menu ----------------------------- 1 - Create New Customer Account 2 - Display Customers 0 - Return to the Main Menu Enter your selection:
Provide the following information --------------------------------- Account #:
Provide the following information --------------------------------- Account #: 9279-570-8394 Meter #: 799-28-461 First Name: Thomas Last Name: Stones Address: 10252 Broward Ave #D4 City: Frederick County: Frederick State: MD ZIP-Code: 32703
Account # | Meter # | First Name | Last Name | Address | City | County | State | ZIP Code |
4820-375-2842 | 392-44-572 | Akhil | Koumari | 748 Red Hills Rd | Roanoke | VA | 24012 | |
7518-302-6895 | 207-94-835 | Grace | Brenner | 4299 Peachtree Court | Rockville | Montgomery | MD | 20853 |
2038-413-9680 | 938-75-869 | Amidou | Gomah | 2075 Rose Hills Ave | Washington | DC | 20004 | |
5938-074-5293 | 592-84-957 | Marie | Rath | 582G Dunhill Ave | Lanham | Prince George | MD | 20706 |
Account # Meter # First Name Last Name City State ============================================================================ 9279-570-8394 799-28-461 Thomas Stones Frederick MD ---------------------------------------------------------------------------- 4820-375-2842 392-44-572 Akhil Koumari Roanoke VA ---------------------------------------------------------------------------- 7518-302-6895 207-94-835 Grace Brenner Rockville MD ---------------------------------------------------------------------------- 2038-413-9680 938-75-869 Amidou Gomah Washington DC ---------------------------------------------------------------------------- 5938-074-5293 592-84-957 Marie Rath Lanham MD ---------------------------------------------------------------------------- Press any key to return to the main menu...
Water Distribution Company ============================= Water Bill Menu ----------------------------- 1 - Prepare New Water Bill 2 - Display Water Bills 0 - Return to the Main Menu Enter your selection:
Provide the following information --------------------------------- Invoice #: 594357 Account #:
Provide the following information --------------------------------- Invoice #: 594357 Account #: 7518-302-6895 =========================================================== Customer Information Account #: 7518-302-6895 Customer Name: Grace Brenner Address: 4299 Peachtree Court Rockville, Montgomery MD 20853 --------------------------------------------------------- Water Meter: Constance Technologies TG-6220 - 207-94-835 =========================================================== Meter Reading End Date (mm/dd/yyyy):
Provide the following information --------------------------------- Invoice #: 594357 Account #: 7518-302-6895 =========================================================== Customer Information Account #: 7518-302-6895 Customer Name: Grace Brenner Address: 4299 Peachtree Court Rockville, Montgomery MD 20853 --------------------------------------------------------- Water Meter: Constance Technologies TG-6220 - 207-94-835 =========================================================== Meter Reading End Date (mm/dd/yyyy): 07/30/2018 Counter Reading End: 114
=============================================== Water Bill Summary ----------------------------------------------- Invoice #: 594357 Account #: 7518-302-6895 Meter Reading Start Date: 2/17/2018 Meter Reading End Date: 7/30/2018 Number of Days: 163 Counter Reading Start: 96 Counter Reading End: 114 Total HCF: 18 Total Gallons: 13464 First 15 HCF: 54.18 Next 10 HCF: 11.75 Remaining HCF: 0.00 Sewer Charges: 16.62 Storm Charges: 0.16 Water Usage Charges: 65.93 Total Charges: 82.71 Local Taxes: 0.41 State Taxes: 1.26 Amount Due: 84.39 Payment Due Date: 8/27/2018 Late Payment Due Date: 9/13/2018 Late Amount Due: 93.34 Payment Date: 1/1/0001 Amount Paid: 0.00 =============================================== Do you want to save the water bill (y/n)?
Account # | Meter Reading End Date | Counter Reading End |
4820-375-2842 | 07/31/2018 | 109998 |
2038-413-9680 | 07/30/2018 | 137975 |
9279-570-8394 | 08/07/2018 | 6275 |
7518-302-6895 | 11/07/2018 | 118 |
2038-413-9680 | 10/27/2018 | 138012 |
|
||
Previous | Copyright © 2008-2019, FunctionX | Next |
|