Search code examples
c#genericsgeneric-programmingtype-constraints

Real-world examples with subtyping constraints in .NET generics


Are there any real-world examples of using subtyping constraints on type parameters in .NET generics? By «subtyping constraints» I mean

where T : <base class name>

and

where T : U

May be there are some standard generics with corresponding constraints? Or specialized generic .NET-libraries.

UPD There are lots of good examples with interface constraints

where T : <interface name>

But subtyping constraints seems to be very specific and not so useful. I try to understand, in which cases this kind of constraints is really crucial. Luaan's answer contains examples with where T : <base class name> from ASP.NET MVC, but I am still interested in real-world examples with where T : U constraint.


Solution

  • It's something you use a lot. In a way, it immitates the way normal inheritance works.

    So for example, if you've got a common functionality built around O/RM entities, you can just create an entity base class, and use that as a type constraint in all the various data layers manipulating that entity.

    Extremely useful is its use with interfaces.

    And very often, you're going to write some kind of a wrapper around something else.

    The basic idea is that you use those when you really only want the type parameter to fit some use case, but rather than just using the interface, you let the user of your code supply their concrete type. It still implements all the stuff you need to work correctly, but at the same time, the user can use all the features, even those you don't know about.

    You will not find many cases in the BCL. Basically, this has to do with the fact that type constraints are constraints. The BCL usually uses generic types and methods to write very general functionality - I guess that's in part because of the fact that most of the BCL was there before generics, and because most of the time, inheritance will work just as well, if not better.

    There's still differences, though. Say you need a collection of some entities. If you just use List<Entity>, you're saying "I expect any entity whatsoever, thanks". If you use List<T> where T : Entity (pseudocode), you're saying "I need to know the type you're giving me is an Entity, but I only want one kind of entity in the whole collection".

    All in all, if you want good applications of generic type constraints, look at newer code. For example, in ASP.NET MVC, there's things like this:

    public abstract class CachedAssociatedMetadataProvider<TModelMetadata> 
           : AssociatedMetadataProvider 
           where TModelMetadata : ModelMetadata
    
    public class DataAnnotationsModelValidator<TAttribute>
           : DataAnnotationsModelValidator 
           where TAttribute : ValidationAttribute
    

    It's also very useful when you're using Actions (or events) to tag functionality to some such general class from the outside.

    Again, the uses are basically such:

    • Constraint the types that can be used in your class
    • Ensure the type passed to you conforms to some contract
    • Improve useability for the users of your code
    • Performance optimization of value-types, mostly avoiding boxing - e.g. you can use IComparable without having to box the value