views:

1671

answers:

3

So I was playing around a little more with attributes in .NET, and realized that every call to Type.GetCustomAttributes() creates a new instance of my attribute. Why is that? I would think that the attribute instance would basically be a singleton-per-MemberInfo, with 1 instance bound to the Type, PropertyInfo, etc...

Here is my test code:

using System;

namespace AttribTest
{
[AttributeUsage(AttributeTargets.Class)]
class MyAttribAttribute : Attribute
{
 public string Value { get; set; }

 public MyAttribAttribute()
  : base()
 {
  Console.WriteLine("Created MyAttrib instance");
 }
}

[MyAttrib(Value = "SetOnClass")]
class MyClass
{
}

class Program
{
 static void Main(string[] args)
 {
  Console.WriteLine("Getting attributes for MyClass.");
  object[] a = typeof(MyClass).GetCustomAttributes(false);
  ((MyAttribAttribute)a[0]).Value = "a1";

  Console.WriteLine("Getting attributes for MyClass.");
  a = typeof(MyClass).GetCustomAttributes(false);
  Console.WriteLine(((MyAttribAttribute)a[0]).Value);

  Console.ReadKey();
 }
}
}

Now if I were to implement attributes, I would expect the output to be:

Created MyAttrib instance
Getting attributes for MyClass.
Getting attributes for MyClass.
a1

Where the "class loader" (sorry, I have more of a Java background, not 100% sure how .net loads its types) would compile MyClass, and create an instance of MyAttribAttribute, and store them together somewhere. (probably the Perm Gen in the heap if this were Java) The 2 calls to GetCustomAttributes() would then just return the same earlier created instance.

But the actual output is:

Getting attributes for MyClass.
Created MyAttrib instance
Getting attributes for MyClass.
Created MyAttrib instance
SetOnClass

So... why? It seems like creating a new instance of all these objects for every call is a bit excessive, and not good for performance/memory management. Is there any way to always get the same instance over and over?

Anyone have any ideas why it was designed this way?

The reason I care at all is because I made a custom attribute that internally holds some validation information, so in the Attribute I basically have a "private bool Validated" that I set to true. The validation stuff takes a while, so I don't want to run it every time. Now the problem is that since it creates a new instance of the attribute each time I get the attributes, Validated is always "false".

+3  A: 

Attributes aren't stored in memory as objects, they're only stored as metadata in the assembly. When you query for it, it will be constructed and returned, and usually attributes are throwaway objects so for the runtime to keep them around just in case you'd need them again would probably waste a lot of memory.

In short, you need to find another way to store your shared information.

Here's the MSDN page on attributes.

Lasse V. Karlsen
+1  A: 

It's because the attributes are saved in metadata. Attributes should be used for informations such as "user-friendly name of property", etc...

TcKs
Though even if I just stored "user-friendly name" in an attribute, the runtime is making a new one every time I lookup the attribute. So just looking up attributes frequently, reguardless of the attributes contents, can become expensive.
rally25rs
Yes, it can. But if you do it frequently, there is propably better solution than this.
TcKs
+3  A: 

Object-creation is cheap.

If you had an attribute like

public class MyAttribute : Attribute {
    public virtual string MyText { get; set; }
}

and applied it to a class like

[MyAttribute(MyText="some text")]
public class MyClass {
}

and you retrieved one like

var attr =
    typeof(MyClass).GetCustomAttributes(typeof(MyAttribute), false)
    .Cast<MyAttribute>().Single();

and you set some properties on it like

attr.MyText = "not the text we started with";

what should happen, and what would happen, the next time you called

Console.WriteLine(
    typeof(MyClass).GetCustomAttributes(typeof(MyAttribute), false)
    .Cast<MyAttribute>().Single().Name
);

?

Justice
Agreed - I think mutability is the real issue.
Kent Boogaart
I agree that mutability is a bit of an issue. If attributes werent mutable though, then that would support the case for having a singleton stored in mem, since it will always be identical, and prob take up less space than the metadata anyway.
rally25rs
I still don't see the case for a singleton. Object-creation is cheap. We would need a singleton if for some reason having two instances representing the same conceptual thing would yield incorrect behavior.
Justice