是否可以从Project MetaDataReferences获取实现细节?

时间:2017-03-02 09:47:19

标签: c# reflection roslyn

从通过MSBuildWorkspace获得的解决方案获得Project p,是否可以获得该项目的详细信息MetadataReferences(在这种情况下它是一个.dll),例如类和方法?

3 个答案:

答案 0 :(得分:1)

我找到了一种通过Micrososoft.CodeAnalysis Symbol Api获取类和方法的方法,它非常受到msdn博客中Kevin Pilch-Bisson帖子的启发。

private void GetSymbolsTest(ref Project project, ref MetadataReference metaRef)
    {
        if (!project.MetadataReferences.Contains(metaRef))
            throw new DllNotFoundException("metadatarefence not in project");

        var compilation = project.GetCompilationAsync().Result;
        var metaRefName = Path.GetFileNameWithoutExtension(metaRef.Display);

        SymbolCollector symCollector = new SymbolCollector();
        symCollector.Find(compilation.GlobalNamespace, metaRefName);
        Console.WriteLine($"Classes found: {symCollector.Classes.Count}");
        Console.WriteLine($"Methods found: {symCollector.Methods.Count}");
    }


public class SymbolCollector
{
    public HashSet<IMethodSymbol> Methods { get; private set; } = new HashSet<IMethodSymbol>();
    public HashSet<INamedTypeSymbol> Classes { get; private set; } = new HashSet<INamedTypeSymbol>();

    public void Find(INamespaceSymbol namespaceSymbol, string assemblyRefName)
    {
        foreach (var type in namespaceSymbol.GetTypeMembers())
        {
            if (String.Equals(type.ContainingAssembly.Name, assemblyRefName, StringComparison.CurrentCultureIgnoreCase))
                Find(type);
        }

        foreach (var childNs in namespaceSymbol.GetNamespaceMembers())
        {
            Find(childNs, assemblyRefName);
        }
    }

    private void Find(INamedTypeSymbol type)
    {
        if (type.Kind == SymbolKind.NamedType)
            Classes.Add(type);

        foreach (var member in type.GetMembers())
        {
            if (member.Kind == SymbolKind.Method)
                Methods.Add(member as IMethodSymbol);
        }

        foreach (var nested in type.GetTypeMembers())
        {
            Find(nested);
        }
    }
}

这样我就不需要使用System.Reflection。希望它能帮到某个人。

答案 1 :(得分:1)

在项目中,调用GetCompilationAsync()以获取编译。从那里,您可以查看GlobalNamespace属性,该属性为您提供全局命名空间,您可以在其中从代码中走到子命名空间和类型,并将所有引用合并在一起。如果你想在特定的引用中遍历类型,你可以调用GetAssemblyOrModuleSymbol给它一个特定的元数据引用,然后你也可以从那里走。

答案 2 :(得分:0)

foreach (var mRef in project.MetadataReferences)
{
    Type[] assemblyTypes;

    if (!File.Exists(mRef.Display))
        continue;

    try
    {
        assemblyTypes = Assembly.ReflectionOnlyLoadFrom(mRef.Display)
                                .GetTypes();
    }
    catch (ReflectionTypeLoadException e)
    {
        assemblyTypes = e.Types
                         .Where(type => type != null)
                         .ToArray();
    }
    // ....
}