views:

84

answers:

2

Hello,

a few weeks ago a co-worker of mine spent about two hours finding out why this piece of C++/CLI code won't compile with Visual Studio 2008 (I just tested it with Visual Studio 2010... same story).

public ref class Test
{
    generic<class T> where T : value class
        void MyMethod(Nullable<T> nullable)
    {

    }
};

The compiler says: Error

1 error C3214: 'T' : invalid type argument for generic parameter 'T' of generic 'System::Nullable', does not meet constraint 'System::ValueType ^' C:\Users\Simon\Desktop\Projektdokumentation\GridLayoutPanel\Generics\Generics.cpp 11 1 Generics

Adding ValueType will make the code compile.

public ref class Test
{
    generic<class T> where T : value class, ValueType
        void MyMethod(Nullable<T> nullable)
    {

    }
};

My question is now. Why? What is the difference between value class and ValueType?

P.S: See the Nullable definition for C++: http://msdn.microsoft.com/de-de/library/b3h38hb0.aspx

A: 

ValueType is special in that it is the "base class" of value types, but not a value type itself. This is probably the issue here.

A nice list of the different entities which are used by the CLR can be found in this excellent blog post.

See also this and this thread for some more information specific to the ValueType.

Lucero
Thanks for your researches, Lucero.
Simon
A: 

I analyzed the IL code of the three following methods:

generic<class T> where T : value class, System::ValueType
    static void MyMethod(T arg)
{

}

generic<typename T> where T: value class
    static void MyMethod2(T arg)
{

}

generic<typename T> where T: ValueType 
    static void MyMethod3(T arg)
{
}

The corresponding IL-code, which I dissassembled with .NET-Reflector:

.method public hidebysig 
 static void MyMethod<valuetype ([mscorlib]System.ValueType).ctor T>
(!!T arg) cil managed
{
}


.method public hidebysig 
static void MyMethod2<valuetype .ctor T>(!!T arg) cil managed
{
}


.method public hidebysig
static void MyMethod3<([mscorlib]System.ValueType) T>(!!T arg) cil managed
{
}

This is the IL-declaration of Nullable<T>:

.class public sequential ansi serializable sealed beforefieldinit 
Nullable<valuetype (System.ValueType) .ctor T>
    extends System.ValueType

As you can clearly see, only the first method's constraint matches 100% with Nullable<T>'s. (Btw: value class seems to imply the presence of a standard constructor). However, why the compiler produces different IL-code for (semantically) the same constraints, remains still a mystery. I will ask Microsoft's C++/CLI Gurus for further information.

Simon