Generics and the special constraints


Someone recently asked me to update an old post of mine  Reflection and Generics .  You gotta be careful what you write in blogs as they seem to live forever. 

 

Well, it is true, this needs a little updating.  We no longer use the NewConstraintAttribute (or the other special constraint attributes) to denote the special constraint in the metadata.  (In fact they are being removed from Whidbey)

 

Here are some examples in C# syntax:

class C<T> where T : new() { } // T must have a public default constructor

class C<T> where T : class { } // T must be a class

class C<T> where T : struct { } // T must be a struct

 

Here are some examples in VB syntax:

 

Class C(Of T As New)

End Class

 

Class C1(Of T As Class)

End Class

 

Class C2(Of T As Structure)

End Class

 

 

We now encode it the IL syntax for special constraints by putting either ‘.ctor’, ‘class’ or ‘valuetype’ before the type parameter name (C<T> above is minimally ‘C`1′<.ctor T> in IL).

 

So, some code to show how this works in the IL:

 

class Class1

{

    static void Main()

    {

        GenericParameterAttributes ga = typeof(C<>).GetGenericArguments()[0].GenericParameterAttributes;

        if ((ga & GenericParameterAttributes.SpecialConstraintMask) == GenericParameterAttributes.DefaultConstructorConstraint)

        {

            Console.WriteLine(“Has New Constriant”);

        }

        else

        {

            Console.WriteLine(“Does not have New Constriant”);

        }

    }

}

 

Comments (7)

  1. Hi,

    I have a question regarding generics. Suppose I have made a class like this:

    class View<Model> : where Model : ModelBase

    Now I have several classes which inherits ModelBase class. For example, CarModel, AirplaneModel.

    Now I am making a collection class like this:

    List<View<ModelBase>> list;

    list.Add( new View<CarModel> );

    Unfortunately I cannot do that. Although

    CarModel is a child of ModelBase and the collection I am making is of View<ModelBase>, but it does not work.

  2. AT says:

    Thanks Brad for an answer.

    I’ve posted a RFC on PF for this http://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?FeedbackId=FDBK16162 – but now unable to close it 🙁

    Omar Al Zabir: Generics does not support downcasting and does NOT follow class inheritance hierarhy of their type params because in addition to input params – generics methods has output params.

    class View<T> {

    T Current { get; }

    bool Update(ref T);

    }

    See my comments on http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=FDBK13559

    But I think that this will be cool to create some kind of inheritance-aware generics if you will mark your generics class with some kind of special flag that one of typeparams can be used for input-only.

    Something like

    class GenericClass<[InputOnly] InT, OutT> where InT: OutT {

    OutT DoMagic(InT x) { return x;}

    }

    or

    class IComparer<[FollowInheritance] T> {

    bool Compare(T a, T b) { return false; }

    }

  3. Diego Mijelshon says:

    Omar,

    Generics and Polymorphism don’t mix.

    If that construction worked, what would list.Item return?

    Remember, a constructed type can’t return generic types.

    You don’t need generics for your model:

    Class View

    {

    public View(ModelBase model) {…}

    }

    List<View> list = new List<View>();

    list.Add(new View(new CarModel()));

    list.Add(new View(new AirPlaneModel()));

  4. Thanks for all the replies.

    The reason I need this is for following:

    List<View<ModelBase>> list = new List<View<ModelBase>>();

    list.Add( new View<CarModel>() );

    list.Add( new View<AirPlaneModel>() );

    View<CarModel> carView = (View<CarModel>)list[0];

    car.Model.Vroomm(); // Model is actual CarModel here

    View<CarModel> airView = (View<CarModel>)list[1];

    air.Model.Shooo(); // Model is actual AirplaneModel here

    But unfortunately, nothing works like this. I think it would be very

    handy feature of Generics. My goal is to ultimately get a View<…> from

    list where View.Model is the actual class.

    class View<T>

    {

    public T Model;

    }

    If I make is using simple polymorphism, then it will be like this:

    class View

    {

    public ModelBase Model;

    }

    In that case, I will have to write:

    ((CarModel)View.Model).Vroom();

    ((AirPlaneModel)View.Model).Shooo();

    I miss all the fun of generics here just because I can’t add generic objects in the collection.

  5. Thanks for all the replies.

    The reason I need this is for following:

    List<View<ModelBase>> list = new List<View<ModelBase>>();

    list.Add( new View<CarModel>() );

    list.Add( new View<AirPlaneModel>() );

    View<CarModel> carView = (View<CarModel>)list[0];

    car.Model.Vroomm(); // Model is actual CarModel here

    View<CarModel> airView = (View<CarModel>)list[1];

    air.Model.Shooo(); // Model is actual AirplaneModel here

    But unfortunately, nothing works like this. I think it would be very

    handy feature of Generics. My goal is to ultimately get a View<…> from

    list where View.Model is the actual class.

    class View<T>

    {

    public T Model;

    }

    If I make is using simple polymorphism, then it will be like this:

    class View

    {

    public ModelBase Model;

    }

    In that case, I will have to write:

    ((CarModel)View.Model).Vroom();

    ((AirPlaneModel)View.Model).Shooo();

    I miss all the fun of generics here just because I can’t add generic objects in the collection.

  6. If you opened up your CD from Krzysztof Cwalina and Brad Abram’s new book Framework Design Guidelines….