Get with Reflection fields that are not generated by the compiler

I recently wrote a method for plotting a graph with dependencies between classes using Reflection and found the following problem. My method parses the return type of the property, the generic arguments of the class definition, and the instance fields of those classes.

To check the fields of a class instance, I use the following method.

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

      

To test this, I write the following class definition:

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; }
}

      

For a few seconds I was shocked to see the result. That's when I remembered that .NET generates an instance field, Set and Get methods to emulate properties.

enter image description here

When I checked with .NET Reflector in the library to see the compiler generated code I find the following definition.

class A
{
    private ulong? _field1; 

    [CompilerGenerated]
    private Byte <PropertyA>k__BackingField;

    [CompilerGenerated]
    private Int32 <PropertyB>k__BackingField;

    [CompilerGenerated]
    private bool <PropertyC>k__BackingField;
}

      

Therefore, I modified the method to exclude fields with the CompilerGenerated attribute and its match with some property.

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;
        }
    }
}

      

QUESTIONS

  • Is there some combination of BindingFlags I am missing for these fields?
  • Is there another way to get these fields because this code seems to me like killing a mosquito with bazooka?

You can download the complete code here .

+3


source to share


1 answer


You need fields: !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;
        }

      

+1


source







All Articles