使用非编译器生成的反射字段获取

Jos*_*eph 5 .net c# reflection

最近在写一个方法,用反射构造类之间的依赖关系图,发现了如下问题。我的方法分析属性的返回类型、类定义的通用参数和这些类的实例字段。

为了检查类的实例字段,我使用以下方法。

public static IEnumerable<FieldInfo> GetFields(Type classType)
{
    return classType
        .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}  
Run Code Online (Sandbox Code Playgroud)

为了测试它,我编写了以下类定义:

static void Main(string[] args)
{
    foreach (var fieldInfo in GetFields(typeof(A)))
        Console.WriteLine(fieldInfo.Name);

    Console.ReadKey();
}

class A
{
    private ulong? _field1;

    public byte PropertyA { get; set; }

    public int PropertyB { get; set; }

    public bool PropertyC { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我震惊了几秒钟,看看结果。正是在我想起 .NET 生成一个实例字段、Set 和 Get 方法来模拟属性的时候。

在此处输入图片说明

当我使用.NET Reflector检查库以查看编译器生成的代码时,我发现以下定义。

class A
{
    private ulong? _field1; 

    [CompilerGenerated]
    private Byte <PropertyA>k__BackingField;

    [CompilerGenerated]
    private Int32 <PropertyB>k__BackingField;

    [CompilerGenerated]
    private bool <PropertyC>k__BackingField;
}
Run Code Online (Sandbox Code Playgroud)

所以我修改了方法以排除具有 CompilerGenerated 属性的字段,并且他的名字与某些属性匹配。

public static IEnumerable<FieldInfo> GetFields(Type classType)
{
    var regex = new Regex(@"^<(?<PropertyName>\w+)>\w+$");

    var fieldInfoes = classType
            .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    foreach (var fieldInfo in fieldInfoes)
    {
        if (fieldInfo.GetCustomAttribute<CompilerGeneratedAttribute>() == null)
            yield return fieldInfo;
        else
        {
            var match = regex.Match(fieldInfo.Name);
            if (!match.Success) 
                continue;

            var propertyName = match.Groups[@"PropertyName"].Value;
            if (classType.GetProperty(propertyName) == null)
                yield return fieldInfo;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题

  • 对于这些字段,我缺少某些 BindingFlags 组合吗?
  • 还有另一种获取这些字段的方法,因为这段代码在我看来就像用火箭筒杀死一只蚊子?

您可以在此处下载完整的代码。

小智 3

您需要的字段是:!field.IsDefined(typeof(CompilerGeneratedAttribute), false)

public static IEnumerable<FieldInfo> GetFields(Type classType)
        {
            var allFields = classType
                .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            var definedFields = from field in allFields
                                where !field.IsDefined(typeof(CompilerGeneratedAttribute), false)
                                select field;

            return definedFields;
        }
Run Code Online (Sandbox Code Playgroud)