簡體   English   中英

如何使用 Roslyn 在給定的命名空間上下文中獲取任意類型的最完全簡化的類型名稱?

[英]How can I get the most fully reduced type name of an arbitrary type in a given namespace context using Roslyn?

我正在編寫一個 function ,它采用任何具體或構造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()與幾個不同的選項一起使用,但我找不到不從語義 model 返回 null 的類型節點。

如何使用 SymbolDisplayFormat 格式化 TypeSyntax?

此外,我希望這改變System.Int32 -> int ,但是,它不會自動修復Nullable<T>ValueTuple<T1...>的實例

如何執行適當的代碼分析規則來替換這些類型名稱?

文檔 state 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM