views:

194

answers:

1

Hi,

I need to be able to retrieve the Custom Attributes of a class from a method in its base class. Right now I am doing it via a protected static method in the base class with the following implementation (the class can have multiple instances of the same attribute applied):

//Defined in a 'Base' class
protected static CustomAttribute GetCustomAttribute(int n) 
{
        return new StackFrame(1, false) //get the previous frame in the stack
                                        //and thus the previous method.
            .GetMethod()
            .DeclaringType
            .GetCustomAttributes(typeof(CustomAttribute), false)
            .Select(o => (CustomAttribute)o).ToList()[n];
}

I call it from a derived class thusly:

[CustomAttribute]
[CustomAttribute]
[CustomAttribute]
class Derived: Base
{
    static void Main(string[] args)
    {

        var attribute = GetCustomAttribute(2);

     }

}

Ideally I'd be able to call this from the contructor and cache the results.

Thanks.

PS

I realize that GetCustomAttributes is not guaranteed to return them with respect to lexical order.

+1  A: 

If you used instance methods rather than static methods, you could call this.GetType(), even from the base class.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
class CustomAttribute : Attribute
{}

abstract class Base
{
    protected Base()
    {
        this.Attributes = Attribute.GetCustomAttributes(this.GetType(), typeof(CustomAttribute))
            .Cast<CustomAttribute>()
            .ToArray();
    }

    protected CustomAttribute[] Attributes { get; private set; }
}

[Custom]
[Custom]
[Custom]
class Derived : Base
{
    static void Main()
    {
        var derived = new Derived();
        var attribute = derived.Attributes[2];
    }
}

It's simpler, and accomplishes the caching in the constructor that you were hoping for.

Daniel Schilling
Thanks. That's a good but I do need this to work for singletons. Looking at the stack frame feels hackish but it keeps the API clean so I'll stick with it for now. I accepted your answer since it may help others.
Rodrick Chapman