SFu*_*n28 5 .net c# reflection .net-4.0 c#-7.0
是否可以使用反射来区分 getter-only 属性和表达式主体属性?
class MyClass
{
DateTime GetterOnly { get; }
DateTime ExpressionBody => DateTime.Now;
}
Run Code Online (Sandbox Code Playgroud)
例如,下面的方法如何完成?
enum PropertyKind
{
NotInteresting,
GetterOnly,
ExpressionBody,
}
PropertyKind GetPropertyKind(PropertyInfo propertyInfo)
{
if (propertyInfo.GetSetMethod(true) == null)
{
// what goes here??
}
return PropertyKind.NotInteresting;
}
Run Code Online (Sandbox Code Playgroud)
首先我们必须定义我们的术语:
=>
(lambda) 语法实现的属性。{...}
语法实现的属性。需要注意的是,不可能区分表达式主体属性和函数主体属性,因为实际上将为两者生成相同的 IL。
但是,我相信您真正想要的是能够区分自动属性和非自动属性。
这是可能的,因为编译器生成一个[CompilerGeneratedAttribute]
用属性派生的名称装饰的支持字段,可以对其进行测试。
支持字段名称当前始终为“<PropertyName>k__BackingField”(其中PropertyName
是属性的名称),对于 .Net 4.6 和 .Net Core 3.1 都是如此 - 但当然这不能保证永远不会改变,因此任何依赖于此的代码都可能会在未来版本的 C# 编译器中崩溃。
尽管有相当大的警告,您可以编写一个方法来检查 a 是否PropertyInfo
实现了自动属性,如下所示:
public static bool IsAutoProperty(PropertyInfo property)
{
string backingFieldName = $"<{property.Name}>k__BackingField";
var backingField = property.DeclaringType.GetField(backingFieldName, BindingFlags.NonPublic | BindingFlags.Instance);
return backingField != null && backingField.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) != null;
}
Run Code Online (Sandbox Code Playgroud)
这将检查属性以查看 (a) 它是否具有一个具有从属性名称派生的特定名称的支持字段,以及 (b) 该支持字段是编译器生成的。
我认为这不是一个好主意,因为它依赖于未记录的和凭经验确定的编译器行为,因此需要谨慎!
这是一个可编译的控制台应用程序来演示:
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace ConsoleApplication1
{
static class Program
{
static void Main(string[] args)
{
var type = typeof(MyClass);
foreach (var property in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
{
if (IsAutoProperty(property))
Console.WriteLine($"{property.Name} is an auto-property");
}
}
public static bool IsAutoProperty(PropertyInfo property)
{
string backingFieldName = $"<{property.Name}>k__BackingField";
var backingField = property.DeclaringType.GetField(backingFieldName, BindingFlags.NonPublic | BindingFlags.Instance);
return backingField != null && backingField.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) != null;
}
}
class MyClass
{
DateTime GetterOnly { get; }
DateTime ExpressionBody => DateTime.Now;
}
}
Run Code Online (Sandbox Code Playgroud)
这输出:
GetterOnly 是一个自动属性