【问题标题】:Find types that inherit from given INamedTypeSymbol查找从给定 INamedTypeSymbol 继承的类型
【发布时间】:2015-08-28 01:50:46
【问题描述】:

给定一个INamedTypeSymbol(来自引用的程序集,而不是源代码)我如何找到从该类型继承的所有类型(在源程序集和引用的程序集中)?

在我的特殊情况下,我正在寻找从NUnit.Framework.TestAttribute 继承的所有类型。我可以按如下方式访问命名类型符号:

var ws = MSBuildWorkspace.Create();
var soln = ws.OpenSolutionAsync(@"C:\Users\...\SampleInheritanceStuff.sln").Result;
var proj = soln.Projects.Single();
var compilation = proj.GetCompilationAsync().Result;

string TEST_ATTRIBUTE_METADATA_NAME = "NUnit.Framework.TestAttribute";
var testAttributeType = compilation.GetTypeByMetadataName(TEST_ATTRIBUTE_METADATA_NAME);

//Now how do I find types that inherit from this type?

我看过SymbolFinderCompilationINamedTypeSymbol,但我没有运气。

编辑:FindDerivedClassesAsync 方法看起来很接近我的需要。 (我不是 100% 确定它在引用的程序集中找到派生类)。不过它是内部的,所以我打开了an issue

【问题讨论】:

  • 你能引用“Assembly”对象吗?
  • 如果您可以拥有程序集对象,您可以使用 GetTypies 方法并使用 IsAssignableFrom 方法进行过滤
  • 获得Assembly 对象并不容易,而且我知道可以使用反射,但我更喜欢使用Roslyn。

标签: c# roslyn


【解决方案1】:

FindDerivedClassesAsync 确实是您正在寻找的。
它在引用的程序集中查找派生类,正如您在DependentTypeFinder 的源代码中看到的那样(注意locationsInMetadata 变量)。

至于使用它,你可以随时通过反射来做:

 private static readonly Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>> FindDerivedClassesAsync
            = new Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>>(() => (Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>)Delegate.CreateDelegate(typeof(Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>), DependentTypeFinder.Value.GetMethod("FindDerivedClassesAsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)));

(code borrowed from Tunnel Vision Laboratories Github)

祝你好运!

更新:

这个方法现在已经公开了。 (source)

【讨论】:

  • 我给了你赏金(但不是答案),因为这是我见过的最接近的方法。不幸的是,这个 API 似乎没有在引用的程序集中找到派生类型。
  • 我今天测试了这个,它似乎也在引用的程序集中找到了派生类型。
【解决方案2】:

您可以使用 Compilation 中公开的 SemanticModel 获取此信息

public static IEnumerable<INamedTypeSymbol> GetBaseClasses(SemanticModel model, BaseTypeDeclarationSyntax type)
    {
        var classSymbol = model.GetDeclaredSymbol(type);
        var returnValue = new List<INamedTypeSymbol>();
        while (classSymbol.BaseType != null)
        {
            returnValue.Add(classSymbol.BaseType);
            if (classSymbol.Interfaces != null)
            returnValue.AddRange(classSymbol.Interfaces);
            classSymbol = classSymbol.BaseType;
        }
        return returnValue;
    }

这将为您提供所有基类以及每个基类实现的每个接口的列表。然后,您可以过滤到您感兴趣的 INamedTypeSymbol:

        public static IEnumerable<BaseTypeDeclarationSyntax>
              FindClassesDerivedOrImplementedByType(Compilation compilation
        , INamedTypeSymbol target)
    {
        foreach (var tree in compilation.SyntaxTrees)
        {
            var semanticModel = compilation.GetSemanticModel(tree);

            foreach (var type in tree.GetRoot().DescendantNodes()
                        .OfType<TypeDeclarationSyntax>())
            {
                var baseClasses = GetBaseClasses(semanticModel, type);
                if (baseClasses != null)
                    if (baseClasses.Contains(target))
                        yield return type;
            }
        } 
    }

【讨论】:

    猜你喜欢
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 2021-01-23
    • 2019-07-11
    • 2015-02-05
    • 1970-01-01
    相关资源
    最近更新 更多