71

I'm creating a custom attribute in C# and I want to do different things based on whether the attribute is applied to a method versus a property. At first I was going to do new StackTrace().GetFrame(1).GetMethod() in my custom attribute constructor to see what method called the attribute constructor, but now I'm unsure what that will give me. What if the attribute was applied to a property? Would GetMethod() return a MethodBase instance for that property? Is there a different way of getting the member to which an attribute was applied in C#?

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
    AllowMultiple = true)]
public class MyCustomAttribute : Attribute

Update: okay, I might have been asking the wrong question. From within a custom attribute class, how do I get the member (or the class containing the member) to which my custom attribute was applied? Aaronaught suggested against walking up the stack to find the class member to which my attribute was applied, but how else would I get this information from within the constructor of my attribute?

Community
  • 1
  • 1
Sarah Vessels
  • 30,930
  • 33
  • 155
  • 222
  • Don't want to sound bad, but I have to ask why you want to find out what attribute is applied to your method? This is one hefty design smell. Maybe you should ask what the motive is to do that. – flq Jan 30 '10 at 18:41
  • @Frank: see the thread here, specifically m3rLinEz's suggestion: http://stackoverflow.com/questions/2164159/c-enforceable-way-of-signifying-a-method-is-there-as-part-of-interface – Sarah Vessels Jan 30 '10 at 18:46
  • 2
    Have you considered how brittle the solution is going to be if you depend on attributes of the calling method? All it takes is for somebody to decide to refactor some common code out of that method in order to break this, and they may be so far removed from your runtime check that they'll have no idea why it's breaking and no way to figure it out. Unless you're writing your own DI/AOP framework, I find this scary... – Aaronaught Jan 30 '10 at 19:06
  • 4
    Answer to your update: You can't. Attributes don't contain any information about the type they were applied to; they work in reverse. Normally you would only know about an attribute because you picked it up from the member's (property or method) `GetCustomAttribute[s]` method. – Aaronaught Jan 30 '10 at 19:56
  • @Aaronaught: nuts. Thanks for responding to my corrected question, though. I fixed the typo in your name in my question, too. – Sarah Vessels Jan 30 '10 at 19:58
  • I went down a similar road when I first started learning about attributes, thinking that there was a way to "intercept" the compilation (saw your other Q as well) - in the end I realized that this is exactly the problem solved by static analysis, where you *can* make good use of these types of attributes. – Aaronaught Jan 30 '10 at 20:09
  • 1
    Add another "can't get there from here" from me. – Sky Sanders Feb 09 '10 at 02:33
  • 3
    Yeah - I'm stuck too, though I disagree that it's bad design to want to detect the target of an attribute. Consider the example of a DescriptionAttribute that's sub-classed to return a culture-sensitive resource string. Ideally, the resource key would stem from the name of the property/member which the DescriptionAttribute was applied to. Without being able to detect the target, the attribute cannot achieve this. – Mark May 26 '10 at 19:55
  • Subclass/split into separate attributes with different AttributeUsageAttribute AttributeTargets? – user423430 Nov 29 '11 at 14:45
  • The link is dead - perhaps this is the new one: https://learn.microsoft.com/en-us/dotnet/standard/attributes/writing-custom-attributes – chakeda Aug 31 '18 at 18:20

4 Answers4

47

Attributes provide metadata and don't know anything about the thing (class, member, etc.) they are decorating. On the other hand, the thing being decorated can ask for the attributes it is decorated with.

If you must know the type of the thing being decorated you will need to explicitly pass it to your attribute in its constructor.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, 
    AllowMultiple = true)] 
public class MyCustomAttribute : Attribute
{
   Type type;

   public MyCustomAttribute(Type type)
   {
      this.type = type;
   }
}
Scott Dorman
  • 42,236
  • 12
  • 79
  • 110
  • I've been reading this information a lot, but what if it is something valid? Does C# provide any other options for that? Like in my case, I need to validate if the logged user is the company manager, but instead of writing that code (or even calling the same method) over and over, I'd rather create a custom attribute that would handle that and also provide a cleaner code. Thanks :) – eestein Jun 05 '16 at 18:11
  • @eestein What context are you in? If you're in a web application, I'd look in to using the Authorize attribute and the Identity framework code. – Scott Dorman Jun 15 '16 at 02:43
  • it is the backend of a Web application. Regular classes. I have the logged user information when I instantiate the class, I'd just prefer to use some sort of annotations instead of calling a method every time I need to validate that. Thanks for your reply – eestein Jun 15 '16 at 02:49
43

Since there seems to be a lot of confusion with respect to how the stack frames and methods work, here is a simple demonstration:

static void Main(string[] args)
{
    MyClass c = new MyClass();
    c.Name = "MyTest";
    Console.ReadLine();
}

class MyClass
{
    private string name;

    void TestMethod()
    {
        StackTrace st = new StackTrace();
        StackFrame currentFrame = st.GetFrame(1);
        MethodBase method = currentFrame.GetMethod();
        Console.WriteLine(method.Name);
    }

    public string Name
    {
        get { return name; }
        set
        {
            TestMethod();
            name = value;
        }
    }
}

The output of this program will be:

set_Name

Properties in C# are a form of syntactic sugar. They compile down to getter and setter methods in the IL, and it's possible that some .NET languages might not even recognize them as properties - property resolution is done entirely by convention, there aren't really any rules in the IL spec.

Now, let's say for the moment that you had a really good reason for a program to want to examine its own stack (and there are precious few practical reasons to do so). Why in the world would you want it to behave differently for properties and methods?

The whole rationale behind attributes is that they are a kind of metadata. If you want a different behaviour, code it into the attribute. If an attribute can mean two different things depending on whether it's applied to a method or property - then you should have two attributes. Set the target on the first to AttributeTargets.Method and the second to AttributeTargets.Property. Simple.

But once again, walking your own stack to pick up some attributes from the calling method is dangerous at best. In a way, you are freezing your program's design, making it far more difficult for anybody to extend or refactor. This is not the way attributes are normally used. A more appropriate example, would be something like a validation attribute:

public class Customer
{
    [Required]
    public string Name { get; set; }
}

Then your validator code, which knows nothing about the actual entity being passed in, can do this:

public void Validate(object o)
{
    Type t = o.GetType();
    foreach (var prop in
        t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
    {
        if (Attribute.IsDefined(prop, typeof(RequiredAttribute)))
        {
            object value = prop.GetValue(o, null);
            if (value == null)
                throw new RequiredFieldException(prop.Name);
        }
    }
}

In other words, you're examining the attributes of an instance that was given to you but which you don't necessarily know anything about the type of. XML attributes, Data Contract attributes, even Attribute attributes - almost all attributes in the .NET Framework are used this way, to implement some functionality that is dynamic with respect to the type of an instance but not with respect to the state of the program or what happens to be on the stack. It is very unlikely that you are actually in control of this at the point where you create the stack trace.

So I'm going to recommend again that you don't use the stack-walking approach unless you have an extremely good reason to do so which you haven't told us about yet. Otherwise you are likely to find yourself in a world of hurt.

If you absolutely must (don't say we didn't warn you), then use two attributes, one that can apply to methods and one that can apply to properties. I think you'll find that to be much easier to work with than a single super-attribute.

mcwyrm
  • 1,571
  • 1
  • 15
  • 27
Aaronaught
  • 120,909
  • 25
  • 266
  • 342
5

GetMethod will always return you the function name. If it is a property, you will get either get_PropertyName or set_PropertyName.

A property is basically a type of method, so when you implement a property, the compiler creates two separate functions in the resulting MSIL, a get_ and a a set_ methods. This is why in the stack trace you receive these names.

Manfred
  • 5,320
  • 3
  • 35
  • 29
Amirshk
  • 8,170
  • 2
  • 35
  • 64
  • So is 'GetMethod' just a misnomer? – Sarah Vessels Jan 30 '10 at 18:48
  • Umm, but you don't actually see the property accessor in the stack trace, do you? It should just be the call to GetCustomAttributes.. – alexdej Jan 30 '10 at 18:58
  • You **will** see the property accessor in the stack trace, because that is actually the method that's being invoked in the IL. – Aaronaught Jan 30 '10 at 19:04
  • well, it really depends how you access the attribute, as @alexdej pointed out, when accessing from GetCustomAttributes, the method name wasn't even in the stack trace (in my test) – Amirshk Jan 30 '10 at 19:14
  • When accessing *what* from `GetCustomAttributes`? The stack trace isn't being done from the attribute itself, it's being done from the code that checks the attributes. Attributes are just metadata, they aren't really "executed" unless you do horrible unspeakable things in the ctor. – Aaronaught Jan 30 '10 at 19:22
  • I checked the stack trace inside the attribute's ctor. – Amirshk Jan 30 '10 at 19:25
4

custom attributes are activated by some code calling the GetCustomAttributes method on the ICustomAttributeProvider (reflection object) that represents the location where the attribute is applied. So in the case of a property, some code would obtain the PropertyInfo for the property and then call GetCustomAttributes on that.

If you want to build out some validation framework you would need to write the code that inspects types & members for custom attributes. You could for example have an interface that attributes implement to participate in your validation framework. Could be as simple as the following:

public interface ICustomValidationAttribute
{
    void Attach(ICustomAttributeProvider foundOn);
}

Your code could look for this inteface on (for example) a Type:

var validators = type.GetCustomAttributes(typeof(ICustomValidationAttribute), true);
foreach (ICustomValidationAttribute validator in validators)
{
     validator.Attach(type);
}

(presumably you would walk the whole reflection graph and do this for each ICustomAttributeProvider). For an example of a similar approach in action in the .net FX you can look at WCF's 'behaviors' (IServiceBehavior, IOperationBehavior, etc).

Update: the .net FX does have a sort-of general purpose, but basically undocumented interception framework in the form of ContextBoundObject and ContextAttribute. You can search the web for some examples of using it for AOP.

alexdej
  • 3,751
  • 23
  • 21