.NET generics terminology is a bit ambiguous. Even worse - it seems to be used ambiguously and differently in different sources. What basically is not clear is relationships between these 4 terms (in relation to "Type"):
I understand that List<T>
is open and List<int>
is closed. But what really is "constructed" and "unbound" in relation to open/closed types?
An unbound type refers to the entity declared by a type declaration. An unbound generic type is not itself a type, and cannot be used as the type of a variable, argument or return value, or as a base type. The only construct in which an unbound generic type can be referenced is the typeof expression (§11.7.
An "open generic type" is just a generic type that doesn't yet have its type specified (e.g., CargoCrate<T> ).
As noted in the Subsequent Procedures Policy Development Process Working Group (SubPro PDP WG) Final Report, a closed generic is "a TLD representing a string that is a generic name or term under which domains are registered and usable exclusively by the registry operator or its affiliates."
What Does Generics Mean? Generics refer to a feature in C# that allows defining a class or method with type as a parameter. Generics allow for designing a classes and methods whose types are specified only at the time of declaration and instantiation.
From the language specification:
4.4 Constructed types
A generic type declaration, by itself, denotes an unbound generic type that is used as a “blueprint” to form many different types, by way of applying type arguments. The type arguments are written within angle brackets (< and> ) immediately following the name of the generic type. A type that includes at least one type argument is called a constructed type. A constructed type can be used in most places in the language in which a type name can appear. An unbound generic type can only be used within a typeof-expression (§7.6.11). [...]
4.4.2 Open and closed types
All types can be classified as either open types or closed types. An open type is a type that involves type parameters. More specifically:
• A type parameter defines an open type.
• An array type is an open type if and only if its element type is an open type.
• A constructed type is an open type if and only if one or more of its type arguments is an open type. A constructed nested type is an open type if and only if one or more of its type arguments or the type arguments of its containing type(s) is an open type.
A closed type is a type that is not an open type. [...]
4.4.3 Bound and unbound types
The term unbound type refers to a non-generic type or an unbound generic type. The term bound type refers to a non-generic type or a constructed type. An unbound type refers to the entity declared by a type declaration. An unbound generic type is not itself a type, and cannot be used as the type of a variable, argument or return value, or as a base type. The only construct in which an unbound generic type can be referenced is the typeof expression (§7.6.11).
Here's an example I thought of:
// Foo<T> is an unbound generic type.
class Foo<T> { .. }
// Bar<K> is an unbound generic type.
// Its base-class Foo<K> is a constructed, open generic type.
class Bar<K> : Foo<K> { .. }
// IntFoo is not a generic type.
// Its base-class Foo<int> is a constructed, closed generic type.
class IntFoo : Foo<int> { .. }
And here's an attempt to tie that in with the reflection API, using the relevant properties: IsGenericType
, IsGenericTypeDefinition
and ContainsGenericParameters
(These tests are not 100% predictive of each "kind" as per the language spec).
+----------+---------------------+-----------+--------------+-------------------+
| Name | Kind | IsGenType | IsGenTypeDef | ContainsGenParams |
+----------+---------------------+-----------+--------------+-------------------+
| Foo<> | Unbound | TRUE | TRUE | TRUE |
| Foo<>* | Constructed, open | TRUE | FALSE | TRUE |
| Foo<int> | Constructed, closed | TRUE | FALSE | FALSE |
| IntFoo | Not generic | FALSE | FALSE | FALSE |
+----------+---------------------+-----------+--------------+-------------------+
* = Bar<>'s base type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With