C# 从Roslyn ClassDeclarationSyntax获取类全名(包括命名空间)

C# 从Roslyn ClassDeclarationSyntax获取类全名(包括命名空间),c#,roslyn,C#,Roslyn,我有一个来自roslyn语法树的ClassDeclarationSyntax。 我是这样读的: var tree = SyntaxTree.ParseText(sourceCode); var root = (CompilationUnitSyntax)tree.GetRoot(); var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>(); var-tree=SyntaxTree.ParseTex

我有一个来自roslyn语法树的ClassDeclarationSyntax。 我是这样读的:

var tree = SyntaxTree.ParseText(sourceCode);
var root = (CompilationUnitSyntax)tree.GetRoot();

var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
var-tree=SyntaxTree.ParseText(源代码);
var root=(CompilationUnitSyntax)tree.GetRoot();
var classes=root.degenantNodes().OfType();
标识符仅包含类的名称,但不包含有关命名空间的信息,因此缺少fullType名称。像“MyClass”,但没有“Namespace1.MyClass”


获取语法的名称空间/FulltypeName的推荐方法是什么?

以下是获取名称空间的方法。您必须为您的案例稍微修改我的代码:

        public static async Task<NamespaceDeclarationSyntax> GetNamespaceAsync(this Document document, CancellationToken cancellationToken = default(CancellationToken))
        {
            SyntaxNode documentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var rootCompUnit = (CompilationUnitSyntax)documentRoot;
            return (NamespaceDeclarationSyntax)rootCompUnit.Members.Where(m => m.IsKind(SyntaxKind.NamespaceDeclaration)).Single();
        }
公共静态异步任务GetNamespaceAsync(此文档,CancellationToken CancellationToken=default(CancellationToken)) { SyntaxNode documentRoot=await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var rootCompUnit=(CompilationUnitSyntax)documentRoot; return(NamespaceDeclarationSyntax)rootCompUnit.Members.Where(m=>m.IsKind(SyntaxKind.NamespaceDeclaration)).Single(); }
您可以使用我编写的helper类执行此操作:

NamespaceDeclarationSyntax namespaceDeclarationSyntax = null;
if (!SyntaxNodeHelper.TryGetParentSyntax(classDeclarationSyntax, out namespaceDeclarationSyntax))
{
    return; // or whatever you want to do in this scenario
}

var namespaceName = namespaceDeclarationSyntax.Name.ToString();
var fullClassName = namespaceName + "." + classDeclarationSyntax.Identifier.ToString();
和助手:

static class SyntaxNodeHelper
{
    public static bool TryGetParentSyntax<T>(SyntaxNode syntaxNode, out T result) 
        where T : SyntaxNode
    {
        // set defaults
        result = null;

        if (syntaxNode == null)
        {
            return false;
        }

        try
        {
            syntaxNode = syntaxNode.Parent;

            if (syntaxNode == null)
            {
                return false;
            }

            if (syntaxNode.GetType() == typeof (T))
            {
                result = syntaxNode as T;
                return true;
            }

            return TryGetParentSyntax<T>(syntaxNode, out result);
        }
        catch
        {
            return false;
        }
    }
}
静态类SyntaxNodeHelper
{
公共静态bool TryGetParentSyntax(SyntaxNode SyntaxNode,out T结果)
其中T:SyntaxNode
{
//设置默认值
结果=空;
if(syntaxNode==null)
{
返回false;
}
尝试
{
syntaxNode=syntaxNode.Parent;
if(syntaxNode==null)
{
返回false;
}
if(syntaxNode.GetType()==typeof(T))
{
结果=作为T的syntaxNode;
返回true;
}
返回TryGetParentSyntax(syntaxNode,out结果);
}
抓住
{
返回false;
}
}
}
这里没有什么过于复杂的事情发生。。。名称空间将位于语法树的“上方”(因为类包含在名称空间中),因此您只需在语法树的“上方”移动,直到找到名称空间并将其附加到
ClassDeclarationSyntax
的标识符,然后尝试以下代码

public static string GetFullName(NamespaceDeclarationSyntax node)
{
    if (node.Parent is NamespaceDeclarationSyntax)
        return String.Format("{0}.{1}",
            GetFullName((NamespaceDeclarationSyntax)node.Parent),
            ((IdentifierNameSyntax)node.Name).Identifier.ToString());
    else
        return ((IdentifierNameSyntax)node.Name).Identifier.ToString();
}

我知道我在游戏中已经很晚了,但在我处理嵌套类的情况下,我偶然发现了不起作用的方法。因此,这里有一个方法也可以处理嵌套类:

public static class ClassDeclarationSyntaxExtensions
{
    public const string NESTED_CLASS_DELIMITER = "+";
    public const string NAMESPACE_CLASS_DELIMITER = ".";

    public static string GetFullName(this ClassDeclarationSyntax source)
    {
        Contract.Requires(null != source);

        var items = new List<string>();
        var parent = source.Parent;
        while (parent.IsKind(SyntaxKind.ClassDeclaration))
        {
            var parentClass = parent as ClassDeclarationSyntax;
            Contract.Assert(null != parentClass);
            items.Add(parentClass.Identifier.Text);

            parent = parent.Parent;
        }

        var nameSpace = parent as NamespaceDeclarationSyntax;
        Contract.Assert(null != nameSpace);
        var sb = new StringBuilder().Append(nameSpace.Name).Append(NAMESPACE_CLASS_DELIMITER);
        items.Reverse();
        items.ForEach(i => { sb.Append(i).Append(NESTED_CLASS_DELIMITER); });
        sb.Append(source.Identifier.Text);

        var result = sb.ToString();
        return result;
    }
}
公共静态类ClassDeclarationSyntaxExtensions
{
公共常量字符串嵌套_类_分隔符=“+”;
公共常量字符串名称空间_类_分隔符=“.”;
公共静态字符串GetFullName(此ClassDeclarationSyntax源)
{
Contract.Requires(null!=源);
var items=新列表();
var parent=source.parent;
while(parent.IsKind(SyntaxKind.ClassDeclaration))
{
var parentClass=parent作为ClassDeclarationSyntax;
Assert(null!=父类);
添加(parentClass.Identifier.Text);
父=父。父;
}
var nameSpace=parent as namespacedclarationsyntax;
Assert(null!=命名空间);
var sb=new StringBuilder().Append(nameSpace.Name).Append(nameSpace\u CLASS\u分隔符);
items.Reverse();
items.ForEach(i=>{sb.Append(i).Append(嵌套的类分隔符);});
sb.Append(source.Identifier.Text);
var result=sb.ToString();
返回结果;
}
}
基于,我添加了对嵌套名称空间、结构和泛型的支持

它使用允许将输出用作的输入

公共静态类TypeDeclarationSyntaxExtensions
{
常量字符嵌套_类_分隔符='+';
常量字符名称空间_类_分隔符='';
const char TYPEPARAMETER_CLASS_DELIMITER='`';
公共静态字符串GetFullName(此TypeDeclarationSyntax源)
{
if(源为空)
抛出新ArgumentNullException(nameof(source));
var namespaces=newlinkedlist();
var types=newlinkedlist();
for(var parent=source.parent;parent=object;parent=parent.parent)
{
if(父项为NamespaceDeclarationSyntax@namespace)
{
namespace.AddFirst(@namespace);
}
else if(父项为TypeDeclarationSyntax类型)
{
类型。AddFirst(类型);
}
}
var result=新的StringBuilder();
for(var item=namespaces.First;item为object;item=item.Next)
{
Append(item.Value.Name).Append(名称空间\类\分隔符);
}
for(var item=types.First;item为object;item=item.Next)
{
var类型=项目价值;
AppendName(结果、类型);
追加(嵌套的类分隔符);
}
附录名称(结果、来源);
返回result.ToString();
}
静态无效AppendName(StringBuilder生成器,TypeDeclarationSyntax类型)
{
builder.Append(type.Identifier.Text);
var typeArguments=type.TypeParameterList?.ChildNodes()
.Count(节点=>节点为TypeParameterSyntax)??0;
if(类型参数!=0)
Append(类型参数\类\分隔符).Append(类型参数);
}
}

还有一个答案。。该实用程序类还支持嵌套的名称空间和嵌套的类

公共静态类SyntaxNodeHelper
{
公共静态字符串GetPrefix(SyntaxNode成员)
{
if(成员==null){
返回“”;
}
StringBuilder sb=新的StringBuilder();
SyntaxNode=成员;
while(node.Parent!=null){
node=node.Parent;
if(节点为NamespaceDeclarationSyntax){
变量namespaceDeclaration=(namespaceDeclaration)
public static class TypeDeclarationSyntaxExtensions
{
    const char NESTED_CLASS_DELIMITER = '+';
    const char NAMESPACE_CLASS_DELIMITER = '.';
    const char TYPEPARAMETER_CLASS_DELIMITER = '`';

    public static string GetFullName(this TypeDeclarationSyntax source)
    {
        if (source is null)
            throw new ArgumentNullException(nameof(source));

        var namespaces = new LinkedList<NamespaceDeclarationSyntax>();
        var types = new LinkedList<TypeDeclarationSyntax>();
        for (var parent = source.Parent; parent is object; parent = parent.Parent)
        {
            if (parent is NamespaceDeclarationSyntax @namespace)
            {
                namespaces.AddFirst(@namespace);
            }
            else if (parent is TypeDeclarationSyntax type)
            {
                types.AddFirst(type);
            }
        }

        var result = new StringBuilder();
        for (var item = namespaces.First; item is object; item = item.Next)
        {
            result.Append(item.Value.Name).Append(NAMESPACE_CLASS_DELIMITER);
        }
        for (var item = types.First; item is object; item = item.Next)
        {
            var type = item.Value;
            AppendName(result, type);
            result.Append(NESTED_CLASS_DELIMITER);
        }
        AppendName(result, source);

        return result.ToString();
    }

    static void AppendName(StringBuilder builder, TypeDeclarationSyntax type)
    {
        builder.Append(type.Identifier.Text);
        var typeArguments = type.TypeParameterList?.ChildNodes()
            .Count(node => node is TypeParameterSyntax) ?? 0;
        if (typeArguments != 0)
            builder.Append(TYPEPARAMETER_CLASS_DELIMITER).Append(typeArguments);
    }
}