How do attribute classes work?

My searches continue to open only manuals explaining how to use and apply attributes to a class. I want to learn how to create my own attribute classes and how they work.

How are attribute classes created? Are they instances when the class instance is applied? Is an instance instance for each class created to use it? For example. if I applied the SerializableAttribute class to the MyData class and I create an instance of 5 MyData instances, will there be 5 instances of the SerializbleAttribute class created backstage? Or is there only one instance shared by all of them?

How are instances of the access attribute class of the class with which they are associated? How does the SerializableAttribute class access the class it applies to so that it can serialize data? Does any property have SerializableAttribute.ThisIsTheInstanceIAmAppliedTo? :) Or does it work in the opposite direction, that whenever I serialize something, the Serialize function through which I pass the MyClass instance will reflectively pass through the attributes and find the SerialiableAttribute instance?

+47
c # attributes
Apr 20 '10 at 15:55
source share
6 answers

I have not used attributes in my daily work before, but I read about them. I also did some tests to support what I will say here. If I'm wrong anywhere - feel free to tell me this :)

From what I know, attributes do not act like regular classes. They are not created when creating the object to which they are applied, and not to one static instance, and not 1 for each instance of the object. They also do not access the class to which they apply.

Instead, they act as properties (attributes ?: P) of the class. Unlike the properties of the .NET class, more similar to the properties of the "one glass property - transparency" property. You can check which attributes apply to the class from reflection, and then act accordingly. This is, in essence, metadata that is tied to a class definition, and not to objects of this type.

You can try to get a list of attributes for a class, method, property, etc. etc. When you get a list of these attributes, this is where they will be created. You can then manipulate the data in these attributes.

eg. Linq tables, properties have attributes on them that determine which table / column they belong to. But these classes do not use these attributes. Instead, the DataContext checks the attributes of these objects when it converts linq expression trees to SQL code.

Now for some real-world examples .. I used them in LinqPad , so don't worry about weird dump (). I replaced it with Console.WriteLine to make the code more understandable for people who do not 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:

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

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

Do you have more questions? Feel free to ask!

UPD: I saw how you asked the question: why use it? As an example, I will tell you about the XML-RPC.NET library. You create your XML-RPC service class using methods that will represent the xml-rpc methods. The main thing now: in XmlRpc, method names can have some special characters, such as periods. This way you can use the flexlabs.ProcessTask () xml rpc method.

You define this class as follows:

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

This allows me to name the method the way I like it, but it still uses the public name, as it should.

+32
Apr 20 '10 at 17:50
source share

Attributes are essentially metadata that can be attached to various parts of your code. This metadata can then be interdependent and affect the behavior of certain operations.

Attributes can apply to almost every aspect of your code. For example, attributes can be associated at the Assembly level, such as the AssemblyVersion and AssemblyFileVersion attributes, which identify the version numbers associated with the assembly.

 [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] 

Then the Serializable attribute, for example, can be applied to the type declaration to indicate the type of support for serialization. In fact, this attribute has special meaning in the CLR and is actually stored as a special directive directly by type in IL, it is optimized for storage as a bit flag, which can be processed much more efficiently, there are several attributes for this character, which is known as pseudo-standard attributes.

Other attributes can be applied to methods, properties, fields, enumerations, return values, etc. You can get an idea of โ€‹โ€‹the possible goals that the attribute can apply to if you look at this link http://msdn.microsoft.com/en-us/library/system.attributetargets(VS.90).aspx

In addition, you can define your own custom attributes, which can then be applied to the targets for which your attributes are intended. Then, at runtime, your code can reflect the values โ€‹โ€‹contained in user attributes and take appropriate action.

For a rather naive example, and this is just for the sake of example :) You might want to write a persistence mechanism that automatically maps classes to tables in your database and maps class column properties to a table. You can start by defining two custom attributes

 TableMappingAttribute ColumnMappingAttribute 

What you can apply to your classes, as an example, we have the Person class

 [TableMapping("People")] public class Person { [ColumnMapping("fname")] public string FirstName {get; set;} [ColumnMapping("lname")] public string LastName {get; set;} } 

When this compiles, with the exception of the fact that the compiler emits additional metadata defined by user attributes, something else is affected. However, now you can write a PersistanceManager that can dynamically check the attributes of an instance of the Person class and insert data into the People table by matching the data in the FirstName property with the fname column and the LastName property in the lname column.

As for your question regarding attribute instances, an attribute instance is not created for every instance of your class. All People instances will share the same instance of the TableMappingAttribute and ColumnMappingAttributes attributes. In fact, attribute instances are only created when you really request attributes for the first time.

+15
Apr 20 '10 at 17:12
source share

Yes, they are created with the parameters that you give them.

The attribute does not "access" the class. The attribute is bound to a list of class / property attributes in reflection data.

 [Serializable] public class MyFancyClass { ... } // Somewhere Else: public void function() { Type t = typeof(MyFancyClass); var attributes = t.GetCustomAttributes(true); if (attributes.Count(p => p is SerializableAttribute) > 0) { // This class is serializable, let do something with it! } } 
+6
Apr 20 '10 at 16:00
source share

Think of post-its attributes that are tied to class or method definitions (built into assembly metadata).

Then you can have a processor / runner / inspector module that accepts these types, reflects, searches for these post-its, and processes them differently. This is called declarative programming. You declare some kind of behavior instead of writing code for them in the type.

  • The Serializable attribute for a type declares that it is built for serialization. The XmlSerializer can then take an object of this class and make it necessary. You mark methods that should be serialized / hidden with the correct post-its.
  • another example would be NUnit. The NUnit runner looks at the [TestFixture] attributes for all classes defined in the target assembly to identify test classes. He then searches for methods marked with the [Test] attribute to identify the tests that he then runs and displays the results.

You might want to complete this tutorial on MSDN , which most of the questions have been answered along with an example at the end. Although they could extract a method called Audit(Type anyType); instead of duplicating this code. The example "prints information" by checking attributes .. but you can do something in the same vein.

+6
Apr 20 '10 at
source share

If you look at this downloadable open source LINQ to Active Directory (CodePlex) , you might be interested in the Attributes.cs File mechanism, where Bart De Smet wrote all the attribute class definitions. I learned the attributes there.

In short, you can specialize the Attribute class and code some specialized properties for your needs.

 public class MyOwnAttributeClass : Attribute { public MyOwnAttributeClass() { } public MyOwnAttributeClass(string myName) { MyName = myName; } public string MyName { get; set; } } 

and then you can use it wherever MyOwnAttributeClass is useful. It can be either above the class definition, or with a property definition.

 [MyOwnAttributeClass("MyCustomerName")] public class Customer { [MyOwnAttributeClass("MyCustomerNameProperty")] public string CustomerName { get; set; } } 

Then you can get it through reflection like this:

 Attribute[] attributes = typeof(Customer).GetCustomAttribute(typeof(MyOwnAttributeClass)); 

Note that the attribute that you put between the square brackets is always the constructor of your attribute. So, if you want to have a parameterized attribute, you need to encode your constructor as such.

This code is provided as is and cannot be compiled. Its purpose is to give you an idea of โ€‹โ€‹how this works.

In fact, you usually want to have a different attribute class for the class than for the property.

Hope this helps!

+2
Apr 20 '10 at 18:01
source share

Not much time to give you a more complete answer, but you can find Attributes that were applied to the value using Reflection. As for their creation, you inherit from the attribute class and work from there - and the values โ€‹โ€‹that you supply with the attribute are passed to the attribute class constructor.

Some time has passed, as you might say ...

Martin

+1
Apr 20 '10 at 16:02
source share



All Articles