检查IPropertySymbol是否有支持字段

时间:2016-01-17 01:51:57

标签: c# roslyn

我几天前开始和roslyn一起玩,我正在尝试编写一个扩展方法,告诉public static bool HasBackingField(this IPropertySymbol property) { return !(property.IsAbstract || property.IsExtern || property.IsReadOnly); } 是否有一个支持字段,所以我认为一个属性有一个支持字段,当且仅当以下情况不适用(据我所知):

  • IF摘要
  • 如果它是外部的
  • 如果是ReadOnlyProperty
  • 如果Getter或Setter没有Body或Empty body

所以我想出了

GetMethod

我的问题是

  • 我是否错过任何条件?
  • 我如何检查最后一个条件?我在SetMethod中找到了IPropertySymbol 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] 属性,但我不知道检查他们是否有身体

启动

的示例
   A SQLiteConnection object for database '//data//data//com.compapps.booster//databases//booster.db' was leaked!  Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.

1 个答案:

答案 0 :(得分:2)

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

这似乎做了你感兴趣的事情:

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其修饰符/属性)。

---

完整代码自行测试:

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;
    }
}