SYSK 267: How to bypass YourGenericClass where T : ValueType constraint restriction

Problem statement: create a general purpose status history class that is a collection of status history items sorted by time stamp. Each status history item must include a status code, updated-by-user string and updated-on time stamp. Important: the status codes must be limited by an enumerated data type, and may vary based on usage; i.e. you might have status codes like Saved, Submitted, Approved, etc. on a RequestStatus enumerated data type, and a totally different set of status codes for a LoanProcessingStatus type.

 

If your goal is to write as little code as you can get away with, and yet, make it easy to understand and strongly typed, you might attempt to do something like this:

 

[DataContract]

public enum YourStatusType : short

{

    [EnumMember] Unknown = 0,

    [EnumMember] Saved = 1,

    [EnumMember] Submitted = 2,

    [EnumMember] Approved = 3,

    [EnumMember] Declined = 4,

}

[DataContract]

public class StatusHistoryItem<T>

{

    [DataMember]

    public T Status;

    [DataMember]

    public string UpdatedBy;

    [DataMember]

    public DateTime UpdatedOn;

}

[DataContract]

public class StatusHistory<T> : SortedDictionary<DateTime, StatusHistoryItem<T>> where T : enum

{

   

}

 

 

and try to use it as:

 

StatusHistory<YourStatusType> statusHistory =

      new StatusHistory<YourStatusType>();

 

. . .

 

The problem is that the bolded code in StatusHistory class will not compile! You will get a “Type expected” error followed by “Identifier expected” error.

 

 

Ok, you might say… I know all my status codes are of type ‘short’… So, I’ll use it as a constraint! So, you change your StatusHistory class definition to be:

 

[DataContract]

public class StatusHistory<T> : SortedDictionary<DateTime, StatusHistoryItem<T>> where T : short

{

 

}

Unfortunately, this won’t work either -- 'short' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.

 

The best work around solution I’ve come up with is to do the type checking at run time… Yes, I agree – it’s nearly as good as catching errors at compilation time, but it’s better than not doing any checking at all…

 

[DataContract]

public class StatusHistory<T> : SortedDictionary<DateTime, StatusHistoryItem<T>>

{

    public StatusHistory()

    {

        // NOTE: Unfortunately, we can't create a 'where T : short' constraint

        if ((typeof(T)).IsEnum == false)

        {

            throw new ApplicationException("Status must be an enumerated data type!");

        }

    }

}