Difference between Type.IsGenericTypeDefinition and Type.ContainsGenericParameters

Type.ContainsGenericParameters is recursive:

var genericList = typeof(List<>);
var listOfSomeUnknownTypeOfList = genericList.MakeGenericType(genericList);
listOfSomeUnknownTypeOfList.IsGenericTypeDefinition;  // => false
listOfSomeUnknownTypeOfList.ContainsGenericParameters; // => true

What happens here is that listOfSomeUnknownTypeOfList is not a generic type definition itself because its type parameter is known to be a List<T> for some T. However, since the type of listOfSomeUnknownTypeOfList is not exactly known (because its type argument is a type definition) ContainsGenericParameters is true.


ContainsGenericParameters is a recursive version of IsGenericTypeDefinition.

typeof(List<Func<>>).IsGenericTypeDefinition is false.


There is a table under IsGenericType that tries to highlight some differences:

The IsGenericTypeDefinition property is true.

Defines a generic type. A constructed type is created by calling the MakeGenericType method on a Type object that represents a generic type definition and specifying an array of type arguments.

or:

The ContainsGenericParameters property is true.

Examples are a generic type that has unassigned type parameters, a type that is nested in a generic type definition or in an open constructed type, or a generic type that has a type argument for which the ContainsGenericParameters property is true.

So they're not precisely the same.