views:

381

answers:

3

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; }
}
+1  A: 

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
Jon Skeet
I don't think this works. The program found an attribute when testing Sedan. This should have returned null. When you ran it did it print 2 lines? If it did, its exhibiting the problem I'm having.
TheDeeno
It printed two lines, but the one for Sedan had a blank after the colon - i.e. what you want. I'll edit the answer to be absolutely complete.
Jon Skeet
My mistake. I got your example working (my actual code is a little different). I still have a problem though: this method still looks at the inheritance chain. If I add an attribute to Car's TurningRadius Sedan will print a line. Is there no way around this? Thanks for the help.
TheDeeno
I update the question to reflect the more accurate code you wrote.
TheDeeno
+3  A: 

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.

Santiago Palladino
+1 for the help. Accepting Skeet's cause he got it in first.
TheDeeno
+3  A: 

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.
Jon Skeet
Thanks for the help. This did the trick I think.
TheDeeno