WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Understanding Attributes

by Satya Komatineni
07/28/2003

Attributes are widely used in the .NET Framework to annotate code. For example, XML serialization uses attributes to control how a class is serialized. The syntax of attributes can be confusing until you realize that attributes are actually just managed classes. This article provides a quick guide to understanding attribute syntax, how to read it, and how to look up attribute documentation to be able to specify them in your programming practice.

Attributes are used all over the place in .NET. Let us consider an XML serialization example where attributes take an important and necessary role. In this example, we will be designing a C# class and streaming it as XML. The C# class definition follows:


	Public class MyClass
	{
		public string myField = "abc";
	}

The above class can be streamed as XML as follows:


	MyClass myObject = new MyClass;
	XmlSerializer  xs = new XmlSerializer(typeof(myObject));
	StringWriter sw = new StringWriter();
	Xs.serialze(sw,myObject);

This will produce an XML as follows:


<MyClass>
	<myField>abc</myField>
</MyClass>

Let us now introduce attributes so that the generated XML can be tailored.


	[XmlRoot("MyXmlClass")]
	Public class MyClass
	{
		[XmlElement(ElementName="myXmlField")]
		public string myField = "abc";
	}

This will produce an XML as follows:


<MyXmlClass>
	<myXmlField>abc</myXmlField>
</MyXmlClass>

Related Reading

.NET & XML
By Niel Bornstein

There are many more attributes in XML serialization to control the serialization process. You can see these attributes in the references section of this article. But for now, these two attributes are sufficient for our discussion.

When I have encountered these attributes, my first problem was figuring out how to read this attribute specification. What is the meaning of "[XmlRoot("somename")]"? I could guess that the programmers were trying to set the name of the root node of the XML, but the syntax is unclear. In one case, they are specifying a string directly inside quotes; in another case, they are using some sort of a key to specify the string against.

Sometimes they use commas to separate multiple attributes, and sometimes they stack them. Sometimes there are repeated attributes and sometimes not. Sometimes they seem to be applied to fields and sometimes to classes. It seemed to be a very inconsistent set of rules.

But it turns out there is a method to this madness, after all. The key to understanding attributes lies in the fact that they represent .NET classes (first-class citizens of the .NET world). Let us investigate this aspect of attributes:

  • Attributes are classes. When you specify an attribute, you are actually allowing .NET to instantiate a class represented by that attribute. Because of this, the specification of an attribute resembles the syntax of a class constructor, where all of the arguments to the constructor are static and specified at compile time.
  • Attribute names are class names. Because an attribute is a class, an attribute's name is a classname. A classname includes a namespace and so does an attributes name. So what class does XmlRoot represent? This name is a short cut for System.Xml.Serialiation.XmlRootAttribute. I will show you later how this long name shrinks to just XmlRoot.
  • Attributes use namespaces. Because attributes are classes, you need to specify the "using" clause to import the namespace they are part of. So in the above case, by importing the System.Xml.Serialization namespace, you can shorten the name to XmlRootAttribute.
  • Attributes have multiple constructors, like classes. Because an attribute specification is identical to the constructor, what goes between the parentheses of the attribute are the arguments to the class' constructor. Like any other managed class, an attribute can have multiple constructors. In fact, if you do not specify a constructor (again, like managed classes), you can simply specify the name of the attribute.
  • An attribute's constructors do something more. An exception to the above construction rule is that the attribute specification allows you not only to construct a class, but also to set its public properties. This means that if the class has some public properties, the specification needs to accommodate a way to set these properties as well. The construction syntax is extended to manage this need. The public properties are named and specified following the regular arguments using a key/value pair syntax.
  • Attributes constructor invocation can take multiple forms. The specification of an attribute can take multiple forms, all leading to its construction and the setting of its public properties. It doesn't matter how you end up specifying an attribute; you derive a final, fully qualified construction specification for the attribute, where you will have the constructor arguments followed by the optional public properties.
  • How to look up attribute documentation. Documentation of an attribute (because it's a class) is available, just like the documentation of any other managed class. You can look up the arguments of its constructor and you can look up the public properties of the attribute class. An attribute documentation will also specify the programming constructs for which this attribute is applicable.
  • Dealing with the public properties of attributes. Public properties of an attribute class are set using key/value pair combinations followed by the mandatory arguments of its constructor.
  • Multiple styles of specifying attributes. When encountering attributes, the things that throw you off the most are the varieties of syntax that can be used to specify an attribute. Let me address the common usage patterns of specifying an attribute.

Usage

[namespace.attributeNameAttribute](arg1,arg2,param1=value,param2=value);
[attributeNameAttribute](arg1,arg2,param1=value,param2=value);
[attributeName](arg1,arg2,param1=value,param2=value);

The first line above identifies a fully qualified class name of an attribute, followed by the constructor arguments, followed by the public properties. The second line omits the namespace from the fully qualified name. The third line omits the Attribute suffix from the class name. This is purely a convenience offered by the programming facilities. Let us see some examples demonstrating these variations.

Attribute Examples


1. [System.Xml.Serialization.XmlRootAttribute(ElementName="LOAD_TENDER_TRIP", 
                                              Namespace="", IsNullable=false)]
2. [System.Xml.Serialization.XmlRootAttribute("LOAD_TENDER_TRIP", 
                                              Namespace="", IsNullable=false)]
3. [XmlRootAttribute(ElementName="LOAD_TENDER_TRIP", 
                     Namespace="", IsNullable=false)]
4. [XmlRoot(ElementName="LOAD_TENDER_TRIP", Namespace="", IsNullable=false)]
  • 1 is allowed because this attribute has a default constructor and three public properties, which are set in that line.
  • 2 is allowed because this attribute also has a constructor that takes one argument. Two public properties are also set in the same line.
  • In line 3, the namespace of the class is omitted, but requires that you import the name space with using System.Xml.Serialization.
  • In line 4, the Attribute suffix is omitted.

Attribute Specification Rules

We can summarize the various rules governing attributes like so:

  1. Attributes are specified inside of square brackets ([]) and are usually specified right above the programming construct to which they belong.
  2. Convention dictates that all attributes classes end their names with Attribute.
  3. The name of an attribute is the name of its class, less the Attribute specified in rule 2.
  4. If the namespace is imported, you can just use the unqualified class name of the attribute while specifying it. This is similar to the usage of specifying a class name, where you can omit the namespace as long as the namespace is in scope.
  5. The suffix Attribute can be omitted from the specification. .NET will add this suffix to locate the class. If the original class does not have an Attribute suffix, then the name (as it is) is used to look for the class.
  6. You can have attributes stacked up one on top of the other to specify multiple attributes to the same programming construct. For example:
    
    [attribute1()]
    [attribute2()]
  7. Attributes can be lined up with a comma separator inside of the square brackets. For example:
    [attribute1(), attribute2()
  8. Some attributes allow multiple instances and some don't. The compiler will give an error if it is set non-multiple and if you try to repeat it.
  9. Constructor arguments are followed by optional, public property specifications. If there is a default constructor, then you can omit the brackets. For example:
    [attribute1]
  10. The IDE knows to go to the right help section for that attribute class, even if the attribute name is in its short form (sans Attribute and sans Namespace).

References

  1. "Programming C#: Attributes and Reflection," by Jesse Liberty at O'Reilly This is an excellent and fairly complete reference on the subject.
  2. "Attributes that Control XML Serialization" in the .NET Framework Developers Guide. This reference lists the complete set of XML attributes that are used in XML serialization.
  3. "Controlling XML Serialization Using Attributes" in the .NET Framework Developers Guide. This reference goes into the detailed process of effectively using these attributes to serialize such elements as arrays and collections.

Satya Komatineni is the CTO at Indent, Inc. and the author of Aspire, an open source web development RAD tool for J2EE/XML.


Return to ONDotnet.com