c# - 如何使用 Roslyn 在给定的命名空间上下文中获得任意类型的最完全简化的类型名称?

标签 c# roslyn roslyn-code-analysis

我正在编写一个函数,它接受任何具体的或构造的 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

  • 完全限定名称 -> 类型语法
  • 通过 Rosly 的 SyntaxFactory.ParseTypeName


  • 现在我想用 .ToDisplayString()有几个不同的选项,但我找不到不从语义模型返回 null 的类型节点。
    如何使用 SymbolDisplayFormat 格式化 TypeSyntax?
    另外,我预计这会改变System.Int32 -> int ,但是,它不会自动修复 Nullable<T> 的实例或 ValueTuple<T1...> 如何执行适当的代码分析规则来替换这些类型名称?

    最佳答案

    文档状态 GetDeclaredSymbol 只适用于

    any type derived from MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax, NamespaceDeclarationSyntax, ParameterSyntax, TypeParameterSyntax, or the alias part of a 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
    

    关于c# - 如何使用 Roslyn 在给定的命名空间上下文中获得任意类型的最完全简化的类型名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61945349/

    相关文章:

    c# - 在 C# 中获取键值对列表的所有可能组合

    C#如何计算排除特定日期的工作日(节假日)

    c# - 避免 VBCSCompiler 性能命中 Roslyn 支持的 ASP.NET Razor MVC View ?

    c# - 如何使用 Roslyn 获取编译时间常量值

    c# - Roslyn TypeDeclarationSyntax、MethodDeclarationSyntax、FieldDeclarationSyntax 具有公共(public)属性但没有公共(public)基类或接口(interface)

    c# - 单元测试返回 void 的方法

    c# - 组合框问题 : Cannot bind to new value member

    c# - CSharpAddImportCodeFixProvider 遇到错误并已被禁用

    c# - 如何使用 Roslyn 在 C# 中添加新运算符

    c# - 使用 roslyn 获取所有类型