Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 区分仅getter属性和表达式体属性?_C#_.net_Reflection_.net 4.0_C# 7.0 - Fatal编程技术网

C# 区分仅getter属性和表达式体属性?

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

是否可以使用反射来区分getter-only属性和expression-body属性

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)语法实现的属性
  • 函数体属性-使用正常的
    {…}
    语法实现的属性
需要注意的是,不可能区分表达式体属性和函数体属性,因为实际上会为两者生成相同的IL

但是,我相信您真正想要的是能够区分自动属性和非自动属性

这是可能的,因为编译器生成一个用
[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我想只检查
编译器生成的属性就足够了。