Search code examples
c#inheritanceenumsconstraintscode-contracts

Using code contracts to make a generic to be of type enum


A few days ago I asked a question titled How to constraint a generic to be of type enum?. To summarize the problem is the following code:

class MyClass<T> where T : enum // Not possible in C#
{
}

I was introduced to code contracts and that I could produce a compile time warning for the problem, which is all I want (to be informed at compile time that T should be an enum). I tried the follwing code (Full source).

class MyClass<T>
{
  public MyClass()
  {
    Contract.Requires(typeof(System.Enum).IsAssignableFrom(typeof(T)));
  }
}

It only produces a useless runtime error. I should be able to produce a compile time warning but I can't get it to work. Can anyone tell me what I'm doing wrong?

Here's a picture of project's Code Contracts setting: Code Contracts Setting


Solution

  • So, I wrote the following code in a file:

    public class SomeClass<T>
    {
        [ContractInvariantMethod]
        private void Invariants()
        {
            Contract.Invariant(typeof(System.Enum).IsAssignableFrom(typeof(T)));
        }
    
        /// <summary>Initializes a new instance of the SomeClass class.</summary>
        /// <param name="dependency"></param>
        public SomeClass()
        {
    
        }
    }
    
    public class SomeOtherClass
    {
        public SomeOtherClass()
        {
            var myClass = new SomeClass<int>();
    
        }
    }
    

    From there, I went into the Code Contracts section of the project options and checked all checkboxes under "static checking". I then turned the warning level to "high". When I rebuilt the solution, I received a warning: "Code Contracts: invariant requires unproven: typeof(...)" that corresponded to the class invariant.

    From there, I set the warning level back to low and saw that there was no warning, ala what you're reporting. So, I think that setting the warning level to high is what you need.

    If that doesn't work, you might try following what I did and defining your contract as a class invariant (which, pedantically, I would suggest doing anyway because this is more of a class level invariant, conceptually, than a result of your constructor's execution).

    Edit: I saw your screenshot after I posted, so I'd amend this to suggest using my "if that doesn't work" suggestion with the class level invariant instead of the requires invocation from the xtor.