2

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

Community
  • 1
  • 1
atoMerz
  • 7,534
  • 16
  • 61
  • 101
  • Did you use the library suggested in the accepted answer to that question? – Oded Jan 03 '12 at 18:19
  • @Oded, I tried, but there are no sample codes so I don't even know where to start. Although this is another question, I find this a nicer way of doing it since its already a part of .NET framework. – atoMerz Jan 03 '12 at 18:21
  • 1
    @AtoMerZ: Unconstrained Melody is designed to be used as a library, but you could use the same IL rewriting for your own code. Just have a look at the code - it's pretty simple. – Jon Skeet Jan 03 '12 at 18:23
  • Did you enable "perform static checking" in the project in question? – Erik Dietrich Jan 03 '12 at 18:26
  • @JonSkeet, I got NuGet, Added Unconstrained Melody to my project, after that I have no Idea what I should do. I still get an error when I write class `MyClass where T:enum`. Could you provide a sample on how to use it? – atoMerz Jan 03 '12 at 18:29
  • One thing to do, if you can't solve the static analysis bit, is to put the type check in the static constructor, so it doesn't run every time you create an object. – phoog Jan 03 '12 at 18:32
  • @AtoMerZ: No, it doesn't change the C# compiler - the NuGet package is just the resulting library, which is basically utility methods around enums. It's possible that I already cover what you're trying to do (you haven't said what your code does) but if not, look at the source for the rewriter and the blog post: http://msmvps.com/blogs/jon_skeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx – Jon Skeet Jan 03 '12 at 18:36
  • @JonSkeet, Either I'm too stupid to understand what you're saying or it's just complex. Anyways, I have a class called `Bead`. It has a field `T value`. I want to make sure T is an enum. – atoMerz Jan 03 '12 at 18:53
  • @AtoMerZ: Well it's reasonably complex - you're asking for a feature which isn't part of the language. I'm saying that there's a way of mimicking it to some extent: the blog post gives a description, and you can download the code to look at how it all hangs together. – Jon Skeet Jan 03 '12 at 18:58
  • @JonSkeet, Sorry, I don't wanna take too much of your time. I understand what the library is trying to do (at least I think I do). I think you're misunderstanding my problem: I don't know how to use it. After adding the library what is the code I should use? Do I define an interface named IEnumConstraint write `MyClass where T : where T : struct, IEnumConstraint`? I tried this and it didn't work. What am I supposed to write so you're library know it should add something to my IL at that point? – atoMerz Jan 03 '12 at 19:10
  • @AtoMerZ: You wouldn't use the normal Unconstrained Melody library at all - you'd use the same IL rewriter which is used to convert the `IEnumConstraint` constraints into "proper" enum constraints. You'd run that tool over your library containing `MyClass`, and after that any callers from *other* assemblies would be constrained. It wouldn't help within the same assembly though. – Jon Skeet Jan 03 '12 at 19:15
  • @JonSkeet, So if I get it right, I should create a file like `mylib.dll`contatining `MyClass where T:IEnumConstraint`. I compile it. I execute some program called `IL rewriter` on `mylib.dll`. After this point any assemblies using my library have to conform to the enum constraint? – atoMerz Jan 03 '12 at 19:26

1 Answers1

1

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.

Erik Dietrich
  • 6,080
  • 6
  • 26
  • 37
  • Thanks. It worked both ways (Precondition and Invariant). I'm not sure what the error was but I noticed warnings took a few seconds to appear after compile so I assume I was just impatient. – atoMerz Jan 03 '12 at 19:04
  • 1
    Default is to run the static checks in the background, so it keeps running after compile is done. This becomes important when the project gets bigger because without it, the static analysis would take a long, long time. You can bypass this if you want, for a smaller project, by unchecking "check in background". – Erik Dietrich Jan 03 '12 at 19:06