创建一个泛型类型,找到实现在ReSharper的插件 [英] Create a generic type to find implementations of in a Resharper plugin
问题描述
我在写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 existingIDeclaredElement
s 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屋!