Reflection (reflection) in. Net-part.3

Source: Internet
Author: User
Tags sendmsg
Document directory
  • 1. Introduction to built-in. NET features
  • 2. Custom features (custom attributes)
  • 3. Use reflection to view custom features
Reflection (reflection) in. Net-part.3 reflection (attribute)

Many people may not understand the features, so let's first look at what features are. Think about it. If a messaging system has such a method to send a short message to someone:

// Title: title; Author: author; content: content; receiverid: recipient id
Public bool sendmsg (String title, string author, string content, int receiverid ){
// Do send action
}

We soon discovered that the scalability of listing parameters to the parameter list of methods is very poor. We 'd better define a message class to encapsulate short messages and then pass a message object to the method:

Public class message {
Private String title;
Private string author;
Private string content;
Private int receiverid;
// Omitted
}
Public bool sendmsg (mes1_msg ){
// Do some action
}

In this case, we should delete the old method and replace it with the sendmsg method with better scalability. Unfortunately, we often cannot, because this group of programs may be released as a group of APIS, and the old version of sendmsg () method is already used in many client programs, if we delete the old sendmsg () method when updating the program, the client program that uses the old sendmsg () method cannot work.

What should we do at this time? Of course we can do this through method overloading, so we don't need to delete the old sendmsg () method. However, if the new sendmsg () not only optimizes parameter transfer, but also comprehensively optimizes the algorithm and efficiency, we will be eager to inform the customer that there is a new high-performance sendmsg () method available, but the customer program does not know that a new sendmsg method already exists, what should we do? We can call the programmer who maintains the client program or send an email to him, but this is obviously not convenient enough. It is best to let him compile the project, any call to the old sendmsg () method will be notified by the compiler.

1. Introduction to built-in. NET features

. Net can be used to do this.A feature is an object that can be loaded into the Assembly and Assembly objects. These objects include the Assembly itself, modules, classes, interfaces, structures, constructors, methods, and method parameters, objects loaded with features are called feature targets. A feature is a mechanism for adding metadata (data describing data) to a program. It can provide instructions to the compiler or instructions on data.

Note: The English name of a feature is attribute. In some books, it is translated as "attribute". In other books, it is translated as "feature "; because we usually call the class members that contain get and/or set accessors as "properties", I will use the term "feature" in this article, to distinguish "property ).
The Chinese version of vs2005 uses "attributes ".

1.1 system. obsoleteattribute

Let's use this example to see how the feature solves the above problem: we can add the obsolete feature to the old sendmsg () method to tell the compiler that this method is outdated, then, when the compiler finds that the obsolete-tagged method is used in the program, a warning is given.

Namespace attribute {

Public class message {}

Public class testclass {
// Add the obsolete feature
[Obsolete ("use the new sendmsg (Message MSG) overload method")]
Public static void showmsg (){
Console. writeline ("this is the old sendmsg () method ");
}

Public static void showmsg (Message MSG ){
Console. writeline ("New sendmsg () method ");
}

}

Class program {
Static void Main (String [] ARGs ){
Testclass. showmsg ();
Testclass. showmsg (New message ());
}
}
}

Now, when running this code, we will find that the compiler has given a warning:Warning cs0618: "attribute. testclass. showmsg ()" expired: "Use the new sendmsg (Message MSG) overload method ".By using the features, we can see that the compiler provides a warning to tell the customer that there is a new method available for use, so that after the programmer sees this warning information, the new sendmsg () method is considered.

Note: For simplicity, the testclass class and program are in the same assembly, but they can actually be far away.

1.2 usage of features

Through the above example, we have roughly seen how to use the feature: first, there is a square brackets "[]", followed by the feature name after the left square brackets "[", such as obsolete, then there is a parentheses "()". Unlike a common class, this parentheses can not only write constructor parameters, but also assign values to class attributes. In the obsolete example, only the constructor parameters are passed.

Note: In fact, when you select obsolete with the mouse box and press F12 to define it, you will find that its full name is obsoleteattribute, which inherits from the attribute class. But here we only use obsolete to mark the method. This is. net convention, all features should end with attribute. If the attribute is not added when marking the object, the compiler will automatically find the version with attribute.

Note: When using the constructor parameters, the order of parameters must be the same as that of the constructor declaration. All parameters are also called positional parameters, attribute parameters are also called named parameters ). It will be described in detail below.

2. Examples of custom features (custom attributes) 2.1

If you cannot define a feature and use it by yourself, I don't think you can understand it very well. Now let's build a feature by ourselves. Suppose we have a very common requirement: When we create or update a class file, we need to explain when and who created the class, in future updates, we also need to explain when the updated content will be updated. You can record or not record the updated content. What would you do in the past? Is it like this to add a comment to the class above the class:

// Update: Matthew, 2008-2-10 , Modify tostring () method
// Update: Jimmy,
// Create: Zhang Ziyang, 2008-1-15
Public class democlass {
// Class body
}

This can indeed be recorded, but what if one day we want to save these records to the database for backup? Do you want to view the source files one by one, find out the comments, and insert them into the database one by one?

Through the definition of the above feature, we know that the feature can be used to add metadata to the type, which can be used to describe the type. In this case, features should be used. In this example, the metadata should be: annotation type ("Update" or "CREATE"), modifier, date, and remarks (optional ). The target type of the feature is the democlass class.

Based on our understanding of the metadata appended to the democlass class, we first create a class recordattribute that encapsulates the metadata:

Public class recordattribute {
Private string recordtype; // record type: update/create
Private string author; // author
Private datetime date; // update/create date
Private string memo; // remarks

// Constructor. The constructor parameters are also called "location parameters" in features ".
Public recordattribute (string recordtype, string author, string date ){
This. recordtype = recordtype;
This. Author = author;
This. Date = convert. todatetime (date );
}

// For location parameters, only get accessors are provided.
Public String recordtype {get {return recordtype ;}}
Public String author {get {return author ;}}
Public datetime Date {get {return date ;}}

// Construct an attribute, which is also called "name parameter" in a feature"
Public String memo {
Get {return memo ;}
Set {memo = value ;}
}
}

Note: The date parameter of the constructor must be a constant, type, or constant array. Therefore, the datetime type cannot be directly transferred.

This class not only looks like it, but is actually no different from a common class. Obviously, it cannot be changed to a feature because it is followed by an attribute. So how can we call it a feature and apply it to a class? Before proceeding to the next step, let's take a look at how the built-in features of. NET are defined:

Namespace system {
[Serializable]
[Attributeusage (6140, inherited = false)]
[Comvisible (true)]
Public sealed class obsoleteattribute: attribute {

Public obsoleteattribute ();
Public obsoleteattribute (string message );
Public obsoleteattribute (string message, bool error );

Public bool iserror {Get ;}
Public String message {Get ;}
}
}

2.2 format of adding features (location parameters and naming parameters)

First, we should find that it inherits from the attribute class, which means that our recordattribute should also inherit from the attribute class.

Secondly, we found that three features are used to describe this feature. These three features are: serializable, attributeusage, and comvisible. The serializable feature has been described earlier. comvisible is simply a definition defined by Microsoft to "control the accessibility of individual managed types, members, or all types of COM in a program set ). We should note that:Features are used to describe the metadata of data, and these three features are used to describe features, so they can be considered as "metadata" (meta-metadata ).

Because we need to use "meta data" to describe our defined feature recordattribute, so now we need to first understand "meta data ". Here we should remember that "meta-data" is also a feature. In most cases, we only need to master attributeusage, so now let's take a look at it. First, let's take a look at how attributeusage is loaded to the obsoleteattribute feature.

[Attributeusage (6140, inherited = false)]

Then let's take a look at the definition of attributeusage:

Namespace system {
Public sealed class attributeusageattribute: attribute {
Public attributeusageattribute (attributetargets validon );

Public bool allowmultiple {Get; set ;}
Public bool inherited {Get; set ;}
Public attributetargets validon {Get ;}
}
}

As you can see, it has a constructor which contains a positional parameter and two named parameter ). Note that the validon attribute is not a named parameter because it does not contain the set accessors.

Here, you may wonder why parameters are divided in this way, which is related to the use of features. If attributeusageattribute is a common class, we must use it like this:

// Instantiate an attributeusageattribute class
Attributeusageattribute usage = new attributeusageattribute (attributetargets. Class)
;
Usage. allowmultiple = true; // you can specify the allowmutiple attribute.
Usage. inherited = false; // you can specify the inherited attribute.

However, the feature is written as only one line of code and then closely related to the type (target type) applied by the feature. What should I do? Microsoft's software engineers came up with the following method: no matter the parameters or attributes of the constructor, they are all written into the parentheses of the constructor. For the constructor parameters, the parameters must follow the order and type of the constructor parameters. For properties, they are separated by commas (,) in the format of "property = value. The code above is reduced to the following:

[Attributeusage (attributetargets. Class, allowmutiple = true, inherited = false)]

It can be seen that attributetargets. Class is a constructor parameter (location parameter), while allowmutiple and inherited are actually attributes (named parameters ). The name parameter is optional. In the future, our recordattribute will be used in the same way. (Why do they call parameters? I guess they look more like method parameters .)

Assume that our recordattribute has been OK, and its usage should be as follows:

[Recordattri ("CREATE", "Zhang Ziyang "," 2008-1-15 ", Memo =" this class is for demonstration only ")]
Public class democlass {
// Classbody
}

Recordtype, author, and date are the location parameters, while memo is the naming parameter.

2.3 attributetargets bit mark

We can see from the attributeusage attribute name that it is used to describe the usage of the feature. Specifically, it should first be the types or objects that the marked features can apply. From the code above, we can see that the attributeusage feature constructor accepts a attributetargets type parameter. Now let's take a look at attributetargets.

Attributetargets is a single-digit tag that defines the types and objects that a feature can apply.

[Flags]
Public Enum attributetargets {

Assembly = 1, // attributes can be applied to the Assembly.
Module = 2, // you can apply attributes to the module.
Class = 4, // you can apply attributes to a class.
Struct = 8, // you can apply properties to the structure, that is, the value type.
Enum = 16, // You can enumerate application attributes.
Constructor = 32, // you can apply attributes to the constructor.
Method = 64, // attributes can be applied to the method.
Property = 128, // you can apply an attribute to a property ).
Field = 256, // you can apply attributes to fields.
Event = 512, // attributes can be applied to the event.
Interface = 1024, // you can apply attributes to interfaces.
Parameter = 2048, // you can apply attributes to parameters.
Delegate = 4096, // you can delegate application attributes.
Returnvalue = 8192, // you can apply the attribute to the returned value.
Genericparameter = 16384, // you can apply attributes to generic parameters.
All = 32767, // you can apply attributes to any application element.
}

It is not difficult to understand why the above examples use:

[Attributeusage (attributetargets. Class, allowmutiple = true, inherited = false)]

The attributeusage loaded on the obsoleteattribute feature is as follows:

[Attributeusage (6140, inherited = false)]

Because attributeusage is a single-digit tag, it can be combined by bit or "|. So when we write this:

[Attributeusage (attributetargets. Class | attributetargets. Interface)

This means that features can be applied to both classes and interfaces.

Note: There are two special cases: observing the attributeusage definition above, it means that the feature can also be loaded to Assembly and module, and these two are our compilation results, this type does not exist in the program. How should we load it? You can use the syntax [Assembly: someattribute (parameter list)]. In addition, this statement must be prior to the start of a Program Statement.

2.4 inherited and allowmutiple attributes

The allowmutiple attribute is used to set whether the feature can be added to a type repeatedly (the default value is false), as shown in the following figure:

[Recordattribute ("Update", "Jimmy "," 2008-1-20 ")]
[Recordattri ("CREATE", "Zhang Ziyang "," 2008-1-15 ", Memo =" this class is for demonstration only ")]
Public class democlass {
// Classbody
}

Therefore, we must set allowmutiple to true.

Inherited is more complicated. If a class inherits from our democlass, when we add recordattriclass to democlass, The democlass subclass also obtains this feature. When a feature is applied to a method, if the method is overwritten by a subclass inherited from this class, then inherited is used to show whether the subclass method inherits this feature.

In our example, set inherited to false.

2.5 implement recordattribute

Now it is very easy to implement recordattribute. You do not need to make any changes to the class subject. We only need to make it inherit from the attribute base class, you can also mark it with the attributeusage feature (assuming we want to apply this feature to classes and methods ):

[Attributeusage (attributetargets. Class | attributetargets. method, allowmultiple = true, inherited = false)]
Public class recordattribute: attribute {
// Omitted
}

2.6 Use recordattribute

We have created our own custom features, and now it is time to use them.

[Record ("Update", "Matthew "," 2008-1-20 ", Memo =" modifying tostring () method ")]
[Record ("Update", "Jimmy "," ")]
[Record ("CREATE", "Zhang Ziyang "," 2008-1-15 ")]
Public class democlass {
Public override string tostring (){
Return "this is a demo class ";
}
}

Class program {
Static void Main (String [] ARGs ){
Democlass demo = new democlass ();
Console. writeline (Demo. tostring ());
}
}

This program simply outputs a "This is a demo class" on the screen ". Our properties also seem to have no impact on the program as if we used "//" for annotation. In fact, the data we added has been added to the Assembly as metadata. You can see through il dasm:

3. Use reflection to view custom features

Using Reflection to view custom feature information is similar to viewing other information. First, obtain a type object based on the Type (democlass in this example), and then call the getcustomattributes () method of the type object, obtain the features applied to this type. When the first attributetype parameter in getcustomattributes (type attributetype, bool inherit) is specified, only the features of the specified type are returned. Otherwise, all features are returned; the second parameter specifies whether to search for the member's inheritance chain to find these attributes.

Class program {
Static void Main (String [] ARGs ){
Type T = typeof (democlass );
Console. writeline ("the following lists the recordattrieline attributes applied to {0}:", t );

// Obtain all recordattributes features
Object [] records = T. getcustomattributes (typeof (recordattrites), false );

Foreach (recordattribute record in Records ){
Console. writeline ("{0}", record );
Console. writeline ("type: {0}", record. recordtype );
Console. writeline ("Author: {0}", record. Author );
Console. writeline ("Date: {0}", record. Date. tow.datestring ());
If (! String. isnullorempty (record. Memo )){
Console. writeline ("Remarks: {0}", record. Memo );
}
}
}
}

Output:

The recordattribute attributes applied to attributedemo. democlass are listed below:
Attributedemo. recordattribute
Type: Update
Author: Matthew
Date: 2008-1-20
Note: Modify tostring () method
Attributedemo. recordattribute
Type: Update
By Jimmy
Date:
Attributedemo. recordattribute
Type: Create
Author: Zhang Ziyang
Date: 2008-1-15

Now, in this step, it will no longer be a problem to input the data into the database, and our chapter on reflecting custom features will end here.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.