C # attributes of series articles,
Attribute, allowing the source code to call methods with simplified syntax. CLR supports two types of attributes: No parameter attribute and no parameter attribute (Indexer ).
1.1 No parameter attribute features
Some improper use of fields will damage the object state, so all fields are generally set to private. To allow users or types to obtain or set status information, you must provide methods (accessors) that encapsulate field access ).
public class Employee{ private string name; public string GetName(){return name;} public string SetName(string value){name = value;}}
The Data encapsulation above has to implement additional methods. Type users must call methods and cannot directly reference field names. Therefore, CLR provides a mechanism called attribute.
public class Employee{ private string name; public string Name
{ get{return name;} set{name=value;} }}
Each attribute has a name and a type (the type cannot be void ). Properties cannot be reloaded.
C # The Compiler generates the following code when obtaining or setting attributes. The get _ and set _ prefixes are automatically appended before the attribute names.
public class Employe{ private string name; public string get_Name() { return n_Name; } pubic void set_Name() { n_Name=value; }}
For each attribute defined in the source code, the compiler generates an attribute definition item in the metadata of the hosted assembly, including some flags and attribute types. The get and set accessors are also referenced. These jobs establish a connection between the abstract concept of attributes and Its accessors.
1.2 automatic attribute implementation
If you create an attribute to encapsulate only one supported field, C # provides a concise syntax called automatic attribute. Public string Name {get; set;} C # automatically declares a private field internally.
Advantage: Any code that accesses this attribute actually calls the get and set methods. If you decide to implement the get and set methods by yourself in the future, you do not need to re-compile any code that accesses the attribute. However, if you declare Name as a field and want to change it to an attribute later, all the code accessing the field must be re-compiled to access the attribute method.
Disadvantage: the name of the supported fields of AIP is determined by the compiler. The name may be changed every time a recompilation is performed. Therefore, if any type contains an AIP, the instance type cannot be deserialized. The runtime serialization engine permanently stores the field names in the serialized stream. Do not use the AIP function for any type that you want to serialize or deserialize. In addition, when using AIP, you cannot add breakpoints. You can manually implement the settings to facilitate debugging. The use of the AIP attribute must be readable and writable. What is the purpose of reading a value only for a writing segment? There must be a default value for read-only. Therefore, AIP acts on the entire attribute and cannot explicitly implement an accessor method, but automatically implement another method.
1.3 notes for using attributes:
- If you define an attribute, it is best to provide it with get and set accessors at the same time.
- Attribute methods may throw an exception; field access will never
- The attribute cannot be passed to the method as an out or ref parameter; the field can
- The attribute method may take a long time to execute and may require additional memory.
- The attribute only simplifies the syntax and does not improve the Code performance. It is best to honestly implement the GetXXX and SetXXX methods.
1.4 object and set Initiator
C # supports a special object initialization syntax: Employee e = new Employee () {Name = "abc", Age = 45 }. This statement constructs an object, calls its non-argument constructor, and sets the public Name attribute to "abc", which is equivalent to e. name = "abc"; e. age = 45; the two methods generate the same IL code. At the same time, C # allows the combination of multiple functions, such
Employee e = new Employee () {Name = "abc", Age = 45}. ToString (). ToUpper ();
If the attribute type implements the IEnumerable or IEnumerable <T> interface, the attribute is considered as a set, and the initialization of the set is an addition operation. As follows:
Public class ClassRoom {private List <string> students = new List <string> (); public List <string> Students {get {return students ;}// initialization, actually, the Add method of the set is called to Add data to the set ClassRoom classRoom = new ClassRoom {Students = {"sd", "sdf", "fgd "};}
}
// Initialize the dictionary type
Var table = new Dictionary <string, int >{{ "abc", 1 },{ "def", 2 }}
1.5 anonymous type
The anonymous type function can automatically declare an unchangeable type of tuples. The type of a set of properties. Var o1 = new {Name = "abc", Year = 1990}
The compiler will deduce the type of each expression, create a private field of the inference type, create a public read-only attribute for each field, and create a constructor to accept all expressions, in this example, private fields are initialized using the evaluate result of the expression passed to them. It also overwrites the Equals, GetHashCode, and ToString methods of the Object to generate code for all these methods.
If multiple anonymous types are defined in the source code, and these types have the same structure (each attribute has the same type and name, and the specified order of these attributes is the same ), then it creates only one anonymous type definition and multiple instances of this type.
Generally, the anonymous type is often used in combination with LINQ. The method prototype cannot accept anonymous type parameters because it does not know what type it is, nor can it return a reference to the anonymous type. To transmit tuples, you can use the System. Tuple type.
string myDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);var query = from pathname in Directory.GetFiles(myDocuments) let LastWriteTime = File.GetLastWriteTime(pathname) where LastWriteTime>(DateTime.Now - TimeSpan.FromDays(7)) orderby LastWriteTime select new {Path = pathname,LastWriteTime};
1.6 parameter attributes
C # Use the array-style syntax to expose the property of the parameter (Indexer). You can reload the indexer as a [] operator by C # developers. For example, define a class Student
Public class Student {public string this [int n] {get {return Name;} set {Name = n> 0? "Greater than 0": "less than 0" ;}} private string Name ;}
When Student stu = new Student (); stu [4] = "NNN"; is executed, the set method is executed, and the Name is set to greater than 0; when stu [4] is executed, the output is greater than 0.
1.7 performance of calling the attribute accessors Method
For simple get and set accessors, the JIT compiler will inline the code (compile the code of the method, that is, the accessors method, directly into the method that calls it ), to avoid the overhead of calling during runtime, the cost is that the compiled method becomes larger. Note: JIT does not inline attribute methods when debugging code, because this will be difficult to debug, the release version will use inline, and the performance will be faster.
1.8Since attributes are essentially methods, C # And CLR support generic methods, but C # does not allow attributes to introduce their own generic type parameters, the primary cause attribute should have been used to indicate that a certain object feature can be queried or set. Once a generic type parameter is introduced, it means that the query/setting behavior may be changed, but the attribute should not be side-by-side with the behavior. methods rather than attributes should be defined to expose the behavior of objects, whether they are generic or not.