
Introduction
This article outlines a simple programming tip to create strongly typed Guid
classes with little effort. Code that uses typed Guids becomes more readable and improves compile time type
safety for Guid instances.
Intent
Define a class to allow .NET Guids to be easily associated with a type.
Motivation
The abstraction of a unique object identifier is often realized by employing the .NET
Guid structure. Each object becomes associated with a Guid and can
then be uniquely identified. A typical example is the storage of objects into relational
database tables, where the object's Guid represents the table's primary key. C# or
VB.NET application code can use this Guid structure to represent references to
objects.
public class Database
{
static public Vendor LoadVendor(Guid guid)
{
}
}
But there are some issues with this approach. The Guid structure is domain or
type oblivious, it can represent any kind of object! A method expressed in terms of a
Guid structure will provide little information to the reader or to the compiler on
the type of object being represented. The opportunity to write expressive code or to detect
errors at compile time is lost...
public class OrderData
{
public Guid TimeID { get { return m_timeID; } }
public Guid ProductID { get { return m_productID; } }
public Guid VendorID { get { return m_vendorID; } }
}
public class Order
{
private OrderData m_orderData;
public Vendor GetVendor()
{
Guid guid = m_orderData.ProductID;
return Database.LoadVendor(guid);
}
}
If we could use a kind of "typed Guid" to represent domain concepts - for
example VendorGuid or ProductGuid - then we would be able to profit
from the benefits of understandable and compile time safe code.
Solution
Class-ify the Guid structure into a class to allow subclassing. The class-ified
base class implements all Guid functionality while subclasses provide the
association with domain types. The association is implied through the type of the subclass.
Structure
The TypedGuid class represents the class-ified Guid structure. It
wraps a Guid instance and replicates most public methods available on the .NET
Guid structure. It is an abstract base class, as creating instances of it would
defeat its purpose. It provides a protected constructor that takes a Guid
argument.
Strongly typed Guid classes are created by deriving subclasses from the
TypedGuid class. The subclass constructor takes a single Guid argument
and calls the base class constructor. In most cases the subclasses can be almost empty.
[Serializable]
public class VendorGuid : TypedGuid
{
public VendorGuid(Guid g) : base(g)
{
}
}
The type of the subclass encapsulates the association with the domain type and can be used to
detect errors at compile time.
Consequences
The TypeGuid class yields the following advantages and disadvantages:
- The
TypedGuid is a reference type whereas the Guid structure is a
value type. The advantages that come with value types are lost on the TypedGuid.
TypedGuid is a first-class object and can be extended like any other object.
- It is easy to add new
TypedGuid instances to the system. In most cases it is
sufficient to derive almost empty subclasses.
TypedGuid champions the CLR's aim of type safety.
Sample Code
The previous code re-expressed in terms of strongly typed Guid classes:
public class Database
{
static public Vendor LoadVendor(VendorGuid vendorGuid)
{
}
}
public class OrderData
{
public TimeGuid TimeID { get { return m_timeID; } }
public ProductGuid ProductID { get { return m_productID; } }
public VendorGuid VendorID { get { return m_vendorID; } }
}
public class Order
{
private OrderData m_orderData;
public Vendor GetVendor()
{
ProductGuid guid = m_orderData.ProductID;
return Database.LoadVendor(guid); }
}