Attributes and
Reflection
Chapter 13
Attributes are a simple technique for adding
metadata information and behavior to code within
applications. You use the reflection technique to
pick the attribute related information at runtime.
This chapter introduces attributes and reflection and
the functions they perform in C# applications. This
chapter discusses attribute syntax, and how to use
some of the predefined attributes. This chapter
discusses also discusses how to create customized
user-defined attributes. In addition, this chapter
discusses reflection and how to use it to extract
attribute related information.
In this chapter, you will learn to:
Describe attributes
Retrieve metadata using reflection
Objectives
Attributes and Reflection 13.3
¤NIIT
An object is described by the values of its attributes. For example, a car can be described
by its make, model, or color. Similarly, a C# program has certain attributes which depict
and influence its behavior, for example, compiler instructions.
An attribute is a declarative tag that is used to convey information to runtime about the
behavior of programmatic elements such as classes, enumerators, and assemblies. A
declarative tag is depicted by square ([ ]) brackets placed above the definition of an
element such as a class or a method.
Attributes are used for adding metadata, such as compiler instructions and other
information such as comments, description, methods, and classes to a program.
that will occur when a method is called. If conditional compilation of a method is
required, the
#if and #endif directives are used in code. The methods to which you
can apply a conditional attribute are subject to a number of restrictions. In particular,
they must have a return type of void and must not be marked as an override, and the
implementation of the method should be from an inherited interface.
For example:
[Conditional("DEBUG")]
The preceding statement ensures that the target element, whether a class or a method
ensures use of that element in debugging mode only. The other value of this attribute
can be:
[Conditional("TRACE")]
WebMethod: Identifies the exposed method in a Web service. A Web service is a
Web application that allows you to expose business functionality to other
applications. Furthermore, the various properties of this attribute enable you to
configure the behavior of the exposed method.
The following code is an example of using
WebMethod attribute:
[WebMethod(Description="Converts temperature from Fahrenheit to
Celsius.")]
public double TempConvert(double myTemp)
{
return ((myTemp - 32) * 5) / 9;
}
The preceding code provides an exposed method of a Web service which converts
temperature from Fahrenheit to Celsius. The
WebMethod attribute definition above
TempConvert() method tells the compiler that it is an exposed method and the
Description property of the WebMethod attribute provides information about
Obsolete attribute:
using System;
public class MyClass
{
[Obsolete("Don't use the A() method, instead use B() method",
true)]
static void A() { }
static void B() { }
public static void Main( )
{
A();
}
}
In the preceding code, the first parameter is string, which contains the message. The
second parameter tells the compiler to treat the use of the element as an error. The
default value is false, which means compiler generates a warning for this.
The .NET Framework allows creation of custom attributes, which can be used to store
information and can be retrieved at run time. This information can be related to any target
element depending upon the design and the need of an application.
Creating Custom Attributes
13.6 Attributes and Reflection
¤NIIT
Consider this scenario. A software development company wants to keep track of all the
bug fixes as a part of its development process. Although, the company maintains a bug
database generated during and after the development process, the program manager wants
to attach proper bug fixing reports in code itself. To address this requirement, developers
might add comment statements to code. The following code statement displaying a
comment is a bug fix example:
indicates the target element. To continue with the bug fixing example, the
Attributes and Reflection 13.7
¤NIIT
AttributeUsage
attribute will be the class and its constructor, fields, methods, and
properties.
The other argument is a flag that indicates whether a given element might be applied with
more than one such attribute. In the preceding code, the
AllowMultiple property is set to
true, indicating that more than one BugFixingAttribute can be applied to class and its
members.
Besides the
AllowMultiple property there are other properties that can be used with the
attributes. These properties are:
Inherited: A boolean value “true” for this property indicates that if an attribute is
applied to base class and all its derived classes. A value of “false” stops the attribute
when it is applied to a subclass.
ValidOn: This property helps define the target elements on which the custom
attribute can be applied. The element to which you attach an attribute is called an
attribute target. The AttributeTargets enumerator is used for setting all the
possible attribute targets.
The following table lists the various member names of the
AttributeTargets
enumerator.
Member Name Attribute Targets
All
Elements including assembly, class, class member,
delegate, enum, event, field, interface, method,
module, parameter, property, or struct
Assembly
Structs
AttributeTargets Enumerator
Naming the Custom Attribute
Let us continue with the bug fixing example in which the new custom attribute is named
as
BugFixingAttribute. The normal convention is to append the word Attribute to the
attribute name. The compiler supports appending by allowing you to call the attribute
with the shorter version of the name.
Therefore, the attribute can be written as shown in the following code statement:
[BugFixing(122,"Sara Levo","8/12/2006") Remarks="Data Type
Mismatch at Line 44 "]
The compiler first looks for the definition of an attribute named BugFixing. When it does
not find the definition it looks for the definition with the name,
BugFixingAttribute.
Constructing the Custom Attribute
Every attribute must contain at least one constructor. In the following bug fixing example,
the bug number, developer's name, and fixed date are positional parameters and remarks
is a named parameter. Positional parameters are passed through the constructor in the
order declared in the constructor, as shown in the following code snippet:
public BugFixingAttribute(int BugNo, string Developer,
string DateFixed)
{
this.BugNo = BugNo;
this.Developer = Developer;
this.DateFixed = DateFixed;
}
Attributes and Reflection 13.9
¤NIIT
Named parameters are implemented as properties, as shown in the following code snippet:
public string Remarks
The BugFixAttribute attribute will be stored with the metadata. The following code
shows the complete listing of the bug fixing program:
using System;
using System.Reflection;
namespace Attribute_Example
{
// create a custom attribute to be assigned to class and its
members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor | AttributeTargets.Field |
13.10 Attributes and Reflection
¤NIIT
AttributeTargets.Method | AttributeTargets.Property, AllowMultiple
= true)]
public class BugFixingAttribute : System.Attribute
{
private int bugNo;
private string developer;
private string dateFixed;
public string remarks;
// attribute constructor for positional parameters
public BugFixingAttribute(int BugNo, string Developer, string
DateFixed)
{
this.bugNo = BugNo;
this.developer = Developer;
this.dateFixed = DateFixed;
}
}
}
}
[BugFixingAttribute(125,"Sara Levo","08/15/06", Remarks="Return
object not specified")]
[BugFixingAttribute(159,"Sara Levo","08/17/06", Remarks="Data Type
Mismatch")]
Attributes and Reflection 13.11
¤NIIT
public class Calculator
{
public double Add(Double num1, Double num2)
{
return num1+num2;
}
public double Subtract(Double num1, Double num2)
{
return num1 - num2;
}
[BugFixingAttribute(155, "Sara Levo", "08/16/06")]
public double Multiply(Double num1, Double num2)
{
return num1 * num2;
}
[BugFixingAttribute(156, "Sara Levo", "08/16/06")]
public double Divide(Double num1, Double num2)
6. Press CTRL+M. The MetaInfo window is displayed. The MetaInfo window
displays the complete metadata information containing the created BugFixing
custom attributes, as shown in the following figure.
The MetaInfo Window
13.14 Attributes and Reflection
¤NIIT
Reflection is used in the process of obtaining type information at runtime. The classes that
give access to the metadata of a running program are in the
System.Reflection
namespace.
The
System.Reflection namespace contains classes that allow programmers to obtain
information about the application that is running and to dynamically add types, values,
and objects to that application.
Reflection is generally used for the following tasks:
Viewing metadata: Allows viewing attribute information from the code at runtime
Performing type discovery: Allows examining the various types in an assembly and
instantiate those types
Late binding to methods and properties: Allows the developer to call properties
and methods on dynamically instantiated objects using type discovery
Reflection emit: Allows you to create new types at runtime and then to use those
types to perform tasks
To view metadata using reflection, the
MemberInfo object of the System.Reflection
namespace needs to be initialized. This object helps discover the attributes of a member
and to provide access to metadata. Taking the bug fixing example further, use reflection
to read metadata in the
Calculator class. To do this you need to define an object of the
Calculator class, as shown in the following code statement:
Type type = typeof(Calculator);
BugFixingAttribute MyBFAObj =
(BugFixingAttribute)attributes;
if (null != MyBFAObj)
{
Console.WriteLine("\nBug #: {0}", MyBFAObj.BugNo);
Console.WriteLine("Developer: {0}",
MyBFAObj.Developer);
Console.WriteLine("Date Fixed: {0}",
MyBFAObj.DateFixed);
Console.WriteLine("Remarks: {0}", MyBFAObj.Remarks);
}
}
// iterating through the attributes of all the methods of
a Calculator class
foreach (MethodInfo method in type.GetMethods())
{
foreach (Attribute attributes in
method.GetCustomAttributes(true))
{
BugFixingAttribute MyBFAObjM =
(BugFixingAttribute)attributes;
if (null != MyBFAObjM)
{
Console.WriteLine("\nBug #: {0} for Method: {1}",
MyBFAObjM.BugNo, method.Name);
Console.WriteLine("Developer: {0}",
MyBFAObjM.Developer);
Console.WriteLine("Date Fixed: {0}",
MyBFAObjM.DateFixed);
new types with methods.
13.18 Attributes and Reflection
¤NIIT
Problem Statement
John is a developer in a software development company. The program manager wants
John to ensure proper documentation of the business logic of the Calculator application as
a part of development process. Although, the company maintains a separate sheet to
describe the use of classes and their version number, the program manager wants to attach
that sheet to classes.
[Hint: Use the Calculator class given in the preceding section for providing the business
logic.]
Solution
To create a console-based application for Calculator application, John needs to perform
the following tasks:
1. Create a console-based application.
2. Build and execute an application.
Task 1: Creating a Console-Based Application
To create a console-based calculator application, John needs to perform the following
steps:
1. Select StartÆAll ProgramsÆMicrosoft Visual Studio 2005ÆMicrosoft Visual
Studio 2005. The Start Page - Microsoft Visual Studio window is displayed.
2. Select FileÆNewÆProject. The New Project window is displayed.
3. Select the project type as Visual C# from the Project types pane and Console
Application from the Templates pane.
4. Type the name of the new project as AttribNamespace in the Name text box.
5. Specify the location where the new project is to be created as
c:\Chapter13\Activity1 in the Location combo box.
6. Click the OK button.
7. Open the Solution Explorer window and right-click the Program.cs file. The
shortcut menu is displayed.
{
return this.description;
}
}
protected Double version;
public Double Version
{
get
{
return this.version;
}
set
{
this.version = value;
}
}
}
[DescriptionAttribute("This class contains two methods", 1.0)]
public class Calculator
{
public double Add(Double num1, Double num2)
{
return num1 + num2;
}
13.20 Attributes and Reflection
¤NIIT
public double Subtract(Double num1, Double num2)
{
return num1 - num2;
(DescriptionAttribute)attributes;
if (null != MyDAObj)
{
Console.WriteLine("\nClass : Calculator -
Description :{0} - Version {1}",
MyDAObj.Description, MyDAObj.Version);
}
}
type = null;
type = typeof(EntryPoint);
foreach (Object attributes in
type.GetCustomAttributes(false))
{
DescriptionAttribute MyDAObj =
(DescriptionAttribute)attributes;
Console.WriteLine("\nClass : EntryPoint -
Description :{0} - Version {1}",
MyDAObj.Description, MyDAObj.Version);
}
Attributes and Reflection 13.21
¤NIIT
Console.ReadLine();
}
}
}
Task 2: Building and Executing an Application
To build and execute the application, John needs to perform the following steps:
1. Select Ctrl+Shift+b or press F6 to build the solution.
2. Select DebugÆStart Debugging or press F5 to execute the application.
3. Verify the output of the application.
the behavior of programmatic elements such as classes, enumerators, and assemblies.
The .NET Framework supports two categories of attributes to be used in C#
programs: predefined and custom.
Predefined attributes are supplied as part of the CLR, and they are integrated into
.NET. Custom attributes are attributes that you create according to your requirement.
The element to which you attach an attribute is called an attribute target.
Reflection is used in the process of obtaining type information at runtime.
Reflection is generally used for the following tasks:
z Viewing metadata
z Performing type discovery
z Late binding to methods and properties
z Reflection emit
Summary
13.24 Attributes and Reflection
¤NIIT
Exercise 1
Write a program, to create BugFixingAttribute custom attribute to be assigned to class
members and DescriptionAttribute custom attribute to be assigned to class members.
Merge the Bugs Fixing attribute and Class description attribute together in a single
application and use reflection to retrieve data from the same.
Exercises