Check if IPropertySymbol has a backing field

I started playing with roslyn few days ago and i am trying to write an extension method which tells if an IPropertySymbol has a backing field, so i thought a property has a backing field if and only if the following does not apply(as far as i am concerned):

  • IF its Abstract
  • IF its Extern
  • IF its ReadOnlyProperty
  • IF the Getter or the Setter has no Body or Empty body

so i came up with

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

My questions are

  • Did i miss any condition?
  • How do i check for the last condition? i found GetMethod and SetMethodproperties in IPropertySymbol but i don't know to check if they have a body

example to start up with

                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]

Answers


I decided to look at the syntax representation rather than the actual symbol -- the syntax is at a lower level than the symbol and contains the raw information we're interested in: looking at individual statements.

This seems to do what you're interested in:

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

Note that I'm not convinced this is reliable enough to conclude that there is a backing field available, but it follows the idea you had by checking if there is a body or not.

I haven't added the other checks you had in mind but these can trivially be added (either use the symbol as you already do or look through the PropertyDeclarationSyntax its modifiers/attributes).

---

Full code to test it out yourself:

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

Need Your Help

Sort child nodes by date - Razor Umbraco

c# list razor sql-order-by umbraco

For the following examples, I'm using a content tree which looks like this:

Sending JSON or SwiftyJSON through Alamofire POST

ios json swift2 alamofire swifty-json

Similar questions to this have been posted before but with slight differences, namely: