How do I create a `ITypeElement` with represents a

2019-08-12 01:05发布

问题:

I'm using the ReSharper 8 sdk and want to find all inheritors of a particular generic interface, where the generic type is a particular type. I have asked a more general question which got most of the way there, but I am only able to find any implementation of ICommandHandler<T> and not the one implementation I want, ICommandHandler<TestCommand>

this is the code I have:

foreach (var psiModule in declaredElement.GetPsiServices().Modules.GetModules())
{
    IDeclaredType genericType = TypeFactory.CreateTypeByCLRName("HandlerNavigationTest.ICommandHandler`1", psiModule, theClass.ResolveContext);
    var genericTypeElement = genericType.GetTypeElement();
    if (genericTypeElement != null)
    {                    
        var theType = TypeFactory.CreateType(originalTypeElement);
        var commandHandlerType = TypeFactory.CreateType(genericTypeElement,theType);
        var handlerTypeelement = commandHandlerType.GetTypeElement();
        solution.GetPsiServices().Finder.FindInheritors(handlerTypeelement, searchDomainFactory.CreateSearchDomain(solution, true),
        inheritorsConsumer, NullProgressIndicator.Instance);
        var inheritedInstance= inheritorsConsumer.FoundElements.First();
        var sourceFile = inheritedInstance.GetSourceFiles().First();
    }
}  

if I tooltip the commandHandlerType after this line:

var commandHandlerType = TypeFactory.CreateType(genericTypeElement,theType);

I see that the type is correctly specified:

But then when I get the ITypeElement from this type to pass into my search using this line

var handlerTypeelement = commandHandlerType.GetTypeElement();

I seem to have lost the type:

And so my search finds all implementations of the ICommandHandler<T>.

So my question is, how do I create the ITypeElement which represents the closed generic type I want to search for?

Or alternatively: How can I search the returned collection of inheritors for the type which has the class I started with as the generic type parameter?

回答1:

Ah, that makes sense. An ITypeElement is an instance of IDeclaredElement, which means it's something that has a declaration - such as a class or interface declaration. So when you get an IType that represents your closed generic, it's made up of an ITypeElement that represents the generic type (ICommandHandler) and an ISubstitution that represents the resolved generic type parameters (AnotherCommand). When you call IType.GetTypeElement(), it will return the type element part of the type element/substitution pair, which is the open generic declared element (because an interface declaration can only ever be open).

I think you might have to take the alternative approach, and find all inheritors (implementors) of ITypeHandler<T> and filter them down in the consumer. The FindResult passed to the consumer can be downcast to a FindResultInheritedElement, which will give you a declared element that represents the class that implements ITypeHandler<T>. You should be able to walk these elements' interfaces to see what they implement, and only accept those find results that implement the correct T. I think TypeElementUtil will help here to get all super types (base types + interfaces) of the declared element.