Reputation: 26281
Consider the following code:
IEnumerable<Type> oneParameterTypes = Assembly.GetAssembly(typeof(object))
.GetTypes()
.Where(t => t.IsGenericType)
.Where(t => t.GetGenericArguments().Length == 1)
.Where(t => t.GetGenericArguments().Single().GetGenericParameterConstraints().Length == 0);
oneParameterTypes
should hold all the generic types in the System.dll
assembly, that can be passed a single generic type parameter and apply no constraint to it.
Now, let's pass in a type parameter:
IEnumerable<Type> intParameterTypes = oneParameterTypes.Select(t => t.MakeGenericType(typeof(int)))
.ToList();
This should work, right? I mean, all the types in oneParameterTypes
should have no type constraints, so System.Int32
should be a valid type.
Yet, the line throws the following exception:
GenericArguments[0], 'System.Int32', on 'System.RuntimeType+ListBuilder`1[T]' violates the constraint of type 'T'.
What is this ListBuilder'1
type and why is it in oneParameterTypes
if it has a type constraint? Why is my Where
filter not working?
Upvotes: 1
Views: 400
Reputation: 149518
The documentation isn't really clear about what Type.GetGenericParameterConstraints
actually looks for:
Use the IsClass property to determine whether a constraint is the base class constraint; if the property returns false, the constraint is an interface constraint. If a type parameter has no class constraint and no interface constraints, an empty array is returned.
You can implicitly understand that it will only check for a base class or interface constraint. To get the complete picture around which constraints exist, you'll need to have additional checks on GenericParameterAttributes
. You can either use HasFlag
or a bitwise mask:
IEnumerable<Type> oneParameterTypes = Assembly.GetAssembly(typeof(object))
.GetTypes()
.Where(t => t.IsGenericType)
.Where(t => t.GetGenericArguments().Length == 1)
.Where(t => t.GetGenericArguments().Single().GetGenericParameterConstraints().Length == 0 && !t.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint);
Upvotes: 1
Reputation: 8843
I think Chris is correct.
Try it like this:
IEnumerable<Type> oneParameterTypes = Assembly.GetAssembly(typeof (object))
.GetTypes()
.Where(t => t.IsGenericType)
.Where(t => t.GetGenericArguments().Length == 1)
.Where(t => t.GetGenericArguments().Single().GetGenericParameterConstraints().Length == 0 &&
!genericArgument.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint);
});
Upvotes: 2
Reputation: 130
typeof() or .GetType() method does not return the actual class, instead they will return the Type Object representation, which will help us in using the type name as a string.
Instead, you can use reflection classes and find the class of that type and use that as a parameter
Upvotes: 0