Dane O'Connor
Dane O'Connor

Reputation: 77288

How do I ignore the inheritance chain when getting attributes?

For some reason I'm not getting this. (Example model below) If I write:

var property = typeof(sedan).GetProperty("TurningRadius");
Attribute.GetCustomAttributes(property,typeof(MyAttribute), false)

the call will return MyAttribute(2) despite indicating I don't want to search the inheritance chain. Does anyone know what code I can write so that calling

MagicAttributeSearcher(typeof(Sedan).GetProperty("TurningRadius"))

returns nothing while calling

MagicAttributeSearcher(typeof(Vehicle).GetProperty("TurningRadius"))

returns MyAttribute(1)?


Example Model:

public class Sedan : Car
{
    // ...
}

public class Car : Vehicle
{
    [MyAttribute(2)]
    public override int TurningRadius { get; set; }
}

public abstract class Vehicle
{
    [MyAttribute(1)]
    public virtual int TurningRadius { get; set; }
}

Upvotes: 2

Views: 873

Answers (3)

Jon Skeet
Jon Skeet

Reputation: 1500185

Okay, given the extra information - I believe the problem is that GetProperty is going up the inheritance change.

If you change your call to GetProperty to:

PropertyInfo prop = type.GetProperty("TurningRadius",
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

then prop will be null if the property isn't overridden. For instance:

static bool MagicAttributeSearcher(Type type)
{
    PropertyInfo prop = type.GetProperty("TurningRadius", BindingFlags.Instance | 
                                         BindingFlags.Public | BindingFlags.DeclaredOnly);

    if (prop == null)
    {
        return false;
    }
    var attr = Attribute.GetCustomAttribute(prop, typeof(MyAttribute), false);
    return attr != null;
}

This returns true and only if:

  • The specified type overrides the TurningRadius property (or declares a new one)
  • The property has the MyAttribute attribute.

Upvotes: 5

Santiago Palladino
Santiago Palladino

Reputation: 3542

I believe the problem is that when you obtain the property TurningRadius from the Sedan object in the first line

var property = typeof(sedan).GetProperty("TurningRadius");

what you are actually getting is the TurningRadius property declared at Car level, since Sedan doesn't have its own overload.

Therefore, when you request its attributes, you are getting the ones defined at car even if you requested not to go up in the inheritance chain, as the property you are querying is the one defined in Car.

You should change the GetProperty to add the necessary flags to obtain only declaring members. I believe DeclaredOnly should do.

Edit: Note that this change will have the first line return null, so watch out for NullPointerExceptions.

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1500185

I think this is what you're after - note that I had to make TurningRadius abstract in Vehicle and overridden in Car. Is that okay?

using System;
using System.Reflection;

public class MyAttribute : Attribute
{
    public MyAttribute(int x) {}
}

public class Sedan : Car
{
    // ...
}

public class Car : Vehicle
{
    public override int TurningRadius { get; set; }
}

public abstract class Vehicle
{
    [MyAttribute(1)]
    public virtual int TurningRadius { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        MagicAttributeSearcher(typeof(Sedan));
        MagicAttributeSearcher(typeof(Vehicle));
    }

    static void MagicAttributeSearcher(Type type)
    {
        PropertyInfo prop = type.GetProperty("TurningRadius");
        var attr = Attribute.GetCustomAttribute(prop, typeof(MyAttribute), false);
        Console.WriteLine("{0}: {1}", type, attr);
    }
}

Output:

Sedan:
Vehicle: MyAttribute

Upvotes: 1

Related Questions