Tải bản đầy đủ (.pdf) (24 trang)

Attributes and Reflection pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (901.81 KB, 24 trang )

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.


The .NET Framework is equipped with a number of predefined attributes. The code to
examine the predefined attributes and act upon the values they contain is also
incorporated as a part of the runtime and .NET Framework Software Development Kit
(SDK).
Attributes are applied to different elements of the code. These elements include
assemblies, modules, classes, structs, enums, constructors, methods, properties, fields,
events, interfaces, parameters, return values, and delegates. Information about attributes is
stored with the metadata of the elements they are associated with.
The following syntax enables you to specify an attribute:
[attribute(positional_parameters,name_parameter=value, )]
element
In the preceding syntax, an attribute name and its values are specified within square
brackets ([ ]) before the element to which the attribute is applied. Attributes might require
one or more parameters, positional or named. Positional parameters are used to specify
essential information of an attribute, whereas named parameters are used to convey
optional information of an attribute.
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 Common
Language Runtime (CLR), and they are integrated into .NET. Custom attributes are
attributes that you create according to your requirement.
Introducing Attributes
A
pplying Attributes
13.4 Attributes and Reflection
¤NIIT
Some commonly used predefined attributes provided with .NET Framework are:
 Conditional: Causes conditional compilation of method calls, depending on the
specified value such as
Debug or Trace. For example, it displays the values of
variables, when debugging a code. However, this attribute only determines the action

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

working of the
TempConvert() method.
 DllImport: Calls an unmanaged code in programs developed outside the .NET
environment. An example of such a program is the standard C program compiled
into DLL files. By using the DllImport attribute, the unmanaged code residing in
DLLs can be called from the managed C# environment.
Using Predefined Attributes
Attributes and Reflection 13.5
¤NIIT
The following code is an example of using DllImport attribute:
using System;
System.Runtime.InteropServices;
class GenerateBeeps
{
[DllImport(.kernel32.dll.)]
public static extern bool Beep(int f, int d);
static void Main()
{
Beep(1000,111);
}
}
The preceding code uses the Beep() method defined in kernel32.dll and
parameters
f and d signify the frequency and duration of beep to generate.
 Obsolete: Enables you to inform the compiler to discard a piece of target element
such as a method of a class. For example, when a new method is being used in a
class but you still want to retain the old method in that class, as a developer, you can
mark the old method as obsolete. You mark the old method as obsolete by displaying
a message stating that instead of the old method, the new method should be used.
The following code is an example of using

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:

// Bug # 122 fixed by Sara Levo on 8/12/2006.
Although, the preceding comment statement gives some information in the source code,
but it gives no direct association to
Bug # 122, information of which might be stored in
the bug database. In such a situation, the custom attribute can help replace the preceding
code statement with the following code statement:
[BugFixingAttribute(122,"Sara Levo","8/12/2006") Remarks="Data Type
Mismatch at Line 44 "]
A simple program can be written to read through the metadata to find the bug fixing
notations and to help update the bug database. Metadata is data about data. In other
words, it is information that is used to describe other data.
To create custom attributes, you need to:
1. Define a custom attribute
2. Name the custom attribute
3. Construct the custom attribute
4. Apply the custom attribute to a target element
Defining a Custom Attribute
A new custom attribute class is derived from the System.Attribute system class, as
shown in the following code:
public class BugFixingAttribute : System.Attribute
You need to then apply the attribute target using a predefined attribute to the new custom
attribute class,
AttributeUsage, as shown in the following code statement:
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
The AttributeUsage attribute allows two arguments. One argument is a set of flags that

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

Assembly only
Class
Instances of the class
ClassMembers
Classes, structs, enums, constructors, methods,
properties, fields, events, delegates, and interfaces
Constructor
Class constructors
Delegate
Delegate methods
Enum
Defined enumeration
Event
Defined events
Field
Fields
Interface
Interfaces
13.8 Attributes and Reflection
¤NIIT
Member Name Attribute Targets
Method
Defined methods
Module
A single module
Parameter
Parameters of a method
Property
Properties (both get and set, if implemented)
Struct

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

{
get
{
return Remarks;
}
set
{
Remarks = value;
}
}
It is common to create read-only properties for the positional parameters:
public int BugNo
{
get
{
return BugNo;
}
}
Applying the Custom Attribute
The attribute can be applied by placing it immediately before its target. To test the
BugFixAttribute attribute for the preceding example, you can create a program for a
simple class named
Calculator and give it four functions. You need to assign the
BugFixAttribute to the target element class to record its code-maintenance history, as
shown in the following code snippet:
[BugFixingAttribute(125,"Sara Levo","08/15/06", Remarks="Return
object not specified")]
[BugFixingAttribute(159,"Sara Levo","08/17/06", Remarks="Data Type
Mismatch")]
public class Calculator

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

public int BugNo
{
get
{
return bugNo;
}
}
public string DateFixed
{
get
{
return dateFixed;
}
}
public string Developer
{
get
{
return developer;
}
}
public string Remarks
{
get
{
return remarks;
}
set
{
remarks = value;

}
}
}
[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)

{
return num1 / num2;
}
}
public class EntryPoint
{
public static void Main()
{
Calculator MyObj = new Calculator();
Console.WriteLine("The sum of specified two nos are: {0}",
MyObj.Add(15,20.5));
Console.ReadLine();
}
}
}
After executing the preceding code, the program output would be displayed. Open the
Attribute_Example.exe using the MSIL Disassembler (IL DSAM.exe). Following are the
steps to open Attribute_Example.exe using the MSIL Disassembler:
1. Select StartÆAll ProgramsÆMicrosoft .NET Framework SDK
v2.0ÆToolsÆMSIL Disassembler.
2. Select FileÆOpen. The Open dialog box is displayed.
3. Select the Attribute_Example.exe file from the Debug folder of the project.
4. Click the OK button. The IL DASM window is displayed.
13.12 Attributes and Reflection
¤NIIT
5. Expand the Attribute_ExampleÆAttribute_Example.Calculator node, as shown
in the following figure.
The IL DASM Window
Attributes and Reflection 13.13
¤NIIT

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

In the preceding code statement the typeof operator on the Calculator type, returns an
object of the
Type type class. The Type class is the root of the reflection class and it is
the primary way to access metadata. It encapsulates a representation of the type of an
object. The
MemberInfo object of System.Reflection namespace derives from the Type
class that encapsulates information about the members of a class.
Then, you need to initiate a call on the
GetCustomAttributes() function. This function
returns an array of objects, each of type
BugFixingAttribute.
Retrieving Metadata Using Reflection
V
iewing Metdata
Attributes and Reflection 13.15
¤NIIT
The following code shows the modified Main() method of the bug fixing example:
public class EntryPoint
{
public static void Main()
{
Calculator MyObj = new Calculator();
Console.WriteLine("The sum of specified two nos are: {0}",
MyObj.Add(15,20.5));
Type type = typeof(Calculator);

// iterating through the attributes of the Calculator class
foreach (Object attributes in
type.GetCustomAttributes(false))
{

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

Console.WriteLine("Remarks: {0}",
MyBFAObjM.Remarks);
}
}
}
Console.ReadLine();
}
}
13.16 Attributes and Reflection
¤NIIT
The preceding code prints all the bug fixing related information defined using attributes.
The following figure displays the output of the preceding code.
Output of the Modified Main() Method
Reflection also helps to explore and examine the contents of an assembly. It helps find the
types associated with a module; the methods, fields, properties, and events associated with
a type, as well as the signatures of each type of methods; the interfaces supported by the
type; and the type's base class. The type discovery information can also be viewed
through the Object Browser window of Visual Studio .NET IDE.
Binding a method at runtime is called late-binding. Reflection provides the flexibility of
choosing an object you will bind at runtime and calling it programmatically. For example,
by using late-binding, you can enable your program to interact with calendar or the other
components of a running word processing application such as Microsoft Word.
Reflection emit allows creation of new types at runtime and further use those types to
perform certain tasks. For example, an assembly can be defined to execute dynamically or
Performing Type Discovery
Late Binding to Methods and Properties
Reflection Emit
Attributes and Reflection 13.17
¤NIIT
to save itself to disk. Furthermore, reflection emit enables you to define new modules and

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.

8. Select the Rename option and type the new name as DescriptionAttribute.cs.
Activity: Creating and Querying Custom Attribute
Information
Attributes and Reflection 13.19
¤NIIT
9. Double-click the DescriptionAttribute.cs file in the Solution Explorer window.
The Code view of DescriptionAttribute.cs file is displayed.
10. Replace the existing code with the following code:
using System;
using System.Reflection;
namespace AttribNamespace
{
// create DescriptionAttribute custom attribute to be assigned
to class members
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
[DescriptionAttribute("This class contains defination of
Description attribute", 1.0)]
public class DescriptionAttribute : System.Attribute
{
// attribute constructor for positional parameters
public DescriptionAttribute(string Description, double
Version)
{
this.description= Description;
this.version= Version;
}
protected String description;
public String Description
{
get

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

}
public double Multiply(Double num1, Double num2)
{
return num1 * num2;
}
public double Divide(Double num1, Double num2)
{
return num1/num2;
}
}

[DescriptionAttribute("This class contains the Main method",
2.0)]
public class EntryPoint
{
public static void Main()
{
Calculator MyObj = new Calculator();
Console.WriteLine("The sum of specified two nos are:
{0}", MyObj.Add(15, 20.5));
Type type = typeof(Calculator);
// Specific call should me made to retrieve an
attribute properties
// when two or more custom attributes are there in an
application
foreach (Object attributes in
type.GetCustomAttributes(typeof(DescriptionAttribute),
false))
{
DescriptionAttribute MyDAObj =

(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 following window verifies the output of the executed program.
Output of the Calculator Application
13.22 Attributes and Reflection
¤NIIT
1. State whether the following statement is true or false:
Reflection emit allows creation of new types at runtime.
2. Consider the following statements:
Statement A: Named parameters are used to specify essential information of an
attribute.
Statement B: Positional parameters are used to convey optional information in an
attribute.
a. Statement A is false, Statement B is true.
b. Statement B is true, Statement B is false.
c. Both Statements A and B are true.
d. Both Statements A and B are false.
3. Which predefined attribute allows you to call an unmanaged code in programs
developed outside the .NET environment?
a. Conditional
b. DLLImport
c. Obsolete
d. WebMethod
4. Attribute property ________ indicates that if an attribute is applied to base class and
all its derived classes.
5. Which window displays the complete metadata information of an application
containing the custom attributes?
Practice Questions
Attributes and Reflection 13.23
¤NIIT
In this chapter, you learned that:
 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.
 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

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×