获取当前项目中的所有 IDeclaredType-s(对于 ReSharper Generator 插件)

Posted

技术标签:

【中文标题】获取当前项目中的所有 IDeclaredType-s(对于 ReSharper Generator 插件)【英文标题】:Get all IDeclaredType-s in current project (for a ReSharper Generator plugin) 【发布时间】:2015-01-18 02:30:21 【问题描述】:

我正在编写一个 ReSharper 7.1 Generator 插件,需要获取当前项目中为 GeneratorProviderBase<CSharpGeneratorContext>.Populate 方法声明的所有类型(类、接口和结构 - IDeclaredType-s)的列表。

使用常规反射,它就像Assembly.GetTypes() 一样简单,但在这里它被证明是一个相当大的挑战。有没有办法做到这一点?

我搜索了高低,文档和示例都没有帮助,然后查看了每个 *Extensions*Util 类,但找不到任何有用的东西...

【问题讨论】:

【参考方案1】:

我设法做我需要的,但我不确定这是否是正确/最佳的方法:

[GeneratorElementProvider("MyGeneratorProvider", typeof(CSharpLanguage))]
public class MyGeneratorProvider : GeneratorProviderBase<CSharpGeneratorContext>

    public override double Priority
    
        get  return 0; 
    

    public override void Populate(CSharpGeneratorContext context)
    
        var projectCsFiles = GetAllCSharpFilesInProject(context.PsiModule);
        var declarations = projectCsFiles.SelectMany(GetDeclarationsFromCSharpFile).ToList();
        context.ProvidedElements.AddRange(declarations.Select(d => new GeneratorDeclarationElement(d)));
    

    private static IEnumerable<ICSharpFile> GetAllCSharpFilesInProject(IPsiModule projectModule)
    
        PsiManager psiManager = projectModule.GetPsiServices().PsiManager;
        return projectModule.SourceFiles.SelectMany(f => psiManager.GetPsiFiles<CSharpLanguage>(f).OfType<ICSharpFile>());
    

    private static IEnumerable<ITypeDeclaration> GetDeclarationsFromCSharpFile(ICSharpFile file)
    
        return file.NamespaceDeclarationNodes.SelectMany(GetDeclarationsFromCSharpNamespace);
    

    private static IEnumerable<ITypeDeclaration> GetDeclarationsFromCSharpNamespace(ICSharpNamespaceDeclaration namespaceDeclaration)
    
        foreach (var namespaceChild in namespaceDeclaration.Body.Children())
        
            var classDeclaration = namespaceChild as IClassDeclaration;
            if (classDeclaration != null)
            
                yield return classDeclaration;
            
            else
            
                var childNamespace = namespaceChild as ICSharpNamespaceDeclaration;
                if (childNamespace != null)
                
                    foreach (var declaration in GetDeclarationsFromCSharpNamespace(childNamespace))
                    
                        yield return declaration;
                    
                
            
        
    

有任何 cmets 或更简单(甚至可能是内置)的方法吗?

【讨论】:

这当然是一个剥离版本,为简洁起见,删除了所有检查和附加条件和转换。 这将非常慢,项目越大 - 您正在遍历每个文件。我手头没有 7.1,但你应该可以从 ReSharper 的 caches 获得这些信息 感谢您的意见,马特!缓存是我看的第一件事,但它的短名称似乎没有太大帮助:在调试会话期间,我看到它有 8000 多个项目,用于仅包含 2 个 cs 文件的项目。大多数名称来自引用的程序集,而不是类,所以我觉得获取这些名称并通过它们会很慢。无论如何,我会再试一次。 您可以查看CacheManager.GetDeclarationsCache 并传入DeclarationCacheLibraryScope.NONE。这应该会返回一个IDeclarationsCache,它只引用解决方案中的项目,而不包括任何库。 啊哈,不知道我怎么错过了...谢谢马特!【参考方案2】:

这是我想出的使用缓存的方法。它似乎仍然不正确,但我希望它比以前的方法更好。这仍然是从GeneratorProvider.Populate 调用的:

public static IEnumerable<ICSharpTypeDeclaration> GetAllPublicTypeDeclarations(this IPsiModule module)

    var declarationCache = module.GetPsiServices().CacheManager.GetDeclarationsCache(module, false, true);
    var declarations = new List<ICSharpTypeDeclaration>();

    foreach (var shortName in declarationCache.GetAllShortNames())
    
        var declaredElements = declarationCache.GetElementsByShortName(shortName).OfType<ITypeElement>().Where(e => 
        
            var elementType = e.GetElementType();
            return elementType == CLRDeclaredElementType.CLASS || elementType == CLRDeclaredElementType.INTERFACE || elementType == CLRDeclaredElementType.ENUM;
        );

        foreach (ITypeElement declaredElement in declaredElements)
        
            var declaration = declaredElement.GetDeclarations().OfType<ICSharpTypeDeclaration>().FirstOrDefault(d => d.GetAccessRights() == AccessRights.PUBLIC);
            if (declaration != null)
            
                declarations.Add(declaration);
            
        
    

    return declarations;

注意:结果与第一个答案不同,因为我更改了一些限制。此外,在这两种情况下,我都不关心部分类。

【讨论】:

以上是关于获取当前项目中的所有 IDeclaredType-s(对于 ReSharper Generator 插件)的主要内容,如果未能解决你的问题,请参考以下文章

无法根据日期字段获取记录 = jhipster 中的当前日期

如果使用分页,如何获取 radlistview 项目

如何在Bitbucket中获取所有repos /所有项目的代码行

有没有办法使用 gitlab python api 从 gitlab 项目中获取当前和旧用户名?

如何在视图绑定中的活动中获取回收者视图当前项目文本值

R语言使用data函数获取当前R环境可用的示例数据集:获取datasets包中的所有示例数据集获取所有包的数据集获取特定包的数据集