Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Attributes: Why does GetCustomAttributes() make a new attribute instance every time?

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".

like image 748
CodingWithSpike Avatar asked Jan 06 '09 16:01

CodingWithSpike


2 Answers

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 documentation on attributes.

like image 148
Lasse V. Karlsen Avatar answered Sep 20 '22 14:09

Lasse V. Karlsen


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
);

?

like image 42
yfeldblum Avatar answered Sep 17 '22 14:09

yfeldblum