Welcome to my tutorial on Creating a Strongly Typed Collection C#. In this tutorial we will be looking at creating your own
type safe collection. Lets say you want to create a collection of IP addresses, one that accepts only the type of IPAddress, to do this you need to create a class that inherits from
CollectionBase Class.
This class gives you all the functionality you need for your strongly typed collection. Before we get to that collection, we need to define an IPAddress collection that you strongly types collection will accept. In this collection we will implement the
IComparable Interface. Here is the
official definition of IComparable:
"
Defines a generalized comparison method that a value type or class implements to create a type-specific comparison method."
The IComparable Interface has but a single method,
CompareTo.
CompareTo gives us the ability, before adding anything to our strongly typed collection, to check the object being added and ensure its of the right type, if it isn't the compiler will generate a compile time error, rather than a run-time error. Catching mistakes like that at compile-time means our application isn't going to die if someone tries to add an object to our collection that it isn't mean to hold.
So now we will create our IPAddress Type for our collection. The first thing we need to add to our class, as always, is a reference to the Namespace's we will be using. We will need a reference to the
System Namespace and the
System.Collections Namespace. The
System Namespace gives us access to the
IComparable Interface, while the
System.Collections Namespace gives us access to the
CollectionBase Class. So now our Namespace's:
CODE
using System;
using System.Collections;
To make referencing our strongly typed collection easier, I suggest adding a Namespace to your class, as I have done here
CODE
namespace PC
{
}
I chose PC simply because I am
Psycho
Coder, you can have whatever Namespace you wish to have. Since we implement an Interface in this class our signature will look somewhat different. The signature for our IPAddress class will look like this:
CODE
public class IPAddress : IComparable
{
}
Next we need our global variables, which will be tied to ths public properties of the class. Since this is a simple class, used for the IPAddress type, we only have 2 variables, one for the ip itself and one for the host name:
CODE
private string _address;
private string _host;
Next we will declare our public properties, these will be accessible from outside our class because we declare them as
public. Properties are natural extensions of data fields and they allow us to control access to the classes members. A read/write property, which we use in our class, consists of 2 parts:
- get: Used to return the value of this data field once it has been written to
- set: Used to write a value to this data field
A read only property only has 1 part, the
get part, since it cannot be written to from outside the class its contained in. Our properties are read/write, one for the ip address itself, the other for the host name:
CODE
#region Properties
/// <summary>
/// Property to hold the IP address
/// </summary>
public string Address
{
//return the value of the property
get { return _address; }
//set the value of the property
set { _address = value; }
}
/// <summary>
/// property to hold the host name
/// </summary>
public string Host
{
//return the value of the property
get { return_host; }
//set the value of the property
set { _host = value; }
}
#endregion
NOTE: I always place areas of my classes in #region ... #endregion sections for ease of finding items when searching through my classes.Next, if we want to be to access our class (initialize) from outside the class itself, we need
Constructors. Constructors are the code that is executed once the object is initialized. In this class we have 2 constructors, the first one is a base constructor that sets our 2 variables, thus our properties, to an empty string. The second constructor utilizes overloading, which means we can have a different set parameters in each constructor. Here are our constructors:
CODE
#region Constructors
public IPAddress()
{
_address = string.Empty;
_host = string.Empty;
}
public IPAddress(string address,string host)
{
_address = address;
_host = host;
}
#endregion
When we implement from
IComparable you have to have a
CompareTo method, which happens to be the only method of the
IComparable Interface. The
CompareTo Method is what allows us to compare each object before it is added to our strongly typed collection. It allows us to ensure the type being added is of the PAddress type. When using
CompareTo 3 possible values are returned
When using
CompareTo we always want a return value of 0 (zero), which means we are adding the proper type to our collection. Here is our
CompareTo method:
CODE
#region IComparable Members
public int CompareTo(object obj)
{
//check to see if the type being passed is
//of the IPAddress type
if (!(obj is IPAddress))
{
//since its not we need to throw
//an ArgumentException
throw new ArgumentException("Object provided is of the wrong type");
}
//convert the object being passed to the type IPAddress
IPAddress addr = (IPAddress)obj;
//execute CompareTo and set its return
//value to our int variable
int cmpl = this.Address.CompareTo(addr.Address);
//check the value of the CompareTo method
if (!(cmpl == 0))
{
//not equal to zero, meaning it isnt the
//right object
return cmpl;
}
return this.Address.CompareTo(addr.Address);
}
Thats the end of our "type" collection. Now that we have finished our type, we need to create our strongly typed collection. In this collection we inherit from the
CollectionBase Class, which gives us more functionality than your average collection.
CollectionBase implements the
IList Interface, which gives us access to methods such as
- Add: Add an item to the current collection
- Contains: Used to check if the collection contains the current element before adding it
- Remove: Remove a specified item from a strongly typed collection
- Insert: Insert an item into the collection at the specified index
CollectionBase gives us access to methods such as:
- CopyTo: Copy an entire collection to a one-dimensional array at the specified index
- RemoveAt: Remove an item from the collection at the specified index
.
First, since we inherit from
CollectionBase we need to specify that in our signature:
CODE
public class AddressList : CollectionBase
{
}
For this collection class we need a
Constructor as well, but the constructor for this class will be empty, it's just there to allow us to initialize our collection:
CODE
#region Constructors
public AddressList()
{
}
#endregion
Next, instead of properties in this class, like the class that defines our type, we use an
Indexer. As the definition states,
Indexers allow us to index a class in the same way an Array is indexed. The only difference between a property and an indexer is an indexer accepts parameters. Our indexer looks like this:
CODE
#region Indexer
/// <summary>
/// Indexer for our collection
/// </summary>
/// <param name="idx">Index of the collection</param>
/// <returns>IPAddress at that index</returns>
public IPAddress this[int idx]
{
get
{
//returns the IPAddress at the specified index
return (IPAddress)this.InnerList[idx];
}
}
Now we get to the CollectionBase/IList Methods. In order to add things to our strongly typed collection we need an
Add Method. This method is a single line of code, and it simply adds the item to the collection in the next available index:
CODE
#region Add
/// <summary>
/// Method for adding an IPAddress to the list
/// </summary>
/// <param name="addr">IPAddress to add</param>
public void Add(IPAddress addr)
{
//add this item to the list
this.InnerList.Add(addr);
}
#endregion
Since this is a strongly typed collection, we don't want to allow duplicate entries. Since we're inheriting from
CollectionBase this offers us the functionality to search our collection, and having duplicate entries can cause some unwanted results, so we add a
Contains method which checks the items of our collection to see if what we're wanting to add already exists in the collection. In this method, we enumerate through each item in the collection, checking if the address/host name combination being added exists anywhere in our collection, if it does we return true, otherwise we return false:
CODE
#region Contains
/// <summary>
/// Method to check and see if the
/// items is in the list
/// </summary>
/// <param name="addr">Item to check</param>
/// <returns>true/false</returns>
public bool Contains(IPAddress addr)
{
//loop through all the items in the list
foreach (IPAddress item in this.InnerList)
{
//check to see if its in the list
//returning 0 means its in the list
if (item.CompareTo(addr) == 0)
{
//return true
return true;
}
}
//not in the list return false
return false;
}
#endregion
Now lets say you want to remove an item from your strongly typed collection. inheriting from
CollectionBase, which implementes the
IList Interface, gives us access to the IList's Remove Method, so we take advantage of that:
CODE
#region Remove
/// <summary>
/// Method for removing a specified IPAddress fromthe list
/// </summary>
/// <param name="ip">IPAddress to remove</param>
public void Remove(IPAddress ip)
{
//check to see if the list contains this
//item, if it doesnt exit the procedure
if (!this.Contains(ip)) return;
//declare a counter variable
int i;
//loop through all the items in the list
for (i = 0; i <= this.InnerList.Count; i++)
{
//create an instance of the IPAddress
IPAddress item = (IPAddress)this.InnerList[i];
//now check to see if its in the list
if ((item.CompareTo(ip) == 0))
{
//if its in the list remove it
this.RemoveAt(i);
return;
}
}
}
#endregion
One method that's accessible when inheriting from CollectionBase, and is almost always overlooked is the
OnValidate Method. This method is very important when creating a strongly typed collection. CollectionBase, as stated before, implements the
IList Interface, which means that a user can cast your object to an
IList object then call any of the methods in the
IList Interface. This gives the user the opportunity to insert incorrect types into your collection. This method should throw an
ArgumentException if the type being passed isn't of the type we're expecting:
CODE
#region OnValidate
protected override void OnValidate(object value)
{
//first validate the object
base.OnValidate(value);
//if the object isnt of the correct type
//throw an ArgumentException
if (!(value is IPAddress))
{
throw new ArgumentException("Collection only supports items of type IPAddress");
}
}
#endregion
There is of course much more than can be accomplished when inheriting from
IComparable and
CollectionBase, but I touched on the most commonly used methods, the ones that you will use continually in your strongly typed collections. Inheriting from base classes and implementing base interfaces available to you in the .Net Framework will make you a much more powerful programmer in the long run, and give you a far better understanding of the power this framework contains, and of Object Oriented Programming.
I am including for download, the class that I created for writing this tutorial. Remember, since the code is under the
GNU - General Public License you may modify, use and distribute as you see fit, but the license header must stay intact. That is the end of this tutorial on Creating a Strongly Typed Collection in C#. I hope you found this tutorial useful and informative. Thanks for reading.
Happy Coding

IPAddress.zip ( 2.03k )
Number of downloads: 199