Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking if an object meets a Generic Parameter constraint

I have an interface similar to the one below:

public interface IInterface<T>
    where T : IInterface<T>
{
}

And now I need to create a type representing this interface using reflection, e.g.

typeof(IInterface<>).MakeGenericType(someType);

However, I don't actually know what type 'someType' will be until runtime, and it's possible that the type won't be valid as a type argument for the generic interface, so MakeGenericType fails.

The question is, how can I check that 'someType' is valid for the generic constraint?

like image 335
Simon Avatar asked Feb 01 '11 15:02

Simon


People also ask

How do you determine what type a generic parameter T is?

You can get the Type that represents T , and use the IsInterface property: Type type = typeof(T); if (type. IsInterface) { ... } If you want to know which interface is passed, just use == to compare the Type objects, e.g.

Where is generic type constraint?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

How do you find the property of a generic type?

Use the IsGenericType property to determine whether the type is generic, and use the IsGenericTypeDefinition property to determine whether the type is a generic type definition. Get an array that contains the generic type arguments, using the GetGenericArguments method.

What are generic constraints with type parameters?

A type constraint on a generic type parameter indicates a requirement that a type must fulfill in order to be accepted as a type argument for that type parameter. (For example, it might have to be a given class type or a subtype of that class type, or it might have to implement a given interface.)


2 Answers

To be honest, the simplest approach would be to just call MakeGenericType and catch the ArgumentException that will be thrown if any type argument is wrong (or if you've got the wrong number of type parameters).

While you could use Type.GetGenericParameterConstraints to find the constraints and then work out what each of them means, it's going to be ugly and bug-prone code.

I don't usually like suggesting "just try it and catch" but in this case I think it's going to be the most reliable approach. Otherwise you're just reimplementing the checks that the CLR is going to perform anyway - and what are the chances you'll reimplement them perfectly? :)

like image 152
Jon Skeet Avatar answered Nov 16 '22 02:11

Jon Skeet


This is possible. Given a constraint, you use Type.GenericParameterAttributes and the masks

GenericParameterAttributes.ReferenceTypeConstraint
GenericParameterAttributes.NotNullableValueTypeConstraint
GenericParameterAttributes.DefaultConstructorConstraint

to check for the presence of class, struct or new() constraints. You can easily check if a given type satisfies these constraints (the first is easy to implement (use Type.IsClass), the second is slightly tricky but you can do it using reflection, and the third has a little gotcha that your unit testing will detect (Type.GetConstructor(new Type[0]) doesn't return the default constructor for value types but you know those have a default constructor anyway).

After this, you use Type.GetGenericParameterConstraints to get the type hierarchy constraints (the where T : Base, IInterface like constraints) and run through them to check that the given type satisfies them.

like image 25
jason Avatar answered Nov 16 '22 03:11

jason