Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / C#
Article

Strongly Typed Guid Classes

Rate me:
Please Sign up or sign in to vote.
4.00/5 (13 votes)
22 Mar 20042 min read 44.9K   496   14   1
Create strongly typed Guid classes by deriving (essentially) empty subclasses from a TypedGuid base class.

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.

C#
public class Database
{
    static public Vendor LoadVendor(Guid guid)
    {
        // Only relevant parts shown.
    }
}

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...

C#
public class OrderData
{
    // Only relevant parts shown.
    public Guid TimeID    { get { return m_timeID; } }
    public Guid ProductID { get { return m_productID; } }
    public Guid VendorID  { get { return m_vendorID; } }
}

public class Order
{
   // Only relevant parts shown.
    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.

C#
[Serializable]
public class VendorGuid : TypedGuid
{
    public VendorGuid(Guid g) : base(g)
    {
        // Empty body.
    }
}

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:

C#
public class Database
{
    static public Vendor LoadVendor(VendorGuid vendorGuid)
    {
        // Only relevant parts shown.
    }
}

public class OrderData
{
    // Only relevant parts shown.
    public TimeGuid    TimeID    { get { return m_timeID; } }
    public ProductGuid ProductID { get { return m_productID; } }
    public VendorGuid  VendorID  { get { return m_vendorID; } }
}

public class Order
{
   // Only relevant parts shown.
    private OrderData m_orderData;

    public Vendor GetVendor()
    {
        ProductGuid guid = m_orderData.ProductID;
        return Database.LoadVendor(guid); // compiler will not allow this
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
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.

Comments and Discussions

 
GeneralGenerics :-) Pin
Uwe Keim24-Mar-04 0:04
sitebuilderUwe Keim24-Mar-04 0:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.