Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
275 views
in Technique[技术] by (71.8m points)

c# - How do attribute classes work?

My searches keep turning up only guides explaining how to use and apply attributes to a class. I want to learn how to create my own attribute classes and the mechanics of how they work.

How are attribute classes instantiated? Are they instantiated when the class they are applied to is instantiated? Is one instantiated for each class instantiated that it is applied to? E.g. if I apply the SerializableAttribute class to a MyData class, and I instantiate 5 MyData instances, will there be 5 instances of the SerializbleAttribute class created behind the scenes? Or is there just one instance shared between all of them?

How do attribute class instances access the class they are associated with? How does a SerializableAttribute class access the class it is applied to so that it can serialize it's data? Does it have some sort of SerializableAttribute.ThisIsTheInstanceIAmAppliedTo property? :) Or does it work in the reverse direction that whenever I serialize something, the Serialize function I pass the MyClass instance to will reflectively go through the Attributes and find the SerialiableAttribute instance?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I haven't use attributes in my day-to-day work before, but I have read about them. Also I have done some tests, to back up what I'll say here. If I'm wrong in any place - feel free to tell me this :)

From what I know, attributes are not acting as regular classes. They aren't instantiated when you create an object that they are applied to, not one static instance, not 1 per each instance of the object. Neither do they access the class that they are applied to..

Instead they act like properties (attributes? :P ) of the class. Not like the .NET class properties, more like in the "one property of glass is transparency" kind of property. You can check which attributes are applied to a class from reflection, and then act on it accordingly. They are essentially metadata that is attached to the class definition, not the objects of that type.

You can try to get the list of attributes on a class, method, property, etc etc.. When you get the list of these attributes - this is where they will be instantiated. Then you can act on the data within these attributes.

E.g. the Linq tables, properties have attributes on them that define which table/column they refer to. But these classes don't use these attributes. Instead, the DataContext will check the attributes of these objects when it will convert linq expression trees to SQL code.

Now for some real examples.. I've ran these in LinqPad, so don't worry about the strange Dump() method. I've replaced it with Console.WriteLine to make the code easier to understand for the people who don't know about it :)

void Main()
{
    Console.WriteLine("before class constructor");
    var test = new TestClass();
    Console.WriteLine("after class constructor");

    var attrs = Attribute.GetCustomAttributes(test.GetType()).Dump();
    foreach(var attr in attrs)
        if (attr is TestClassAttribute)
            Console.WriteLine(attr.ToString());
}

public class TestClassAttribute : Attribute
{
    public TestClassAttribute()
    {
        DefaultDescription = "hello";
        Console.WriteLine("I am here. I'm the attribute constructor!");
    }
    public String CustomDescription {get;set;}
    public String DefaultDescription{get;set;}

    public override String ToString()
    {
        return String.Format("Custom: {0}; Default: {1}", CustomDescription, DefaultDescription);
    }
}

[Serializable]
[TestClass(CustomDescription="custm")]
public class TestClass
{
    public int Foo {get;set;}
}

The console result of this method is:

before class constructor
after class constructor
I am here. I'm the attribute constructor!
Custom: custm; Default: hello

And the Attribute.GetCustomAttributes(test.GetType()) returns this array: (the table shows all available columns for all entries.. So no, the Serializable attribute does not have these properties :) ) LinqPad Attributes Array

Got any more questions? Feel free to ask!

UPD: I've seen you ask a question: why use them? As an example I'll tell you about the XML-RPC.NET library. You create your XML-RPC service class, with methods that will represent the xml-rpc methods. The main thing right now is: in XmlRpc the method names can have some special characters, like dots. So, you can have a flexlabs.ProcessTask() xml rpc method.

You would define this class as follows:

[XmlRpcMethod("flexlabs.ProcessTask")]
public int ProcessTask_MyCustomName_BecauseILikeIt();

This allows me to name the method in the way I like it, while still using the public name as it has to be.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...