【问题标题】:C# Roslyn Compiler - How to get namespace of a type from IdentifierNameSyntax?C# Roslyn 编译器 - 如何从 IdentifierNameSyntax 获取类型的命名空间?
【发布时间】:2017-08-10 12:21:58
【问题描述】:

假设我在代码中有一个调用,SomeClass.SomeStaticMethod<T>(),它是一个 InvocationExpressionSyntax。

我将泛型类型 T 的名称作为字符串(来自 IdentifierNameSyntax)。我尝试获取 T 符号,但没有成功。

如何找到类型T的命名空间信息?

更新:@SJP 的回答是正确的。我想为那些想从 IdentifierNameSyntax 获取命名空间信息的人解释我的错误,其中包含一个类的标识符(类名):

我最初的目标是查找SomeClass.SomeMethod<T>() 格式的调用,并获取类型为 T 的命名空间信息。

var namedTypeSymbol = context.Symbol as INamedTypeSymbol;
var reference = nameTypeSymbol.DeclaringSyntaxReferences.First();
var classSyntaxTree = reference.SyntaxTree;

var semanticModel = context.Compilation.GetSemanticModel(classSyntaxTree);
var genericNameSyntax = (GenericNameSyntax)((MemberAccessExpressionSyntax)node.Expression).Name;
var identifierNameSyntax = genericNameSyntax.TypeArgumentList.Arguments.First();
var typeInfo = semanticModel.GetTypeInfo(identifierNameSyntax);
var nameSpace = ((INamedTypeSymbol)typeInfo.Type).ContainingNamespace;
var nameSpaceName = nameSpace.ToString();

这是我的错误:

我试图获得像 <module_name>.<namespace_part_1>.<namespace_part_2> 这样的完整命名空间,但是当我这样做时 namedTypeSymbol.ContainingNamespace.Name ,我只得到了 <namespace_part_2>。几个小时后,我发现获取完整的命名空间就像namedTypeSymbol.ContainingNamespace.ToString()

有时最好的办法就是到户外呼吸新鲜空气:)

【问题讨论】:

    标签: c# roslyn roslyn-code-analysis


    【解决方案1】:

    您将需要语义模型来完成您的任务。假设您需要 SomeClass 的命名空间,那么您可以通过访问表达式的名称字段从 MemberAccessExpressionSyntax 中获取类型和名称,如下所示:

    var semanticModel = await document.GetSemanticModelAsync()
    var name = (GenericNameSyntax)((MemberAccessExpressionSyntax)node.Expression).Name;
    var typeInfo = semanticModel.GetTypeInfo(name.TypeArgumentList.Arguments.First());
    var nameSpace = ((INamedTypeSymbol)typeInfo.Type).ContainingNamespace;
    var nameSpaceName = nameSpace.Name;
    

    对于以下示例程序,这将导致变量 nameSpaceName 为“System”或“ConsoleApp1”(取决于调用),而变量 nameSpace 可以访问所有其他信息。

    namespace ConsoleApp1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Program.DoStuff<string>();
                Program.DoStuff<Program>();
            }
    
            static void DoStuff<T>()
            {
    
            }
        }
    }
    

    【讨论】:

    • 是的,OP 需要语义模型。但是他需要调用本身的GetSymbolInfo,然后从IMethodSymbol 中获取第一个类型参数。我认为由于格式错误,问题之前并不清楚,但我现在解决了这个问题。
    • 非常感谢,我不知道所提问题的初衷。我相应地调整了代码。
    • @SJP 现在好多了
    • 首先,感谢@KrisVandermotten 的更正,问题不清楚,我现在意识到了。另外,感谢您提供详细,解释清楚的答案。但是,我仍然无法获取命名空间名称。我使用 SyntaxNodeAnalysisContext 作为上下文,当我做 context.SemanticModel.GetTypeInfo(identifierNameSyntax) 时,我只能得到泛型类型名称。当我尝试获取 (INamedTypeSymbol)typeInfo.Type).ContainingNamespace.Name 时,我得到的是“Interface”而不是“.”。
    • 我想我无法正确获取 SemanticModel。我无法像您那样获得“文档”,因为我正在为分析器编写代码。我的目标是以“SomeClass.SomeStaticMethod()”格式捕获调用,并在 T 与执行调用的类不在同一个命名空间中时发出警告。我希望我能更好地解释自己。提前感谢您的帮助。
    【解决方案2】:

    对 Function{SuppliedArgument}(...) 的调用将有一个 GenericNameSyntax 作为 {SuppliedArgument}。这与 TypeDeclaration.TypeParameterList.Parameters 不同。你不能从这些那里得到任何东西。它们是占位符。您需要遍历 GenericNameSyntax.TypeArgumentList,并在每个上使用 SemanticModel.GetSymbolInfo(identifierNameSyntax).Symbol.ContainingNamespace 来获取包含标识符的命名空间。

    【讨论】:

      猜你喜欢
      • 2015-06-11
      • 1970-01-01
      • 2015-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-05
      • 1970-01-01
      • 2016-08-16
      相关资源
      最近更新 更多