如何使用Roslyn在给定的命名空间上下文中获得任意类型的最完全缩减类型名?

问题描述 投票:3回答:1

我正在编写一个函数,该函数接收任何具体的或构造的 Type比如说 typeof(ValueTuple<Nullable<System.Int32>, double, List<string>) 并返回一个字符串,该字符串是该类型的简化C#语法表示(即在本例中的 (int?, double, List<string>) 在本例中)。)

这是我目前的成果。

public static string ToCSharpString(this Type type, string[] usingNamespaces = null, Assembly[] usingAssemblies = null)
{
    var compilationUnit = SyntaxFactory.CompilationUnit();
    if (usingNamespaces != null)
    {
        compilationUnit = compilationUnit.AddUsings(
            Array.ConvertAll(usingNamespaces, n => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(n))));
    }
    else
    {
        compilationUnit = compilationUnit.AddUsings(
            SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System")));
    }

    MetadataReference[] metadataReferences;
    if (usingAssemblies != null)
    {
        metadataReferences = Array.ConvertAll(usingAssemblies, u => MetadataReference.CreateFromFile(u.Location));
    }
    else
    {
        metadataReferences = new[]
        {
            MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
            MetadataReference.CreateFromFile(type.Assembly.Location)
        };
    }

    TypeSyntax typeName;
    using (var provider = new CSharpCodeProvider())
    {
        typeName = SyntaxFactory.ParseTypeName(provider.GetTypeOutput(new CodeTypeReference(type)));
    }

    var field = SyntaxFactory.FieldDeclaration(
        SyntaxFactory.VariableDeclaration(typeName).WithVariables(
            SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
                SyntaxFactory.VariableDeclarator(
                    SyntaxFactory.Identifier("field")))));
    compilationUnit = compilationUnit.AddMembers(
        SyntaxFactory.ClassDeclaration("MyClass").AddMembers(
            field))
        .NormalizeWhitespace();

    var tree = compilationUnit.SyntaxTree;
    var compilation = CSharpCompilation.Create("MyAssembly", new[] { tree }, metadataReferences);
    var semanticModel = compilation.GetSemanticModel(tree);
    var root = tree.GetRoot();

    var typeSymbol = semanticModel.GetDeclaredSymbol(compilationUnit
        .DescendantNodes().OfType<ClassDeclarationSyntax>().Single()
        .Members.OfType<FieldDeclarationSyntax>().Single()
        .Declaration.Type);

    return typeSymbol.ToDisplayString(new SymbolDisplayFormat(
        typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
        miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
}

我试图将一些已知的转换类型的方法串联起来。

  • 类型 -> 完全限定名
    • 通过CodeDOM的CSharpCodeProvider.GetTypeOutput实现的
  • 完全限定名称 -> TypeSyntax(类型语法)
    • 通过 Rosly 的 SyntaxFactory.ParseTypeName

现在我想用 .ToDisplayString() 有几个不同的选项,但我无法为我的类型找到一个不从语义模型中返回null的类型节点。

我如何使用SymbolDisplayFormat来格式化TypeSyntax?

此外,我希望这个 变化 System.Int32 -> int然而,它不会自动修复 Nullable<T>ValueTuple<T1...>

如何执行相应的代码分析规则来替换这些类型名?

c# roslyn roslyn-code-analysis
1个回答
2
投票

文档中写道 GetDeclaredSymbol 只适用于

源于MemberDeclarationSyntax、TypeDeclarationSyntax、EnumDeclarationSyntax、NamespaceDeclarationSyntax、ParameterSyntax、TypeParameterSyntax或UsingDirectiveSyntax的别名部分的任何类型。

你的似乎是 QualifiedNameSyntax 这似乎与预期的输入非常一致,但对 Roslyn 来说显然是另一种意思(我承认我没有费心检查它是否真的从预期的类型中继承)。

然而,得到 TypeInfo 而不是,似乎让你的特定例子工作。

    var typeSymbol = semanticModel.GetTypeInfo(compilationUnit // just changed this method
        .DescendantNodes().OfType<ClassDeclarationSyntax>().Single()
        .Members.OfType<FieldDeclarationSyntax>().Single()
        .Declaration.Type); 
    return typeSymbol.Type.ToDisplayString(new SymbolDisplayFormat(
        typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
        miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes)); // I'm getting "(int?, double, List)" here
© www.soinside.com 2019 - 2024. All rights reserved.