检查 IPropertySymbol 是否有支持字段

Check if IPropertySymbol has a backing field

几天前我开始玩 roslyn,我正在尝试编写一个扩展方法来判断 IPropertySymbol 是否有支持字段,所以我认为 属性 有一个支持字段如果并且仅当以下情况不适用时(就我而言):

所以我想到了

public static bool HasBackingField(this IPropertySymbol property)
        {
            return !(property.IsAbstract || property.IsExtern || property.IsReadOnly);
        }

我的问题是

启动示例

                var code = 
                @"class XYZ
                   {
                      public int x => 4;                                  //HasBacking field : false IsReadOnly

                      public int m { get { return 0;}}                    //HasBacking field : false IsReadOnly     

                      public int y { get; set; }                          //HasBacking field : false Null body for setter or getter

                      public int z { get { return 0; } set { } }          //HasBacking field : false Empty body for setter or getter

                      private int _g;
                      public int g                                        //HasBacking field : true Getter and Setter has no empty Bodies
                       {
                           get { return _g; }
                           set { _g = value; }
                       }
                  }";

            var syntaxTree = CSharpSyntaxTree.ParseText(code);
            var compilation = CSharpCompilation.Create("xxx").AddSyntaxTrees(syntaxTree);
            var classSymbol = compilation.GetTypeByMetadataName("XYZ");
            var propSymbols = classSymbol.GetMembers().OfType<IPropertySymbol>();
            var results = propSymbols.Select(ps => ps.HasBackingField()); //should be [false false false false true]

我决定查看语法表示而不是实际符号 -- 语法比符号处于较低级别并且包含我们感兴趣的原始信息:查看单个语句。

这似乎是您感兴趣的内容:

internal static bool HasBackingField(this PropertyDeclarationSyntax property)
{
    var getter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.GetAccessorDeclaration));
    var setter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.SetAccessorDeclaration));

    if (setter?.Body == null || getter?.Body == null)
    {
        return false;
    }

    bool setterHasBodyStatements = setter.Body.Statements.Any();
    bool getterHasBodyStatements = getter.Body.Statements.Any();

    return setterHasBodyStatements && getterHasBodyStatements;
}

请注意,我不相信这足以得出存在可用支持字段的结论,但它遵循您的想法,即检查是否有主体。

我没有添加您想要的其他检查,但可以轻松添加这些检查(使用您已经使用的符号或查看 PropertyDeclarationSyntax 其 modifiers/attributes)。

---

完整代码自行测试:

public static void Execute()
{
    var code =
@"class XYZ
{
  public int x => 4;                                  //HasBacking field : false IsReadOnly

  public int m { get { return 0;}}                    //HasBacking field : false IsReadOnly     

  public int y { get; set; }                          //HasBacking field : false Null body for setter or getter

  public int z { get { return 0; } set { } }          //HasBacking field : false Empty body for setter or getter

  private int _g;
  public int g                                        //HasBacking field : true Getter and Setter has no empty Bodies
   {
       get { return _g; }
       set { _g = value; }
   }
}";

    var tree = CSharpSyntaxTree.ParseText(code);
    var root = tree.GetRoot();

    foreach (var prop in root.DescendantNodes().OfType<PropertyDeclarationSyntax>())
    {
        Console.WriteLine(prop.HasBackingField());
    }
}
    }

internal static class Extensions
{
    internal static bool HasBackingField(this PropertyDeclarationSyntax property)
    {
        var getter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.GetAccessorDeclaration));
        var setter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.SetAccessorDeclaration));

        if (setter?.Body == null || getter?.Body == null)
        {
            return false;
        }

        bool setterHasBodyStatements = setter.Body.Statements.Any();
        bool getterHasBodyStatements = getter.Body.Statements.Any();

        return setterHasBodyStatements && getterHasBodyStatements;
    }
}