Page Comparison - 3.1 Type System (v.6 vs v.7)

Versions Compared


  • This line was added.
  • This line was removed.
  • Formatting was changed.


Hint: use the Explore Type Hierarchy (Ctrl+E,H) command to explore the hiearchies of the various IXxxType interfaces.


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 IType.


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 IType.


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.


Image Added
The 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.

Beyond IDeclaredType

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 CSharpField.



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 IClass, IStruct, and so on. Let’s discuss some of its members:

  • NestedTypes — this property is itself a list of ITypeElement entities representing the nested types.
  • Constructors, Operators, 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 ITypeMember entities.
  • GetContainingNamespace() — does exactly what it says, and may return null if 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 IsDescendantOf() method.