5

I defined a following example class having one generic method DoSomething:

public static class MyClass
{
    public static void DoSomething<T>(T val)
    {
        System.Diagnostics.Contracts.Contract.Requires(typeof(T).IsEnum);
    }
}

And I have the following enum:

public enum MyEnum { A, B }

Now I invoke the method with an instance of my enum as follows:

class Program
{
    static void Main(string[] args)
    {
        MyClass.DoSomething(MyEnum.A);
    }
}

With static checking enabled in the code contracts, the following warning is displayed at the line where I invoke the method:

CodeContracts: requires unproven: typeof(T).IsEnum

Why is it unproven if it the value is known at compile-time?

EDIT

Since this is obviously not working, probably because Code Contracts do not understand the semantics of IsEnum or val is Enum (as well pointed out by Jon). I am interested, if there is any known way to do this kind of checks in code contracts?

Edin
  • 1,476
  • 11
  • 21
  • 2
    Almost certainly because Code Contracts has not been instructed about the semantics of `IsEnum`, since as you say all the information necessary to prove the requirement is available statically. – Jon May 22 '14 at 12:02
  • While it is known in some sense at compile type that `MyEnum` is an enumeration, it is apparently not known just how `System.Type.IsEnum` is implemented (it is actually overridden in `System.RuntimeType` which is going to be the actual type of `typeof(T)`). So I agree with Jon. I don't know if Code Contracts offers another way to express this requirement. – Jeppe Stig Nielsen May 22 '14 at 12:04
  • Suggestion: I would _think_ `val is Enum` could be resolved at compile time. A value of `MyEnum` is never `null` when boxed, and always of a type derived from `System.Enum`. If some fool uses `DoSomething((Enum)null);` or similar, then because `System.Enum` is not an "enum" but a reference type, it might be caught in a good way? – Jeppe Stig Nielsen May 22 '14 at 12:10
  • @Jeppe: `val is Enum` produces the same requires unproved warning. – Edin May 22 '14 at 12:46
  • OK, thanks. Actually I have no experience with Code Contracts. I just know that code like `MyEnum value = XXX; bool test = value is Enum;` will make the C# compiler issue a warning (not error) that the `is` expression has always the same value. That was why I _thought_ it might work. – Jeppe Stig Nielsen May 22 '14 at 13:23
  • What property of Enum are you trying to ensure that your generic parameter have? Do you just need to be sure you can convert it to a string/int? If so an approximation would be to put a T : struct, IConvertible constraint on the generic parameter itself. Still not perfect but the problem with generics is they can be anything so hard to know at compile time that IsEnum will be true (there isn't unfortunately a way in C# to constrain a generic parameter to Enum). – Mike Jun 21 '14 at 04:22

1 Answers1

0

If you're trying to work around the lack of an "enum" constraint in c#, there's a strange yet totally workable solution already given here: Enum type constraints in C#

public abstract class Enums<Temp> where Temp : class {
    public TEnum DoSomething<TEnum>(string name) where TEnum : struct, Temp
    {
        // Your code
    }
}

public abstract class Enums : Enums<Enum>
{ 
}

Or, you can do it in c++/CLI in a small sub-project since the constraint does seem to work there (example is for type-safe "enum.parse"):

using namespace System;

public ref class EnumHelper 
{
public:
    generic <typename T> where T : Enum
    static T Parse(String^ value)
    {
        return Parse<T>(value,
                        false);
    }

    generic <typename T> where T : Enum
    static T Parse(String^ value,
                   bool ignoreCase)
    {
        return safe_cast<T>(Enum::Parse(T::typeid,
                                        value,
                                        ignoreCase));
    }
};
Community
  • 1
  • 1
dbc
  • 104,963
  • 20
  • 228
  • 340