Reflection characteristics (Attribute)
Many people may not yet understand the features, so let's look at what is a feature first. Think about it. If there is a message system, it has a way to send a short message to someone:
Title: Author: Author; content: Contents; Receiverid: Recipient ID
public bool Sendmsg (string title, string author, string content, int receiverid) {
Do Send Action
}
We soon found out that it is very bad to have the parameters listed in the parameter list of the method, we'd better define a message class to encapsulate the short message, and then pass a message object to the method:
public class message{
private string title;
private string author;
private string content;
private int Receiverid;
Slightly
}
public bool Sendmsg (Messag msg) {
Do some Action
}
At this point, we might want to remove the old method and replace it with this more extensible sendmsg method. Unfortunately we often do not, because this group of programs may be published as a set of APIs, in many client programs already using the old version of the Sendmsg () method, if we update the program simply remove the old sendmsg () method, then will be caused by using the old version sendmsg () The client program for the method does not work.
At this time, what should we do? We can certainly do this through the method overloads, so we don't have to delete the old Sendmsg () method. But if the new sendmsg () not only optimizes the transfer of parameters, but also optimizes the algorithm and efficiency, then we would be eager to inform the client that there is now a new high-performance sendmsg () method to use, But at this point the client program does not know that there is already a new sendmsg method, what should we do? We can call the programmer who maintains the client program, or e-mail it to him, but this is obviously not convenient, and there is a way to get him to compile the project, as long as there is a call to the old version of the Sendmsg () method, it will be told by the compiler.
1..Net built-in features introduction
You can use attributes to do this in. Net. an attribute is an object that can be loaded into an assembly and an Assembly object, which includes the assembly itself, modules, classes, interfaces, structures, constructors, methods, method parameters, and so on, and the object that loads the attribute is called the target of the attribute. An attribute is a mechanism for adding metadata (data that describes data) to a program that can provide instructions to the compiler or provide a description of the data.
Note: The English name of the feature is called attribute, and in some books it is translated as "attributes"; in other books, it is translated as "attributes"; because we typically refer to class members that contain get and/or set accessors as "Properties", So I'm going to use the term "attribute" in this article to differentiate the property.
The Chinese version of VS2005 uses "properties".
1.1 System.ObsoleteAttribute Characteristics
Let's look at how the feature solves the problem in this example: we can add the obsolete feature to the old Sendmsg () method to tell the compiler that this method is obsolete, and then when the compiler finds that there are places in the program that use this obsolete-tagged method, A warning message will be given.
Namespace Attribute {
public class Message {}
public class TestClass {
Add Obsolete attribute
[Obsolete ("Use the new Sendmsg (Message msg) overloaded 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 run this code, we will find a warning: warning CS0618: "ATTRIBUTE.TESTCLASS.SHOWMSG ()" is obsolete: "Please use the new sendmsg (Message msg) overloaded method." by using attributes, we can see that the compiler gives the warning message and tells the client that there is a new way to use it, so that the programmer will consider using the new Sendmsg () method after seeing the warning message.
Note: For simplicity, the TestClass class and program are in the same assembly, and in fact they can be far away.
1.2 How to use features
From the above example, we have seen the use of features in general: First, there is a square bracket "[]", the left Parenthesis "[" followed by the name of the attribute, such as obsolete, followed by a parenthesis "()". Unlike normal classes, this parenthesis can be used not only to write arguments to constructors, but also to assign values to the properties of a class, in the case of obsolete, only the constructor arguments are passed.
Note: In fact, when you use the mouse box to select Obsolete, and then press F12 to go to the definition, you will find that its full name is ObsoleteAttribute, inherited from the attribute class. But here it is only using obsolete to mark the method, which is. NET, all attributes should end in attribute, and if you do not add attribute when labeling an object, the compiler will automatically look for a version with attribute.
Note: With constructor arguments, the order of the arguments must be the same as the order in which the constructor is declared, all of which are also called positional parameters (positional Parameters) in the attribute, and, accordingly, the attribute arguments are called named parameters (Named Parameters). This is explained in more detail below.
2. Custom Attributes 2.1 Example Introduction
If you can't define a feature yourself and use it, I don't think you can understand the features well, so let's build a feature on our own. 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, and in the future update we will explain when who updated it, can record or not record the updated content, what would you do in the past? Is it like this? Add a comment to the class above the class:
Updated: Matthew, 2008-2-10, modify the ToString () method
Updated: Jimmy, 2008-1-18
Created: Zhang Ziyang, 2008-1-15
public class democlass{
Class Body
}
This can be recorded, but what if one day we want to save these records in a database for backup? Are you going to go through the source files one by one, find these comments, and insert them into the database?
With the definition of the above attribute, we know that attributes can be used to add metadata to a type that can be used to describe the type. So here, the features should come in handy. So in this case, the metadata should be: Comment Type ("Update" or "create"), modify person, date, note information (optional). The target type of the attribute is the Democlass class.
By understanding the metadata attached 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; Note
constructor, the parameters of the constructor are also called positional parameters in the attribute.
Public Recordattribute (String recordtype, string author, string date) {
This.recordtype = RecordType;
This.author = author;
This.date = convert.todatetime (date);
}
For positional parameters, typically only get accessors are provided
public string RecordType {get {return recordtype;} }
public string Author {get {return Author;}}
Public DateTime Date {get {return Date;}}
Build an attribute, also called a named parameter in the attribute
public string Memo {
get {return memo;}
set {memo = value;}
}
}
Note: The parameter date of the constructor must be a constant, type, or constant array, so the DateTime type cannot be passed directly.
This class does not only look, but actually does not have any difference from the ordinary class, obviously it can not be because the name followed by a attribute to become a feature. So how do you make it known as an attribute and apply it to a class? Let's take a look before proceeding to the next step. NET built-in feature obsolete is how to define:
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 Adding the format of an attribute (positional and named 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 find that in the definition of this feature, three features are used to describe it. These three properties are: Serializable, AttributeUsage and ComVisible. Serializable features as we've already covered, comvisible is simply "the control program centralizes individual managed types, members, or all types of COM accessibility" (defined by Microsoft). Here we should note that the attribute itself is the metadata used to describe the data, and these three attributes are used to describe the attributes, so they can be considered "metadata metadata" (Meta data: meta-metadata).
Because we need to use "meta data" to describe our defined feature recordattribute, now we need to look at "meta data" first. Here should remember "meta-data" is also a feature, in most cases, we only need to master AttributeUsage on it, so now look at it. Let's start by looking at how the above AttributeUsage is loaded onto the ObsoleteAttribute feature.
[AttributeUsage (6140, inherited = False)]
Then let's 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 that contains a positional parameter of type AttributeTargets (positional Parameter) and two named parameters (Named Parameter). Note the Validon property is not a named parameter because it does not contain a set accessor.
Here we must wonder why such partitioning of parameters, which is related to the use of features. If AttributeUsageAttribute is an ordinary class, we must use this:
Instantiate a class of AttributeUsageAttribute
AttributeUsageAttribute usage=new AttributeUsageAttribute (attributetargets.class)
;
Usage. AllowMultiple = true; Setting the Allowmutiple Property
Usage. inherited = false;//Setting inherited property
However, the attribute is only written in one line of code, and then close to the type it is applied to (the target type). Microsoft's software engineers have come up with the idea that, regardless of the constructor's arguments or attributes, all of them are written into the parentheses of the constructor, and for the parameters of the constructor, they must be in the order and type of the constructor arguments, and in the case of attributes, they are separated by commas, in the form of property = value. So the code above is reduced to this:
[AttributeUsage (AttributeTargets.Class, Allowmutiple=true, Inherited=false)]
As you can see, AttributeTargets.Class is a constructor parameter (positional parameter), whereas Allowmutiple and inherited are actually attributes (named arguments). Named parameters are optional. Our recordattribute will be used in the same way in the future. (Why call them arguments, I guess because they are used in a way that looks more like the parameters of a method.) )
Assuming that our recordattribute is ok now, it should be used like this:
[Recordattribute ("Create", "Zhang Ziyang", "2008-1-15", memo= "This class is for demonstration only")]
public class democlass{
Classbody
}
where RecordType, author and date are positional parameters, Memo is a named parameter.
2.3 AttributeTargets bit Mark
You can see from the name of the AttributeUsage attribute that it is used to describe how the attribute is used. Specifically, the first should be what types or objects the attributes it marks can be applied to. From the code above, we see that the constructor of the AttributeUsage attribute accepts a parameter of type AttributeTargets, so let's look at AttributeTargets now.
AttributeTargets is a bit tag that defines the types and objects that an attribute can apply to.
[Flags]
public enum AttributeTargets {
Assembly = 1,//You can apply properties to an assembly.
module = 2,//You can apply properties to the module.
class = 4,//You can apply properties to the class.
struct = 8,//You can apply a property to the structure, that is, the value type.
enum = 16,//You can apply a property to an enumeration.
Constructor = 32,//The property can be applied to the constructor.
METHOD = 64,//The property can be applied to the methods.
property = 128,//attribute (Attribute) can be applied to the property.
field = 256,//You can apply a property to a field.
event = 512,//The attribute can be applied to events.
Interface = 1024,//properties can be applied to the interface.
Parameter = 2048,//The attribute can be applied to the parameter.
Delegate = 4096,//The attribute can be applied to the delegate.
returnvalue = 8192,//The property can be applied to the return value.
Genericparameter = 16384,//You can apply properties to generic parameters.
all = 32767,//You can apply attributes to any application element.
}
It should not be difficult to understand why I used the example above:
[AttributeUsage (AttributeTargets.Class, Allowmutiple=true, Inherited=false)]
The AttributeUsage loaded on the ObsoleteAttribute feature is this:
[AttributeUsage (6140, inherited = False)]
Because AttributeUsage is a bit marker, you can use either a bitwise OR a ' | ' To be combined. So, when we write this:
[AttributeUsage (attributetargets.class| Attributetargets.interface)
means that you can apply an attribute to a class or to an interface.
Note: There are two exceptions: observe the definition of the above AttributeUsage, stating that the attributes can also be loaded onto the assembly assembly and module modules, and these two are our compilation results, and there is no such type in the program. How do we load it? You can use this syntax: [assembly:someattribute (parameter list)], and this statement must precede the beginning of the program statement.
2.4 Inherited and Allowmutiple properties
The Allowmutiple property is used to set whether the attribute can be repeatedly added to a type (false by default), as if:
[Recordattribute ("Update", "Jimmy", "2008-1-20")]
[Recordattribute ("Create", "Zhang Ziyang", "2008-1-15", memo= "This class is for demonstration only")]
public class democlass{
Classbody
}
So, we have to display the Allowmutiple set to True.
Inherited is more complicated, and if a class inherits from our Democlass, then when we add Recordattribute to Democlass, the subclass of Democlass gets that attribute as well. When an attribute is applied to a method, if the subclass inheriting from the class overrides the method, then inherited is used to indicate whether the subclass method inherits this attribute.
In our example, set inherited to False.
2.5 Implementation Recordattribute
It should be very easy to implement Recordattribute now, for the body of the class does not need to make any modifications, we just need to let it inherit from the attribute base class, and use the AttributeUsage attribute to mark it as well ( Suppose we want to apply this attribute to classes and methods):
[AttributeUsage (attributetargets.class| AttributeTargets.Method, Allowmultiple=true, Inherited=false)]
public class Recordattribute:attribute {
Slightly
}
2.6 Using Recordattribute
Now that we've created our own custom features, it's time to use it.
[Record ("Update", "Matthew", "2008-1-20", Memo = "Modify ToString () method")]
[Record ("Update", "Jimmy", "2008-1-18")]
[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 use "//" to annotate the program without any effect, in fact, the data we added has been added as metadata to the assembly. You can see through IL dasm:
3. Viewing custom attributes using reflection
Using reflection to view custom attribute information is similar to looking at other information, first getting a type object based on the type (in this case, Democlass), and then invoking the GetCustomAttributes () method of the type object to get the attributes applied to that type. When the first parameter in the specified GetCustomAttributes (type attributetype, bool inherit) is AttributeType, only the attributes of the specified type are returned, otherwise all attributes are returned The second parameter specifies whether to search for the member's inheritance chain to find these properties.
Class Program {
static void Main (string[] args) {
Type t = typeof (DemoClass);
Console.WriteLine ("The Recordattribute attribute applied to {0} is listed below:", t);
Get all the recordattributes features
object[] Records = T.getcustomattributes (typeof (Recordattribute), false);
foreach (Recordattribute record in records) {
Console.WriteLine ("{0}", record);
Console.WriteLine ("Type: {0}", record.) RecordType);
Console.WriteLine ("{0}", record. Author);
Console.WriteLine ("Date: {0}", record.) Date.toshortdatestring ());
if (! String.IsNullOrEmpty (record. Memo)) {
Console.WriteLine ("Note: {0}", record.) Memo);
}
}
}
}
The output is:
The Recordattribute properties applied to Attributedemo.democlass are listed below:
Attributedemo.recordattribute
Type: Update
Matthew
Date: 2008-1-20
Remarks: Modify the ToString () method
Attributedemo.recordattribute
Type: Update
Jimmy
Date: 2008-1-18
Attributedemo.recordattribute
Type: Create
Zhang Ziyang
Date: 2008-1-15
Well, at this point, I think it's no longer a problem to put this data into a database, and that's where our chapters on reflective custom features go.
Reflection (reflection characteristics) in. Net-Part.3