c# - 创建通用类型以在 Resharper 插件中查找实现

标签 c# resharper resharper-8.0 resharper-plugins

我正在为 resharper 编写一个插件,我想用它从 ConcreteCommand 导航-> ConcreteCommandHandler这些类型看起来像这样

public class ConcreteCommand : ICommand

public class ConcreteCommandHandler : ICommandHandler<ConcreteCommand>

当光标位于 ICommand 上时,我已经添加了我的导航菜单选项。实例/定义(目前仅通过检查名称是否包含“Command”而不是“CommandHandler”),我认为我有必要的代码来实际搜索继承某些东西的类型,但我的问题是我实际上唯一的事情有一个类型是我的 ConcereteCommand我需要创建(或获取对)泛型类型 ICommandHandler<T>T是光标当前所在的类型。

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

  • 如何检查我的 IDeclaredElement是特定接口(interface)的实现(理想情况下通过在配置字符串中指定全名)?
  • 如何创建 ITypeElement这是一个特定接口(interface)的泛型类型,我可以从现有的 IDeclaredElement 中设置泛型类型s 类型,所以我可以找到继承它的类?

我现有的代码如下所示:

[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");
    }
}

最佳答案

好的,在@CitizenMatt 的正确方向插入下,成功地解决了这个问题。

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

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;
    }
}

这让我无法导航到多个处理程序(如果存在)。这目前依赖于处理类型的接口(interface)和位于同一程序集中的处理程序类型。但目前这对我来说似乎足够合理。

关于c# - 创建通用类型以在 Resharper 插件中查找实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30918419/

相关文章:

c# - 如何创建跨进程工作的类级互斥量

c# - 您将加密 key 放在面向公众的服务器上的什么位置?

c# - resharper提取界面变灰

visual-studio-2008 - 如何将所有类提取到单独的文件中?

c# - 是否可以将 Resharper Intellisense 配置为按字母顺序排序?

c# - 将方法执行移动到单独的线程并接收返回值

c# - Null 条件运算符仅计算一次

c# - 为什么 ReSharper 建议在动态类型上可能出现 NullReferenceException?

c# - 是否可以找到特定类型的 SomeMethod<T> 用法?