IDeclaredElement interfaces provide a semantic view of something that has a declaration, but that doesn’t necessarily allow for modelling usages of the element. Specifically, if we take a look at CLR types, a declared element is a declaration of a type, such as a class, but it can’t represent all usages of the type, such as in an array, pointer or closed generic type. The
ITypeElement interface can provide a semantic view of the declaration of
Bar<T>, but it can’t represent
Declared elements need to be able to model these usage scenarios to provide information about base classes, method signatures, etc. In order to do so, the derived declared elements (such as
ITypeElement) use an additional interface hierarchy to represent this “type system” information. This hierarchy is language specific, like the derived declared elements that use them. For CLR types, it’s the
IType is additional information rather than a replacement for the declared element’s semantic view. While the
IType can return a symbol table of all type members, it doesn’t provide accessors in the same way that
ITypeElement does. However, it is possible to get back to the declared element. If the type implements
GetTypeElement method will return the
ITypeElement, which gives the full semantic view of the type.
Arrays and pointers are both defined in terms of another instance of
IType, allowing for recursively declaring types, such as multi-dimensional arrays, or arrays of generic types. The derived interfaces, such as a
IArrayType allow getting the element type (such as
int), and in the case of arrays, the array’s rank.
Generic types are internally represented by a declared element and an instance of
ISubstitution, which describes how the generic type parameters are substituted. (Non generic types are represented in the same manner, but use the Null Object Pattern and use an instance of
It’s also possible to get the underlying declared type via the
IType.GetScalarType method, which returns the element type for arrays, and will downcast to
IDeclaredType for other types.
Types are retrieved from a declared element - such as a base type, or member type signature. Alternatively, types can be created using the
TypeFactory.CreateType methods, passing in a fully qualified type name and any type parameters, or an
IDeclaredElement and an instance of
ISubstitution. Some frequently used types are also available from the