检查 IPropertySymbol 是否有支持字段
Check if IPropertySymbol has a backing field
几天前我开始玩 roslyn,我正在尝试编写一个扩展方法来判断 IPropertySymbol
是否有支持字段,所以我认为 属性 有一个支持字段如果并且仅当以下情况不适用时(就我而言):
- 如果它的摘要
- 如果它是外部的
- 如果其 ReadOnlyProperty
- 如果 Getter 或 Setter 没有主体或空主体
所以我想到了
public static bool HasBackingField(this IPropertySymbol property)
{
return !(property.IsAbstract || property.IsExtern || property.IsReadOnly);
}
我的问题是
- 我错过了什么条件吗?
- 如何检查最后一个条件?我在
IPropertySymbol
中找到了 GetMethod
和 SetMethod
属性,但我不知道要检查它们是否有主体
启动示例
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;
}
}
几天前我开始玩 roslyn,我正在尝试编写一个扩展方法来判断 IPropertySymbol
是否有支持字段,所以我认为 属性 有一个支持字段如果并且仅当以下情况不适用时(就我而言):
- 如果它的摘要
- 如果它是外部的
- 如果其 ReadOnlyProperty
- 如果 Getter 或 Setter 没有主体或空主体
所以我想到了
public static bool HasBackingField(this IPropertySymbol property)
{
return !(property.IsAbstract || property.IsExtern || property.IsReadOnly);
}
我的问题是
- 我错过了什么条件吗?
- 如何检查最后一个条件?我在
IPropertySymbol
中找到了GetMethod
和SetMethod
属性,但我不知道要检查它们是否有主体
启动示例
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;
}
}