【问题标题】:Determining if a field is serializable with Roslyn使用 Roslyn 确定字段是否可序列化
【发布时间】:2019-08-07 14:14:17
【问题描述】:

我几乎找不到关于 Roslyn 的好文档,如果我遗漏了什么,请原谅我,这应该是显而易见的。 我正在解析一些代码,我的目标是从一个类中提取每个可序列化的字段。

到目前为止,我所拥有的是这个。首先我解析代码文件

            SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
            CSharpCompilation compilation = CSharpCompilation.Create("HelloWorld")
                                                             .AddReferences(MetadataReference
                                                                                .CreateFromFile(typeof(object)
                                                                                                .Assembly
                                                                                                .Location))
                                                             .AddSyntaxTrees(tree);

            CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

接下来,我得到每个类的所有字段

        foreach (MemberDeclarationSyntax member in root.Members)
        {
            if (member is ClassDeclarationSyntax classDeclarationSyntax)
            {

                foreach (MemberDeclarationSyntax rootGameMember in classDeclarationSyntax.Members)
                {
                    if (IsFieldSerializable(rootGameMember))
                    {
                    }
                }
            }
        }

aaaaand 现在我被困住了。我想对这个字段做一些基于 Unity 3D 序列化规则的事情

  • 查看类型是否公开
  • 查看是否应用了属性[SerializeField]
  • 查看类型是int、float、string、double等
  • 查看类型,如果它的类具有[Serializable]属性

我想就是这样。目前,我正试图弄清楚该领域的类型,并迷失在一堆选项中,似乎没有一个能满足我的需求。

【问题讨论】:

    标签: c# roslyn roslyn-code-analysis


    【解决方案1】:

    您需要做的第一件事是获取代表您的字段的符号,您可以使用SemanticModel 类来完成。我认为这将有助于解释如何根据您的示例获得语义模型:

    https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Semantic-Analysis

    TLDR:使用compilation.GetSemanticModel()

    这个问题比我原来的答案回答了如何做到这一点,所以请看这里:

    How to get a Roslyn FieldSymbol from a FieldDeclarationSyntax node?

    现在您已经掌握了有关该领域的语义信息,让我们一次一个地查看每个问题。

    1) 查看类型是否为public

    这应该很简单,因为IFieldSymbol 接口有一个DeclaredAccessibility 属性,它会告诉你你需要知道什么!

    if(fieldSymbol.DeclaredAccessibility != Accessibility.Public)
    {
        // not interested in no-public members
    }
    

    2) 查看属性[SerializeField]是否被应用

    使用IFieldSymbol接口的GetAttributes()方法。然后你可以像查询其他INamedTypeSymbol 一样查询属性的AttributeClass

    var attributes = fieldSymbol.GetAttributes();
    if(!attributes.Any(attribute => attribute.AttributeClass.Name == "SerializeField"))
    {
        // only interested in fields with the SerializeField attribute
    }
    

    3) 查看类型是否为intfloatstringdouble

    幸运的是,Type 也是IFieldSymbol 接口的属性,所以我们可以检查字段符号的属性。如果您只关心简单类型,则可以引用生成的ITypeSymbolName 属性。

    var fieldTypes = new List<string> { "int", "float", "string", "double" };
    
    if(!fieldTypes.Contains(fieldSymbol.Type.Name))
    {
        // only interested in certain types
    }
    

    (您可能需要在调试器中仔细检查类型名称字符串)

    4) 查看类型,如果它的类具有[Serializable] 属性

    从这里我猜你的意思是这个类有[Serializable] 属性。为此,您可以使用与 2 相同的方法,但需要类符号,因此必须在字段检查功能之外完成。

    var classSymbol = model.GetSymbolInfo(classDeclarationSyntax).Symbol;
    // remember to null check this
    var attributes = classSymbol.GetAttributes();
    if(attributes.Any(attribute => attribute.AttributeClass.Name == "Serializable"))
    {
       // class is serializable
    }
    

    编辑: 如果您认为按名称检查属性有点 hacky,这个答案也可能对您有所帮助!

    Roslyn Check Type of an Attribute

    IFieldSymbol:

    https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.ifieldsymbol?view=roslyn-dotnet

    INamedTypeSymbol

    https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.inamedtypesymbol?view=roslyn-dotnet

    顺便说一句,我完全同意,好的 Roslyn 文档似乎非常罕见。

    【讨论】:

    • 非常感谢您的详细回答。这是一个很大的帮助。现在我正在努力获取字段符号。那将是我猜测的两件事之一。类型是public List&lt;MyClass&gt;,所以 SemanticModel 不知道 List 或者它不知道 MyClass。我的代码库是从众多文件中解析出来的,所以我想我需要将它们全部包含在CSharpSyntaxTree.ParseText 中,而不仅仅是第一个文件。如果问题是列表,那么我不知道如何解决它。
    • 您需要列表符号中的TypeArguments。语义模型中的GetDeclaredSymbol 也值得使用。(docs.microsoft.com/en-us/dotnet/api/…)
    猜你喜欢
    • 2021-12-06
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 2013-09-07
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 2014-04-14
    相关资源
    最近更新 更多