2

When you annotate a type or method or property with an attribute, what is the compiler/CLR/etc. doing for you?

My guess is that it is "injecting" methods, properties, etc. into your class definitions (or maybe just into your object?, or?) and providing automatic behavior, sort of like how when you declare a delegate with the terse:

public delegate void MySuperSpecialDelegate(myAwesomeClass myAwesomeObject);

you then get some really great automatic behavior that is "injected" into the compiled code (CIL) for you.

So to reiterate the question, what is happening automatically "behind the scenes" when you use attributes?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
richard
  • 12,263
  • 23
  • 95
  • 151

2 Answers2

3

Absolutely nothing, with a few very specific examples:

  • PrincipalPermissionAttribute
  • MethodImplAttribute
  • etc

which have some very specific handling

Other than that, attributes are inert and only activated when explicitly using reflection.

There are a few that the compiler uses, though - ConditionalAttribute, SerializableAttribute, etc.

But to reiterate, in the general case and for the vast majority of attributes: nothing, nil, zip, nada nix and null.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • So the only thing that happens is that you get the attribute metadata? – richard Mar 04 '11 at 20:09
  • @Richard - with only very limited number of exceptions, correct. – Marc Gravell Mar 04 '11 at 20:11
  • @Marc: See my comment on _Mehrdad_'s answer. That is where my confusion lay. Also, when does the attribute's code come into play. Seeing your edit to your answer it seems to me now like MOST attributes are only for the purposes of things you would do using reflection . . . however some of them (as you mention serializable) actually do get used by the compiler. Can you explain what happens in these cases? – richard Mar 04 '11 at 20:15
  • @Richard it really varies per attribute. SerializableAttribute becomes a flag in the IL, ConditionalAttribute selective blocks methods from executing, some others become baked into the exe data, etc – Marc Gravell Mar 04 '11 at 20:20
  • @Richard - no, that is an inert one. The asmx layer inspects that with reflection. There is no compiler or JIT action on WebMethodAttribute. – Marc Gravell Mar 04 '11 at 20:22
  • One more example that comes to mind is any attribute that inherits from ContextAttribute, such as SynchronizationAttribute. It doesn't do anything for the compiler or Jit, but the runtime applies specific behaves when used. – vcsjones Mar 04 '11 at 20:25
  • @Marc: Ok. Re: `SerializableAttribute`, what methods is `ConditionalAttribute` blocking? Methods in the serialization classes, or methods in the class marked `[serializable]`? You are hinting at the answer I am really driving for. LOL – richard Mar 04 '11 at 20:30
  • @Richard ConditionalAttribute is how Debug.WriteLine and Trace.WriteLine etc work; if a method is marked [Conditional("FOO")], then calls to those methods (including evaluation of parameters) is only performed when "FOO" is defined as a compilation symbol. No need to guess, then, that Debug.WriteLine is marked [Conditional("DEBUG")] and Trace.WriteLine is marked [Conditional("TRACE")] – Marc Gravell Mar 04 '11 at 20:38
  • @Richard Serializable is different again; in the IL flags for a typical class it is the difference between `.class private auto ansi beforefieldinit` and `.class private auto ansi serializable beforefieldinit` – Marc Gravell Mar 04 '11 at 20:44
2

It depends on the attribute.

"Normal" attributes like CLSCompliantAttribute don't do anything at run-time (unless you try to read them, in which case they're instantiated); they're just metadata describing the data/code, that's sometimes used by the compiler and/or debugger to help the programmer.

"Special" attributes are, well, special. They can change flags in the code, cause the CLR behavior to change in some way, or cause some other observable change; it's attribute-dependent. (E.g. FieldOffsetAttribute can cause the field layout to change, which is obviously an observable run-time effect.)

An extreme example of change in behavior can be seen with the ProxyAttribute, in which case you can pretty much hijack the entire code for a class (even the constructor).

Other examples of such "special" attributes include InAttribute, OutAttribute, ThreadStaticAttribute, MTAThreadAttribute, TypeForwardedToAttribute (I think), ComImportAttribute, DllImportAttribute, etc, etc... there's actually quite a lot of them!

Community
  • 1
  • 1
user541686
  • 205,094
  • 128
  • 528
  • 886
  • What confuses me then, is why you have to add [serializable] to a class if you want to serialize instances of it. If the CLR isn't doing anything, or having to track anything based on this attribute, why can't you just serialize an object without having to declare that it is serializable? It seems like the attributes must be causing the CLR to do _something_. – richard Mar 04 '11 at 20:12
  • 1
    @Richard: `[Serializable]` doesn't change the behavior of the CLR; it changes the behavior of the classes that use it (namely, the classes in the `System.Runtime.Serialization` namespace). Whether or not a class is serializable has no effect on the running of the nature of the program itself, and hence is outside of the CLR's concern; it just changes how the data is converted to other representations by the serializers. – user541686 Mar 04 '11 at 20:15
  • @Mehrad: In what way does it change the behavior of the `System.Runtime.Serialization` namespace classes? – richard Mar 04 '11 at 20:19
  • @Richard: I think what I said was misleading. The attribute by itself doesn't do anything; it's the serializer itself that *checks* for the presence of the attribute, and adjusts its behavior accordingly. If you use [BinaryFormatter](http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx) for instance, it would check whether or not the attribute exits and it would serialize differently based on the result. (I'm not sure exactly where in the code the check is done, though; it might be in a different class.) – user541686 Mar 04 '11 at 20:22
  • @Mehrad: ok. . . so then in what way is the behavior adjusted. The reason I ask is, it won't even attempt a serialization if you don't annotate with [serializable], so it seems an adjustment would be unnecessary, since in all cases it would act the same way. . . – richard Mar 04 '11 at 20:23
  • @Richard: I'm not sure what you mean... it won't attempt serialization by default if you don't annotate with `[Serializable]`, and it will if you do; that's the behavior change. (Am I understanding what you mean correctly?) – user541686 Mar 04 '11 at 20:25
  • @Mehrad: Yes. And I understand that part, but I don't understand why you would need to annotate it with [serializable]. what does that do for it that it needs to know that in order to attempt the serialization? – richard Mar 04 '11 at 20:28
  • @Richard: Oh... so you're asking why the default isn't *serializable*? Well, it's because it doesn't make sense to serialize most classes with the default behavior, and it can introduce bugs if the programmer didn't intend the class to be serializable. So it's opt-in instead of opt-out. (You can explicitly opt-out a member, though, by the `NonSerialized` attribute.) – user541686 Mar 04 '11 at 20:29
  • Ok I see. So it is sort of forcing "good behavior" on the part of the programmer and making them think about what they are really intending to do. – richard Mar 04 '11 at 20:31
  • @Richard: Yup. :) In reality, only a small proportion of all the classes need serialization, so I think this makes sense. – user541686 Mar 04 '11 at 20:31