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);
}
}
Darius Zakrzewski currently lives in Australia. He founded the Melbourne Patterns Group in 1999 and moderated it until the end of 2001. In 2000 he was a co-founder and conference chair of the Australian patterns conference series, KoalaPLoP. His interests include C++, C#, .NET, SQL, patterns, design, and Generative Programming. He can be reached at DariusZ at pobox dot com.