Generic constraints for value types

I came across an oddity in the C# language the other day. I was trying to create a generic method that returned a nullable value. A simple example of this:

   1: public T? GetNullable<T>(int index)
   2: {
   3:   if(index < 0)
   4:       return null;
   5:  
   6:   return default(T);
   7: }

 

This will result in a compiler error:

Error 1 The type ‘T’ must be a non-nullable value type in order to use it as parameter ‘T’ in the generic type or method ‘System.Nullable<T>’

This is a cryptic error that means that I need to put a constraint on my method to restrict it to a value type. In C#, this is done with the ‘struct’ keyword:

   1: public T? GetNullable<T>(int index) where T : struct

This seems really odd to me. If someone were to read the interface for this class, it is not at all clear that I can send an int, bool double, etc into this method.

It turns out that T? and System.Nullable<T> compile into the same IL and the interface for System.Nullable<T> also has a constraint on ‘struct’. So, as odd as it is, we need to consider the ‘struct’ constraint to really mean any value type.

Just a little bit later, I created a utility method to convert a string to an enum. The code is really straight forward:

   1: public T GetEnum<T>(string enumValue)
   2: {
   3:    return (T)Enum.Parse(typeof (T), enumValue);
   4: }

Because this method is only designed to be used for enums, it would be great if I could add an enum constraint:

   1: public T GetEnum<T>(string enumValue) where T : enum

This, unfortunately, is not valid. C# does, however, allow you to put a constraint with a base class. Since all enums are derived from System.Enum, I thought I could restrict using System.Enum:

   1: public T GetEnum<T>(string enumValue) where T : System.Enum

Again, no dice. System.Enum is considered a "special class" and cannot be used as a constraint. So, again, I am stuck using the ‘struct’ constraint and again, I am left feeling like this is not quite right. With this constraint, it would be perfectly acceptable to to write the following:

   1: GetEnum<int>("4");

Woof. I guess the only thing I can do now, is to add the following parameter check:

   1: if(!typeof(T).IsEnum)
   2:    throw new ArgumentException("Type T Must be an Enum");

This is the best I can do, thought it is far from ideal. It gives me a runtime check, at least, even though I can’t get a compile-time check.

It leaves me hoping that in C# 4.0, that we see some significant changes to generic constraints. It would be nice if we could at least have an Enum construct. In addition, it would be nice to use the ‘value’ keyword in constraints instead of ‘struct’. It will only improve readability.

One Response to “Generic constraints for value types”

  1. Fabio Milheiro says:

    Thanks mate! Struct!

Leave a Reply