Hint: use the Explore Type Hierarchy (Ctrl+E,H) command to explore the hiearchies of the various
Image Added At the very top of the ‘hierarchy of types’, we have the
IExpressionType interface. This is a wide-reaching interface that covers any type that an expression may be and also happens to cover the principal ‘concrete’ interface
So where is
IExpressionType used? Well, the most obvious example is if you’ve got an expression (i.e., an
IExpression), you can use its
GetExpressionType() method to get the expression’s
IExpressionType. Of course, in most cases the expression type is expected to be an actual object type — type -- an
IType — -- in which case it makes sense to call
IExpressionType.ToIType() method. Of course, it returns
null in case when the expression in question is not an
We’ve looked at a hierarchy of types, but how does this help us? Well, now that we know a little about types, we can start looking at yet another hierarchy -- a hierarchy of declared elements.
IDeclaredElement is ReSharper’s über-interface for defining various physical language constructs in ReSharper. By physical we assume that a PSI tree has been built for them, in other words, we have the source code that defines this element. Declared elements are used to represent not just different constructs (such as a CLR class or a CSS function) but also different facets of structures.
Important Note: concrete declared elements can implement multiple interfaces. As a result, a single declared element can be both an
ITypeOwner and an
ITypeParametersOwner. The majority of declared elements implement multiple interfaces.
At this stage, it would be counterproductive to discuss each of the possible declared elements. The recommended approach for figuring out the exact structure is to introspect the type hierarchy and locate concrete types. For example, looking into an
ITypeOwner one can find an
IField interface and its concrete implementation
While on the subject of types as such, let’s discuss the CLR types and how they are exposed. Walking down the inheritance hierarchy, underneath
IClrDeclaredElement we first encounter the
ITypeParametersOwner interface which, as mentioned previously, is implemented by any construct that can have type parameters. This interface exposes just one property, a list of
ITypeParameter objects that correspond to type parameters.
What’s more interesting, however, is the underface inheriting from it. This interface is called
ITypeElement. What’s important about this interface is that it represents a CLR type, such as a class, structure, enumeration or delegate. This interface is inherited by interfaces such as
IStruct, and so on. Let’s discuss some of its members:
NestedTypes— this property is itself a list of
ITypeElemententities representing the nested types.
Methods, and so on — all these properties yield enumerations of appropriate type members.
GetMembers()— helps you get all of the above in a single list of
GetContainingNamespace()— does exactly what it says, and may return
nullif the type isn’t within a namespace (i.e., it is at global scope).
There is also a
TypeElementExtensions class which provides additional functionality. For example, to check if a type is a descendant of another type (i.e., has another type above it somewhere in the inheritance chain), you can use the