如何获取属性的支持字段(AssociatedPropertyOrEvent 为空)

本文关键字:支持 字段 AssociatedPropertyOrEvent 为空 属性 获取 何获取 | 更新日期: 2023-09-27 18:37:22

我正在尝试使用 Roslyn 来获取对属性支持字段的符号 (FieldSymbol) 的引用,但 AssociatedPropertyOrEvent 为空。下面是失败的单元测试。

[Test]
public void Get_BackingField_for_Property()
{
    var sourceCode = @" public class Player
                    {
                        private Person _MyPerson;
                        public virtual Person MyPerson
                        {
                            get { return _MyPerson; }
                        }
                        public virtual void Set(Person person)
                        {
                            _MyPerson = person;
                        }
                    }";

    var syntaxTree = SyntaxTree.ParseText(sourceCode);

    var mscorlib = MetadataReference.CreateAssemblyReference(
                                     "mscorlib");

    var compilation = Compilation.Create("HelloWorld")
                    .AddReferences(mscorlib)
                    .AddSyntaxTrees(syntaxTree);
    //var  semanticModel = compilation.GetSemanticModel(syntaxTree);
    var classSymbol =
        compilation.GetTypeByMetadataName("Player");
    Assert.That(classSymbol,Is.Not.Null, "class");
    var propertySymbol = classSymbol.GetMembers().Where(x => x.Kind == SymbolKind.Property);
    Assert.That(propertySymbol, Is.Not.Null, "property");
    var backingField = classSymbol.GetMembers().Where(x=>x.Kind== SymbolKind.Field).Cast<FieldSymbol>().First();
    Assert.That(backingField.AssociatedPropertyOrEvent, Is.Not.Null,"backing field");

更新:对于任何尝试执行相同操作的人 INotifyPropertyChaged 示例具有获取属性支持字段的代码。我修改了它以满足我的需求。这是代码

internal static IFieldSymbol GetBackingField(this IPropertySymbol property, ISemanticModel semanticModel)
{
    var propertyDelcarationSyntax = (PropertyDeclarationSyntax)property.DeclaringSyntaxNodes.First();
    var getter = propertyDelcarationSyntax.AccessorList.Accessors.First(a => a.Kind == SyntaxKind.GetAccessorDeclaration);
    return GetBackingFieldFromGetter(getter, semanticModel);
}
private static IFieldSymbol GetBackingFieldFromGetter(AccessorDeclarationSyntax getter, ISemanticModel semanticModel)
{
    // The getter should have a body containing a single return of a backing field.
    if (getter.Body == null)
    {
        throw new Exception("Missing a getter body for property " + semanticModel.GetDeclaredSymbol(getter.Parent).Name);
    }
    var statements = getter.Body.Statements;
    if (statements.Count != 1)
    {
        throw new Exception("Getter body has more then one statement for property " + semanticModel.GetDeclaredSymbol(getter.Parent).Name);
    }
    var returnStatement = statements.Single() as ReturnStatementSyntax;
    if (returnStatement == null || returnStatement.Expression == null)
    {
        throw new Exception("Getter body is missing a return statement for property " + semanticModel.GetDeclaredSymbol(getter.Parent).Name);
    }
    return semanticModel.GetSymbolInfo(returnStatement.Expression).Symbol as IFieldSymbol;
}

如何获取属性的支持字段(AssociatedPropertyOrEvent 为空)

AssociatedPropertyOrEvent的文档说:

如果此字段用作自动生成的属性或类似字段的事件的支持变量,则返回该属性/事件。否则返回 null。

由于您的字段与任何自动属性无关,因此AssociatedPropertyOrEvent正确返回null

通常,您询问的内容是不可能的,因为可能有许多属性访问同一字段。

您只能使用当前的 API 走另一条路。 使用 GetMembers 获取所有这些字段,然后找到其AssociatedPropertyOrEvent为所需属性的字段。