C# 区分仅getter属性和表达式体属性?
是否可以使用反射来区分getter-only属性和expression-body属性C# 区分仅getter属性和表达式体属性?,c#,.net,reflection,.net-4.0,c#-7.0,C#,.net,Reflection,.net 4.0,C# 7.0,是否可以使用反射来区分getter-only属性和expression-body属性 class MyClass { DateTime GetterOnly { get; } DateTime ExpressionBody => DateTime.Now; } 例如,如何完成下面的方法 enum PropertyKind { NotInteresting, GetterOnly, ExpressionBody, } PropertyKind
class MyClass
{
DateTime GetterOnly { get; }
DateTime ExpressionBody => DateTime.Now;
}
例如,如何完成下面的方法
enum PropertyKind
{
NotInteresting,
GetterOnly,
ExpressionBody,
}
PropertyKind GetPropertyKind(PropertyInfo propertyInfo)
{
if (propertyInfo.GetSetMethod(true) == null)
{
// what goes here??
}
return PropertyKind.NotInteresting;
}
相关职位:
首先,我们必须定义我们的术语:
- Auto属性-具有由编译器自动生成的支持字段的属性
- Expression bodied属性-使用
(lambda)语法实现的属性=>
- 函数体属性-使用正常的
语法实现的属性{…}
[CompilerGeneratedAttribute]
修饰的支持字段,并使用从属性派生的名称,可以对该属性进行测试
备份字段名称当前始终为“k_ubackingfield”(其中PropertyName
是属性的名称),这对于.Net 4.6和.Net Core 3.1都是正确的-但当然,这并不能保证永远不会更改,因此任何依赖于此的代码都可能在C编译器的未来版本中中断
尽管有相当大的警告,但您可以编写一个方法来检查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;
}
公共静态bool IsAutoProperty(PropertyInfo属性)
{
字符串backingFieldName=$“k_ubackingfield”;
var backingField=property.DeclaringType.GetField(backingFieldName,BindingFlags.NonPublic | BindingFlags.Instance);
return backingField!=null&&backingField.GetCustomAttribute(typeof(CompilerGeneratedAttribute))!=null;
}
这将检查属性,以查看(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;
}
}
使用系统;
运用系统反思;
使用System.Runtime.CompilerServices;
命名空间控制台应用程序1
{
静态类程序
{
静态void Main(字符串[]参数)
{
变量类型=类型(MyClass);
foreach(type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)中的var属性)
{
如果(不动产(不动产))
WriteLine($“{property.Name}是一个自动属性”);
}
}
公共静态bool IsAutoProperty(PropertyInfo属性)
{
字符串backingFieldName=$“k_ubackingfield”;
var backingField=property.DeclaringType.GetField(backingFieldName,BindingFlags.NonPublic | BindingFlags.Instance);
return backingField!=null&&backingField.GetCustomAttribute(typeof(CompilerGeneratedAttribute))!=null;
}
}
类MyClass
{
DateTime GetterOnly{get;}
DateTime ExpressionBody=>DateTime.Now;
}
}
这将产生:
GetterOnly是一个自动属性
你当然可以通过反射判断是否只实现了一个getter(只要搜索setter,它就不存在了)。一个表达式体属性是一个getter-only属性,它的getter不只是返回支持字段值。我怀疑真正的问题是不同的。您是否正在尝试创建自定义序列化程序或分析器?Roslyn分析器可以检测语法是只获取自动属性还是表达式体属性。这就是重构如何在两者之间切换的方法。但在运行时,除了代码之外,getter和getter之间没有区别。当你说“expression body property”时,反射无法分辨这些getter来自何处,你的意思是“expression body property”,还是“auto-implemented property”?因为从IL中你无法区分普通属性和表达式体属性之间的区别。除了属性和支持字段的存在:显示自动属性具有
编译器生成的属性。请参阅本文的详细信息。我写了一篇很长的文章作为对我问题的评论,但没有提交。你给了我很多思考的机会。这里的复杂性部分在于,有很多方法可以创建一个属性,但我的开发人员并没有使用所有这样的选项。我真正想做的是区分需要序列化的属性,因为它们是重新水化对象所必需的,而不需要序列化的对象是其他信息的派生。我认为这通常是一个需要解决的麻烦问题,因此我使用的是仅以某些方式编写属性作为代理,以确定序列化需要哪些属性,哪些属性不需要。@SFun28您可以创建自己的自定义属性类型,并让开发人员用它装饰相应的属性吗?然后可以使用反射来查看属性是否具有该属性。我不喜欢属性上的属性。我觉得它污染了模型。不管怎么说,这已经足够让我继续下去了@SFun28我想只检查编译器生成的属性就足够了。