Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / MS Press - Msdn Training Programming Net Framework With C#

.pdf
Скачиваний:
173
Добавлен:
12.02.2016
Размер:
16.87 Mб
Скачать

Module 17 (Optional): Attributes

31

 

 

 

Exercise 2

Defining and Using a Custom Attribute

In this exercise, you will create a custom attribute called DeveloperInfoAttribute. This attribute will allow the name of the developer and, optionally, the creation date of a class to be stored in the metadata of that class. This attribute will permit multiple use because more than one developer might be involved in the coding of a class.

You will then write a method that retrieves and displays all of the

DevloperInfoAttribute values for a class.

! Define a custom attribute class

1.Using Visual Studio .NET, create a new Microsoft Visual C# project, using the information shown in the following table.

Element

Value

 

 

Project Type

Visual C# Projects

Template

Class Library

Name

CustomAttribute

Location

install folder\Labs\Lab17\Starter

2.Change the name and file name of class Class1 to DeveloperInfoAttribute. Make sure that you also change the name of the constructor.

3.Specify that the DeveloperInfoAttribute class is derived from

System.Attribute.

This attribute will be applicable to classes, enums, and structs only. It will also be allowed to occur more than once when it is used.

4.Add the following AttributeUsage attribute before the class definition:

[AttributeUsage(AttributeTargets.Class | !AttributeTargets.Enum | AttributeTargets.Struct, !AllowMultiple=true)]

5.Document your attribute with a meaningful summary (between the <summary> tags). Use the exercise description to help you.

6.The DeveloperInfoAttribute attribute requires the name of the developer of the class as a mandatory parameter and takes the date that the class was written as an optional string parameter. Add private instance variables to hold this information, as follows:

private string developerName; private string dateCreated;

7.Modify the constructor so that it takes a single string parameter that is also called developerName, and add a line of code to the constructor that assigns this parameter to this.developerName.

8.Add a public string read-only property called Developer that can be used to get the value of developerName. Do not write a set accessor.

32Module 17 (Optional): Attributes

9.Add another public string property that is called Date. This property should have a get accessor that reads dateCreated and a set accessor that writes dateCreated.

10.Compile the class and correct any errors.

Because the class is in a class library, the compilation process will produce a DLL (CustomAttribute.dll) rather than a stand-alone executable program. The complete code for the DeveloperInfoAttribute class follows:

namespace CustomAttribute

{

using System;

///<summary>

///This class is a custom attribute that allows

///the name of the developer of a class to be stored

///with the metadata of that class.

///</summary>

[AttributeUsage(AttributeTargets.Class | !AttributeTargets.Enum | AttributeTargets.Struct, !AllowMultiple=true)]

public class DeveloperInfoAttribute: System.Attribute

{

private string developerName; private string dateCreated;

//Constructor. Developer name is the only

//mandatory parameter for this attribute.

public DeveloperInfoAttribute(string developerName)

{

this.developerName = developerName;

}

public string Developer

{

get

{

return developerName;

}

}

// Optional parameter public string Date

{

get

{

return dateCreated;

}

set

{

dateCreated = value;

}

}

}

}

Module 17 (Optional): Attributes

33

 

 

 

! Add a custom attribute to a class

1.You will now use the DeveloperInfo attribute to record the name of the developer of the Rational number class. Open the Rational.sln project in the install folder\Labs\Lab17\Starter\Rational folder.

2.Perform the following steps to add a reference to the CustomAttribute library that you created earlier:

a.In Solution Explorer, expand the Rational tree.

b.Right-click References, and then click Add Reference.

c.In the Add Reference dialog box, click Browse.

d.Navigate to the install folder\Labs\Lab17\Starter\ CustomAttribute\Bin\Debug folder, and click CustomAttribute.dll.

e.Click Open, and then click OK.

3.Add a CustomAttribute.DeveloperInfo attribute to the Rational class, specifying your name as the developer and the current date as the optional date parameter, as follows:

[CustomAttribute.DeveloperInfo("Your Name", !Date="Today")]

4.Add a second developer to the Rational class.

5.Compile the Rational project and correct any errors.

6.Open a Visual Studio .NET Command Prompt window and navigate to the install folder\Labs\Lab17\Starter\Rational\Bin\Debug folder.

This folder should contain your Rational.exe executable.

7.Run the MSIL disassembler and open Rational.exe.

8.Expand the Rational namespace in the tree view.

9.Expand the Rational class.

10.Near the top of the class, notice your custom attribute and the values that you supplied.

11.Close the MSIL disassembler.

34Module 17 (Optional): Attributes

!Use reflection to query attribute values

Using the MSIL disassembler is only one way to examine attribute values. You can also use reflection in C# programs. Return to Visual Studio, and edit the TestRational class in the Rational project.

1.In the Main method, create a variable called attrInfo of type

System.Reflection.MemberInfo, as shown in the following code:

public static void Main( )

{

System.Reflection.MemberInfo attrInfo;

...

2.You can use a MemberInfo object to hold information about the members of a class. Assign the Rational type to the MemberInfo object by using the typeof operator, as follows:

attrInfo = typeof(Rational);

3.The attributes of a class are held as part of the class information. You can retrieve the attribute values by using the GetCustomAttributes method. Create an object array called attrs, and use the GetCustomAttributes method of attrInfo to find all of the custom attributes used by the Rational class, as shown in the following code:

object[ ] attrs = attrInfo.GetCustomAttributes(false);

4.Now you need to extract the attribute information that is stored in the attrs array and print it. Create a variable called developerAttr of type

CustomAttribute.DeveloperInfoAttribute, and assign it the first element in the attrs array, casting as appropriate, as shown in the following code:

CustomAttribute.DeveloperInfoAttribute developerAttr; developerAttr =

!(CustomAttribute.DeveloperInfoAttribute)attrs[0];

Note In production code, you would use reflection rather than a cast to determine the type of the attribute.

5.Use the get accessor of the DeveloperInfoAttribute attribute to retrieve the Developer and Date attributes and print them out as follows:

Console.WriteLine("Developer: {0}\tDate: {1}", !developerAttr.Developer, developerAttr.Date);

6.Repeat steps 4 and 5 for element 1 of the attrs array.

You can use a loop if you want to be able to retrieve the values of more than two attributes.

Module 17 (Optional): Attributes

35

 

 

 

7. Compile the project and correct any errors.

The completed code for the Main method is shown in the following code:

namespace Rational

{

using System;

// Test harness

public class TestRational

{

public static void Main( )

{

System.Reflection.MemberInfo attrInfo; attrInfo = typeof(Rational);

object[ ] attrs = attrInfo.GetCustomAttributes(false); CustomAttribute.DeveloperInfoAttribute developerAttr; developerAttr =

!(CustomAttribute.DeveloperInfoAttribute)attrs[0]; Console.WriteLine("Developer: {0}\tDate: {1}",

!developerAttr.Developer, developerAttr.Date); developerAttr =

!(CustomAttribute.DeveloperInfoAttribute)attrs[1]; Console.WriteLine("Developer: {0}\tDate: {1}",

!developerAttr.Developer, developerAttr.Date);

}

}

}

Here is an alternative Main that uses a foreach loop:

public static void Main( )

{

System.Reflection.MemberInfo attrInfo; attrInfo = typeof(Rational);

object[ ] attrs = attrInfo.GetCustomAttributes(false);

foreach (CustomAttribute.DeveloperInfoAttribute ! devAttr in attrs)

{

Console.WriteLine("Developer: {0}\tDate: {1}", !devAttr.Developer, devAttr.Date);

}

}

8.When you run this program, it will display the names and dates that you supplied as DeveloperInfoAttribute information to the Rational class.

36

Module 17 (Optional): Attributes

Review

Topic Objective

To reinforce module objectives by reviewing key points.

Lead-in

The review questions cover some of the key concepts taught in the module.

!Overview of Attributes

!Defining Custom Attributes

!Retrieving Attribute Values

*****************************ILLEGAL FOR NON-TRAINER USE******************************

1.Can you tag individual objects by using attributes?

No. Attributes can be associated with classes or other types, or with methods, parameters, return values, constructors, assemblies, delegates, events, interfaces, properties, or fields, but not with individual objects.

2.Where are attribute values stored?

An attribute value is stored with the metadata of the programming element that it was used with.

3.What mechanism is used to determine the value of an attribute at run time?

Reflection.

Module 17 (Optional): Attributes

37

 

 

 

4.Define an attribute class called CodeTestAttributes that is applicable only to classes. It should have no positional parameters and two named parameters called Reviewed and HasTestSuite. These parameters should be of type bool and should be implemented by using read/write properties.

using System; [AttributeUsage(AttributeTargets.Class)]

public class CodeTestAttributes: System.Attribute

{

public bool Reviewed

{

get { return reviewed; } set { reviewed = value; }

}

public bool HasTestSuite

{

get { return hasTestSuite; } set { hasTestSuite = value; }

}

private bool reviewed, hasTestSuite;

}

5.Define a class called Widget, and use CodeTestAttributes from the previous question to mark that Widget has been reviewed but has no test suite.

[CodeTestAttributes(Reviewed=true, HasTestSuite=false)] class Widget

{

...

}

6.Suppose that Widget from the previous question had a method called LogBug. Could CodeTestAttributes be used to mark only this method?

No. CodeTestAttributes can only target whole classes.

Соседние файлы в папке c#