What are the properties of enumerations we want to be able
to replicate?
·
Strongly typed access
·
Unchanging at runtime
·
Name and value pairing
·
Customizable values
·
Conversion to integers
·
Get by value
·
Get by name
·
List all
So in order to replace our enumeration we are going to need
to include these. Since we are using objects, the first one should be easily
done. Our object will need to have at least two properties for the Name and the
Value. So if we were just going to create a regular object we would have
something like this.
Listing 3: Normal Object
public class MyObject
{
public int Id { get; set; }
public string Name { get; set; }
}
With this object we could create instances of it at runtime,
but this is not what we want yet. The next step is making sure that we have a
set of instances to start with and no more can be created. To do this we will
make out constructor private. With the constructor private, we will need to
declare the instances of this object inside the class, so the instances will
need to be static. We will need to make sure that all of the values can be
passed into the constructor so the instances can be created easily as static
properties of the class This has the nice effect of allowing us to access them
using ClassName.InstanceName. That naming convention
will look similar to the one for enumerations which is Enumname.InstanceName.
Our new code which uses static instances and a private
constructor looks like this.
Listing 4: Static Instances and Private Constructor
public class MyObject
{
public static MyObject MyObjectOne = new MyObject(1, "MyObjectOne");
public static MyObject MyObjectTwo = new MyObject(2, "MyObjectTwo");
public static MyObject MyObjectThree = new MyObject(3, "MyObjectThree");
public int Id { get; private set; }
public string Name { get; private set; }
private MyObject(int id, string name)
{
Id = id;
Name = name;
}
}
This object will already do a lot of what we need. It
maintains a limited set, is strongly typed, has a name, has a value, you have
control over the values for each, and the Id property lets you have it as an
integer. Now we need to be able to get these based on the Id and the Name, and
we also need to maintain a list of them.
Listing all of the values is useful for displaying them in
different places such as a DropDownList or something similar.
Listing 5: Listing All of the Instances
public static List<MyObject> ListAll()
{
return new List<MyObject>
{
MyObjectOne,
MyObjectTwo,
MyObjectThree
};
}
For this it is pretty easy to just put them in a list like
this or something similar. Not too difficult to maintain, it gives you good
control of what is in the list.
Getting the instance of the object by Id and by Name is also
pretty easy. With very little effort we are able to get them, and we throw some
exceptions if we receive invalid method arguments.
Listing 6: FromId and FromName
public static MyObject FromId(int id)
{
List<MyObject> items = ListAll();
MyObject match = Array.Find(items.ToArray(), instance => instance.Id == id);
if (match == null)
{
throw new ArgumentOutOfRangeException(string.Format(
"Id '{0}' is invalid for {1}", id, typeof(MyObject).Name));
}
return match;
}
public static MyObject FromName(string name)
{
List<MyObject> items = ListAll();
MyObject match = Array.Find(items.ToArray(), instance => instance.Name == name);
if (match == null)
{
throw new ArgumentOutOfRangeException(string.Format(
"Name '{0}' is not a valid {1}", name, typeof(MyObject).Name));
}
return match;
}
At this point our object does pretty much everything we want
it to do. This class is fairly testable, and is designed in such a way that we
can add extra information to it. We can also add extra properties for any
attributes we want like descriptions.