创建一个泛型类型,找到实现在ReSharper的插件 [英] Create a generic type to find implementations of in a Resharper plugin

查看:129
本文介绍了创建一个泛型类型,找到实现在ReSharper的插件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写ReSharper的一个插件,我想用从导航一个的ConcreteCommand - > ConcreteCommandHandler 其中,这些类型看起来像这样

 公共类的ConcreteCommand:ICommand的

公共类ConcreteCommandHandler:ICommandHandler<的ConcreteCommand> ;

当光标位于一个<$ C我得尽可能加入我的导航菜单选项$ C>的ICommand 实例/定义(目前只有通过检查名称中包含'命令',而不是'CommandHandler'),我想我要真正为它继承东西类型进行搜索所需的代码,但我的问题是我唯一真正有型的,是我的 ConcereteCommand ,我需要创建(或获得一个参考)泛型类型 ICommandHandler< T> T 作为光标当前的类型



所以,我有两件事我还是想知道:




  • 如何检查,如果我的 IDeclaredElement 是一个特殊的接口的实现(最好在从配置字符串指定全名)?

  • 如何创建一个 ITypeElement 这是一个泛型类型特定的接口,我可以从我现有的 IDeclaredElement S型设置泛型类型的,这样的话,我可以找到它继承的类这个



我现有的代码如下所示:

  [ContextNavigationProvider] 
公共类CommandHandlerNavigationProvider:INavigateFromHereProvider
{
公开的IEnumerable< ContextNavigation> CreateWorkflow(IDataContext的DataContext)
{
ICollection的< IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
如果(declaredElements = NULL || declaredElements.Any()!)
{
IDeclaredElement declaredElement = declaredElements.First();

如果(IsCommand(declaredElement))
{
VAR解决方案= dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
收益回报新ContextNavigation(该命令的&放大器;处理程序,空,NavigationActionGroup.Other,()=> {GotToInheritor(溶液,declaredElement);});
}
}
}

私人无效GotToInheritor(ISolution解决方案,IDeclaredElement declaredElement)
{
变种inheritorsConsumer =新InheritorsConsumer();
SearchDomainFactory searchDomainFactory = solution.GetComponent< SearchDomainFactory>();
//我怎样才能创建ITypeElement MyNameSpace.ICommandHandler≤(ITypeElement)declaredElement>这里?
solution.GetPsiServices()Finder.FindInheritors((ITypeElement)declaredElement,searchDomainFactory.CreateSearchDomain(溶液,真),inheritorsConsumer,NullProgressIndicator.Instance)。
}

私人布尔IsCommand(IDeclaredElement declaredElement)
{
//我如何检查我的declaredElement是这里的ICommand的实现?
字符串的className = declaredElement.ShortName;
返回className.Contains(命令)
和;&安培; !className.Contains(CommandHandler);
}
}


解决方案

确定管理与从@CitizenMatt正确的方向推进公平一点的工作了这一点。



基本上我的解决方案看起来像这样(仍然需要一些整理)

 私有静态只读表<&的HandlerMapping GT;的HandlerMappings =新的List<&的HandlerMapping GT; 
{
新的HandlerMapping(HandlerNavigationTest.ICommand,HandlerNavigationTest.ICommandHandler`1,HandlerNavigationTest),
新的HandlerMapping(HandlerNavTest2.IEvent,HandlerNavTest2.IEventHandler`1 ,HandlerNavTest2)
};

公开的IEnumerable< ContextNavigation> CreateWorkflow(IDataContext的DataContext)
{
ICollection的< IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
如果(declaredElements = NULL&放大器;!&安培; declaredElements.Any())
{
IDeclaredElement declaredElement = declaredElements.First();

ISolution液= dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
ITypeElement handlerType = GetHandlerType(declaredElement);
如果(handlerType!= NULL)
{
收益回报新ContextNavigation(与&处理程序,空,NavigationActionGroup.Other,()=> GoToInheritor(溶液,declaredElement为的iCLASS, DataContext的,handlerType));
}
}
}

私有静态ITypeElement GetHandlerType(IDeclaredElement declaredElement)
{
VAR theClass描述= declaredElement为的iCLASS;
如果(theClass描述!= NULL)
{
的foreach(IPsiModule psiModule在declaredElement.GetPsiServices()。Modules.GetModules())
{
的foreach(VAR的HandlerMapping在的HandlerMappings)
{
IDeclaredType commandInterfaceType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandledType,psiModule,theClass.ResolveContext);

ITypeElement typeElement = commandInterfaceType.GetTypeElement();
如果(typeElement!= NULL)
{
如果(theClass.IsDescendantOf(typeElement))
{
IDeclaredType genericType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandlerType,psiModule ,theClass.ResolveContext);
ITypeElement genericTypeElement = genericType.GetTypeElement();
返回genericTypeElement;
}
}
}

}
}

返回NULL;
}

私有静态无效GoToInheritor(ISolution解决方案,iCLASS非theClass描述,IDataContext的datacontext,ITypeElement genericHandlerType)
{
变种inheritorsConsumer =新InheritorsConsumer();
VAR searchDomainFactory = solution.GetComponent< SearchDomainFactory>();

IDeclaredType theType = TypeFactory.CreateType(theClass描述);
IDeclaredType commandHandlerType = TypeFactory.CreateType(genericHandlerType,theType);
ITypeElement handlerTypeelement = commandHandlerType.GetTypeElement();
solution.GetPsiServices()Finder.FindInheritors(handlerTypeelement,searchDomainFactory.CreateSearchDomain(溶液,真),
inheritorsConsumer,NullProgressIndicator.Instance);
变种potentialNavigationPoints =新的List< INavigationPoint>();
的foreach(ITypeElement inheritedInstance在inheritorsConsumer.FoundElements)
{
IDeclaredType [] =基类inheritedInstance.GetAllSuperTypes();
的foreach(IDeclaredType的declaredType在基类)
{
如果(declaredType.IsInterfaceType())
{
如果(declaredType.Equals(commandHandlerType))
{
变种navigationPoint =新DeclaredElementNavigationPoint(inheritedInstance);
potentialNavigationPoints.Add(navigationPoint);
}
}
}
}

如果(potentialNavigationPoints.Any())
{
NavigationOptions选项= NavigationOptions。 FromDataContext(DataContext的,你要哪一个处理程序导航到?);
NavigationManager.GetInstance(液).Navigate(potentialNavigationPoints,期权);
}
}

公共类InheritorsConsumer:IFindResultConsumer< ITypeElement>
{
私人const int的MaxInheritors = 50;

私人只读的HashSet< ITypeElement>元素=新的HashSet< ITypeElement>();

公开的IEnumerable< ITypeElement> FoundElements
{
{返回元素; }
}

公共ITypeElement建设(FindResult结果)
{
VAR inheritedElement =结果为FindResultInheritedElement;
如果(inheritedElement!= NULL)
回报(ITypeElement)inheritedElement.DeclaredElement;
返回NULL;
}

公共FindExecution合并(ITypeElement数据)
{
elements.Add(数据);
返回elements.Count< MaxInheritors? FindExecution.Continue:FindExecution.Stop;
}
}



这让我没有定位到多个处理程序,如果他们存在。这目前依赖的处理类型和处理器类型相同的组件在接口。但是,这似乎是合理的足以让我的时刻。


I'm writing a plugin for resharper which I want to use to navigate from a ConcreteCommand -> ConcreteCommandHandler where those types look like this

public class ConcreteCommand : ICommand

public class ConcreteCommandHandler : ICommandHandler<ConcreteCommand>

I've got as far as adding my navigation menu option when the cursor is on a ICommand instance/definition (currently only by checking if the name contains 'Command' and not 'CommandHandler'), and I think I have the code necessary to actually search for a type which inherits something, but my issue is that the only thing I actually have a type for is my ConcereteCommand and I need to create (or get a reference to) the generic type ICommandHandler<T> with T being the type the cursor is currently on.

So I have 2 things I still want to know:

  • How can I check if my IDeclaredElement is an implementation of a particular interface (ideally by specifying the full name in a string from config)?
  • How can I create a ITypeElement which is a generic type of a specific interface where I can set the generic type from my existing IDeclaredElements type, so I can then find classes which inherit this?

My existing code looks like this:

[ContextNavigationProvider]
public class CommandHandlerNavigationProvider : INavigateFromHereProvider
{
    public IEnumerable<ContextNavigation> CreateWorkflow(IDataContext dataContext)
    {
        ICollection<IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
        if (declaredElements != null || declaredElements.Any())
        {
            IDeclaredElement declaredElement = declaredElements.First();

            if (IsCommand(declaredElement))
            {
                var solution = dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
                yield return new ContextNavigation("This Command's &handler", null, NavigationActionGroup.Other, () => { GotToInheritor(solution,declaredElement); });
            }
        }
    }

    private void GotToInheritor(ISolution solution, IDeclaredElement declaredElement)
    {            
        var inheritorsConsumer = new InheritorsConsumer();
        SearchDomainFactory searchDomainFactory = solution.GetComponent<SearchDomainFactory>();
//How can I create the ITypeElement MyNameSpace.ICommandHandler<(ITypeElement)declaredElement> here?  
      solution.GetPsiServices().Finder.FindInheritors((ITypeElement)declaredElement, searchDomainFactory.CreateSearchDomain(solution, true),                    inheritorsConsumer, NullProgressIndicator.Instance);
    }

    private bool IsCommand(IDeclaredElement declaredElement)
    {
//How can I check if my declaredElement is an implementation of ICommand here?
        string className = declaredElement.ShortName;
        return className.Contains("Command")
               && !className.Contains("CommandHandler");
    }
}

解决方案

Ok managed to work this out with a fair bit of pushing in the right direction from @CitizenMatt.

basically my solution looks like this (still needs some tidying up)

private static readonly List<HandlerMapping> HandlerMappings = new List<HandlerMapping>
{
    new HandlerMapping("HandlerNavigationTest.ICommand", "HandlerNavigationTest.ICommandHandler`1", "HandlerNavigationTest"),
    new HandlerMapping("HandlerNavTest2.IEvent", "HandlerNavTest2.IEventHandler`1", "HandlerNavTest2")
};

public IEnumerable<ContextNavigation> CreateWorkflow(IDataContext dataContext)
{
    ICollection<IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
    if (declaredElements != null && declaredElements.Any())
    {
        IDeclaredElement declaredElement = declaredElements.First();

        ISolution solution = dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
        ITypeElement handlerType = GetHandlerType(declaredElement);
        if (handlerType != null)
        {
            yield return new ContextNavigation("&Handler", null, NavigationActionGroup.Other, () => GoToInheritor(solution, declaredElement as IClass, dataContext, handlerType));
        }
    }
}

private static ITypeElement GetHandlerType(IDeclaredElement declaredElement)
{
    var theClass = declaredElement as IClass;
    if (theClass != null)
    {
        foreach (IPsiModule psiModule in declaredElement.GetPsiServices().Modules.GetModules())
        {
            foreach (var handlerMapping in HandlerMappings)
            {
                IDeclaredType commandInterfaceType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandledType, psiModule, theClass.ResolveContext);

                ITypeElement typeElement = commandInterfaceType.GetTypeElement();
                if (typeElement != null)
                {
                    if (theClass.IsDescendantOf(typeElement))
                    {
                        IDeclaredType genericType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandlerType, psiModule, theClass.ResolveContext);
                        ITypeElement genericTypeElement = genericType.GetTypeElement();
                        return genericTypeElement;
                    }
                }
            }

        }
    }

    return null;
}

private static void GoToInheritor(ISolution solution, IClass theClass, IDataContext dataContext, ITypeElement genericHandlerType)
{
    var inheritorsConsumer = new InheritorsConsumer();
    var searchDomainFactory = solution.GetComponent<SearchDomainFactory>();

    IDeclaredType theType = TypeFactory.CreateType(theClass);
    IDeclaredType commandHandlerType = TypeFactory.CreateType(genericHandlerType, theType);
    ITypeElement handlerTypeelement = commandHandlerType.GetTypeElement();
    solution.GetPsiServices().Finder.FindInheritors(handlerTypeelement, searchDomainFactory.CreateSearchDomain(solution, true),
        inheritorsConsumer, NullProgressIndicator.Instance);
    var potentialNavigationPoints = new List<INavigationPoint>();
    foreach (ITypeElement inheritedInstance in inheritorsConsumer.FoundElements)
    {
        IDeclaredType[] baseClasses = inheritedInstance.GetAllSuperTypes();
        foreach (IDeclaredType declaredType in baseClasses)
        {
            if (declaredType.IsInterfaceType())
            {
                if (declaredType.Equals(commandHandlerType))
                {
                    var navigationPoint = new DeclaredElementNavigationPoint(inheritedInstance);
                    potentialNavigationPoints.Add(navigationPoint);
                }
            }
        }
    }

    if (potentialNavigationPoints.Any())
    {
        NavigationOptions options = NavigationOptions.FromDataContext(dataContext, "Which handler do you want to navigate to?");
        NavigationManager.GetInstance(solution).Navigate(potentialNavigationPoints, options);
    }
} 

public class InheritorsConsumer : IFindResultConsumer<ITypeElement>
{
    private const int MaxInheritors = 50;

    private readonly HashSet<ITypeElement> elements = new HashSet<ITypeElement>();

    public IEnumerable<ITypeElement> FoundElements
    {
        get { return elements; }
    } 

    public ITypeElement Build(FindResult result)
    {
        var inheritedElement = result as FindResultInheritedElement;
        if (inheritedElement != null)
            return (ITypeElement) inheritedElement.DeclaredElement;
        return null;
    }

    public FindExecution Merge(ITypeElement data)
    {
        elements.Add(data);
        return elements.Count < MaxInheritors ? FindExecution.Continue : FindExecution.Stop;
    }
}

And this allows me no navigate to multiple handlers if they exist. This currently relies on the interfaces for the handled type and the handler type being in the same assembly. But this seems reasonable enough for me at the moment.

这篇关于创建一个泛型类型,找到实现在ReSharper的插件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆