Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to define the C# feature

2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains "how to define the C# feature". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to define the C# feature.

I. what are the characteristics?

An Attribute is a declarative tag used to pass behavior information about various elements in a program, such as classes, methods, structures, enumerations, components, and so on, at run time. You can add declarative information to your program by using features. A declarative tag is described by square brackets ([]) placed in front of the element to which it applies.

Attribute is used to add metadata, such as compiler instructions and comments, descriptions, methods, classes, and other information. The .net framework provides two types of properties: predefined properties and custom properties.

The syntax for the feature is as follows:

[attribute (positional_parameters, name_parameter = value,...)] element

The name and value of the Attribute are specified in square brackets and are placed before the element to which it applies. Positional_parameters specifies the required information, and name_parameter specifies the optional information.

2. Predefined properties Obsolete characteristics

This predefined feature marks program entities that should not be used. It allows you to tell the compiler to discard a particular target element. For example, when a new method is used in a class, but you still want to keep the old method in the class, you can mark it as obsolete (outdated) by displaying a message that should use the new method instead of the old one.

The syntax is as follows:

[Obsolete (message)] [Obsolete (message, iserror)]

Where:

The parameter message, is a string that describes why the project is out of date and what the alternative uses.

Parameter iserror, which is a Boolean value. If the value is true, the compiler should treat the use of the project as an error. The default value is false (the compiler generates a warning).

Take a look at the following small example:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute {[Obsolete ("Please do not use this class, this class is out of date, please use what to replace")] public class Student {public int Id {get; set;} public string Name {get; set;} public string Accont {get; set;} public long QQ {get; set } public string Answer ([Custom] string name) {return $"This is {name}";}

In the above example, the Obsolete feature is used on the Student class to mark that the class is out of date. Compile the code result:

III. Custom characteristics

The .net framework allows you to create custom properties that store declarative information and can be retrieved at run time. This information can be related to any target element based on design standards and application needs.

Creating and using custom properties involves four steps:

Declare custom properties

Build custom features

Apply custom properties to target program elements

Access properties through reflection

1. Declare custom properties

In the above example, use F12 to view the definition of Obsolete:

As you can see from the screenshot above, the predefined features in the .NET Framework are inherited from the Attribute class, so to customize a feature, you only need the class to inherit from Attribute. The following defines a Custom custom feature:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute {/ Custom Custom attribute / public class CustomAttribute: Attribute {}}

Note: all features end with Attribute by default, but can be declared without ending with Attribute.

2. Build custom features

Each property must have at least one constructor. The required positional parameters should be passed through the constructor. The following code demonstrates the CustomAttribute class:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks Namespace MyAttribute {/ Custom Custom attribute / public class CustomAttribute: Attribute {/ No parameter constructor / public CustomAttribute () {} / parameter constructor / / public CustomAttribute (string description) {this.Description = description } / attribute / public string Description {get; set;} / Field / public string Remark = null; public void Show () {Console.WriteLine ("This Is CustomAttribute") 3. Apply custom properties to the target program element

Apply a property by placing it on its immediate target (class, method, property, field, etc.):

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute {[Obsolete ("Please do not use this class, this class is out of date")] [Custom ("this is a Custom custom feature")] public class Student {public int Id {get; set;} public string Name {get; set;} public string Accont {get; set;} public long QQ {get Set;} public string Answer ([Custom] string name) {return $"This is {name}";}

Note:

1. If you use the Attribute ending when declaring a custom feature, you can omit Attribute when applying the custom feature; if the declaration does not end with Attribute, you cannot omit Attribute when applying the custom feature.

2. By default, the same feature can only be applied once. If you want to apply the feature multiple times, you need to add the AttributeUsage feature to the feature. The CustomAttribute feature is modified as follows:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks Namespace MyAttribute {/ Custom Custom property / [AttributeUsage (AttributeTargets.All,AllowMultiple = true) Inherited = true)] public class CustomAttribute: Attribute {/ nonparametric constructor / public CustomAttribute () {} / public CustomAttribute (string description) {this.Description = description } / attribute / public string Description {get; set;} / Field / public string Remark = null; public void Show () {Console.WriteLine ("This Is CustomAttribute");}

Where AttributeTargets is the enumerated value, and F12 goes to the definition to view all the enumerated values of AttributeTargets:

The enumerated value of AttributeTargets indicates to which targets the Custom feature can be applied. For example, if the enumerated value of AttributeTargets is Class, it means that CustomAttribute can only be applied to classes. The enumerated value here is All, which means that this feature can be used on any type. By default, the enumeration value is All.

AllowMultiple indicates whether this feature can be used multiple times on a type:

Here the value of AllowMultiple is true, which means that this feature can be used multiple times on the type. If false, it means you can only use it once. False is the default.

Inherited indicates whether the feature can be inherited by a subclass:

By default, Inherited is true.

This is looking at the Student class:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute {[Obsolete ("Please do not use this class, this class is obsolete")] [Custom ("this is a Custom custom feature")] / / using parametric construction [Custom ()] / / using no-parameter construction public class Student {public int Id {get; set } / use the Custom attribute on the attribute / [Custom ("this is a Name attribute")] public string Name {get; set;} public string Accont {get; set;} public long QQ {get; set } / use the Custom attribute on methods and parameters / [Custom ("this is an Answer method")] public string Answer ([Custom ("this is a method parameter")] string name) {return $"This is {name}";}

Note: if the same feature is used multiple times on a type, the features can be written together, separated by commas, for example, the above definition has the same effect as the one below:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute {[Obsolete ("Please do not use this class, this class is out of date")] [Custom ("this is a Custom custom feature"), Custom,Custom (), Custom (Remark = "remarks")] public class Student {public int Id {get; set } / use the Custom attribute on the attribute / [Custom ("this is a Name attribute")] public string Name {get; set;} public string Accont {get; set;} public long QQ {get; set } / in methods, method parameters, The return value of the method uses the Custom property / [Custom ("this is the Answer method") / / the method applies the property [return:Custom ()] / / the return value of the method applies the property public string Answer ([Custom ("this is a method parameter")] string name) {return $"This is {name}" }}}

Note: in Web API, FromBaby and FromUri apply properties to the parameters of the method.

4. Access features through reflection

Define a Manager class to manage features:

Using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks;namespace MyAttribute {/ Management feature / public class Manager {public static void Show (Student student) {/ / get type Type type = typeof (Student); / / or use student.GetType () / / find the property above the type type.IsDefined means to find the property above the type if (type.IsDefined (typeof (CustomAttribute), true)) / / check whether there is a high performance {/ / GetCustomAttribute to obtain the property type.GetCustomAttribute means to find the property defined above the type Means to call the constructor to create an object of type CustomAttribute CustomAttribute attribute = (CustomAttribute) type.GetCustomAttribute (typeof (CustomAttribute), true) / / attribute.Description indicates that the attribute attribute.Remark in the property class represents the field Console.WriteLine ($"{attribute.Description} _ {attribute.Remark}") in the property class; attribute.Show () } # region get the property defined above the ID attribute / / get the Id attribute PropertyInfo property = type.GetProperty ("Id") / / check whether the CustomAttribute attribute if (property.IsDefined (typeof (CustomAttribute), true)) {CustomAttribute attribute = (CustomAttribute) property.GetCustomAttribute (typeof (CustomAttribute), true) is defined above the Id attribute; Console.WriteLine ($"{attribute.Description} _ {attribute.Remark}"); attribute.Show () } # endregion # region get the properties defined above in the Answer () method / / get the Answer method MethodInfo method = type.GetMethod ("Answer"); if (method.IsDefined (typeof (CustomAttribute), true)) {CustomAttribute attribute = (CustomAttribute) method.GetCustomAttribute (typeof (CustomAttribute), true) Console.WriteLine ($"{attribute.Description} _ {attribute.Remark}"); attribute.Show ();} # endregion # region get the property defined by the parameter ParameterInfo parameter = method.GetParameters () [0] If (parameter.IsDefined (typeof (CustomAttribute), true) {CustomAttribute attribute = (CustomAttribute) parameter.GetCustomAttribute (typeof (CustomAttribute), true); Console.WriteLine ($"{attribute.Description} _ {attribute.Remark}"); attribute.Show () } # endregion # region get the property defined by the return value ParameterInfo returnParameter = method.ReturnParameter; if (returnParameter.IsDefined (typeof (CustomAttribute), true)) {CustomAttribute attribute = (CustomAttribute) returnParameter.GetCustomAttribute (typeof (CustomAttribute), true); Console.WriteLine ($"{attribute.Description} _ {attribute.Remark}") Attribute.Show ();} # endregion string result = student.Answer ("Tom"); Console.WriteLine (result);}

Called in the Main () method:

Using MyAttribute.Extension;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute {class Program {static void Main (string [] args) {Student student = new Student (); student.Id = 123; student.Name = "time"; / / use Manager class to manage Student Manager.Show (student) Console.ReadKey ();}

Results:

4. Application feature scenario 1: the enumerated values of user status are defined in English, and the meaning in Chinese needs to be output. The enumeration is defined as follows: using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks Namespace MyAttribute.Extension {/ enumerated type user status / public enum UserState {/ normal / Normal = 0, / freeze / Frozen = 1 / delete / Deleted = 2}}

Common practice: judge according to the enumerated value, and then output the Chinese meaning:

UserState userState = UserState.Normal;switch (userState) {case UserState.Normal: Console.WriteLine ("normal"); break; case UserState.Frozen: Console.WriteLine ("frozen"); break; case UserState.Deleted: Console.WriteLine ("delete"); break;}

This way of writing violates the open principle and is not conducive to future expansion, which is implemented using features below.

Define Remark properties first:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Reflection;namespace MyAttribute.Extension {/ RemarkAttribute feature / public class RemarkAttribute: Attribute {private string _ Remark = null / public RemarkAttribute (string remark) {this._Remark = remark;} public string GetRemark () {return _ Remark;}

The UserState enumeration is modified as follows:

Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks Namespace MyAttribute.Extension {/ enumerated type user status / public enum UserState {/ normal / / [Remark (normal)] Normal = 0 / freeze / / [Remark ("freeze")] Frozen = 1, / delete / [Remark ("delete")] Deleted = 2}}

Extend the Enum type:

Using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks Namespace MyAttribute.Extension {extension method of public static class EnumExtension {/ Enum. Add the this keyword / public static string GetRemark (this Enum value) {/ / get type Type type = value.GetType () before the first parameter of static class and static method. / / get the field FieldInfo field = type.GetField (value.ToString ()); / / determine whether the RemarkAttribute feature if (field.IsDefined (typeof (RemarkAttribute) {/ / create an instance RemarkAttribute attribute = (RemarkAttribute) field.GetCustomAttribute (typeof (RemarkAttribute)) is defined above the field / / return the GetRemark () method return attribute.GetRemark () in the RemarkAttribute feature;} else {return value.ToString ();}

Called in the Main () method:

Using MyAttribute.Extension;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute {class Program {static void Main (string [] args) {Student student = new Student (); student.Id = 123; student.Name = "time"; / / use Manager class to manage Student / / Manager.Show (student) UserState userState = UserState.Normal; / / switch (userState) / / {/ / case UserState.Normal: / / Console.WriteLine ("normal"); / / break; / / case UserState.Frozen: / / Console.WriteLine ("freeze") / / break; / / case UserState.Deleted: / / Console.WriteLine ("delete"); / / break; / /} Console.WriteLine (userState.GetRemark ()); Console.ReadKey ();}

Results:

Scenario 2. Do data verification

Student has the attribute QQ, which ranges from 10000 to 9999999999, and verifies that the value of the QQ attribute is in this range.

1. Define a RangeAttribute feature to validate the attribute range using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks Namespace MyAttribute.Extension {/ defines LongAttribute attributes, and attributes can only be applied to fields and attributes / [AttributeUsage (AttributeTargets.Field | AttributeTargets.Property)] public class RangeAttribute: Attribute {/ minimum range / private long _ MinRange = 0 / maximum range / private long _ MaxRange = 0; public RangeAttribute (long min,long max) {this._MinRange = min; this._MaxRange = max } / check the property range / public bool Check (object value) {if (valueworthy null & &! string.IsNullOrWhiteSpace (value.ToString () {if (long.TryParse (value.ToString () Out long IResult) {if (IResult > this._MinRange & & IResult this._MinLength & & IResult

< this._MaxLength) { return true; } } } return false; } }} 在Student类的Name属性上面应用LengthAttribute特性: [Length(5,10)]public string Name { get; set; } 在ObjectExtension里面增加长度的验证: using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks;namespace MyAttribute.Extension{ /// /// object类型的验证扩展 /// public static class ObjectExtension { /// /// 对object类型扩展一个Validate的方法 /// /// /// 输出参数,输出验证信息。如果验证通过,输出空字符串;如果验证不通过,输出具体信息 /// public static bool Validate(this object obj,out string msg) { // 获取类型 Type type = obj.GetType(); // 获取属性 PropertyInfo[] propertyInfos= type.GetProperties(); foreach(PropertyInfo prop in propertyInfos) { // 检查属性上面是否定义了RangeAttribute特性 if (prop.IsDefined(typeof(RangeAttribute))) { RangeAttribute attribute = (RangeAttribute)prop.GetCustomAttribute(typeof(RangeAttribute)); if(!attribute.Check(prop.GetValue(obj))) { msg = string.Format($"属性{ prop.Name}范围检查失败"); return false; } } // 检查属性上面是否定义了LengthAttribute特性 if (prop.IsDefined(typeof(LengthAttribute))) { LengthAttribute attribute = (LengthAttribute)prop.GetCustomAttribute(typeof(LengthAttribute)); if (!attribute.Check(prop.GetValue(obj))) { msg = string.Format($"属性{ prop.Name}长度检查失败"); return false; } } } msg = ""; return true; } }} 最后在Main()方法里面调用: Student student = new Student();student.Id = 123;student.Name = "time";// 使用Manager类管理StudentManager.Show(student); 结果: 仔细查看ObjectExtension扩展类:每增加一个特性,扩展方法里面就要增加一段相同的代码(只是特性的类型不同),那么能不能做到增加特性,而这里不需要修改呢?请看下面的修改: 1、定义一个抽象类继承自Attribute,里面有一个抽象的Check()方法,定义如下:using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute.Extension{ /// /// 抽象基类,继承自Attribute /// public abstract class AbstractValidateAttribute:Attribute { public abstract bool Check(object value); }}2、修改RangeAttribute和LengthAttribute两个特性类,都继承自AbstractValidateAttribute基类 RangeAttribute类: using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace MyAttribute.Extension{ /// /// 定义LongAttribute特性,并且特性只能应用在字段和属性上面 /// [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)] public class RangeAttribute : AbstractValidateAttribute { /// /// 最小范围 /// private long _MinRange = 0; /// /// 最大范围 /// private long _MaxRange = 0; public RangeAttribute(long min,long max) { this._MinRange = min; this._MaxRange = max; } /// /// 重写基类方法 检查属性范围 /// /// /// public override bool Check(object value) { if(value!=null && !string.IsNullOrWhiteSpace(value.ToString())) { if(long.TryParse(value.ToString(),out long IResult)) { if(IResult>

This._MinRange & & IResult this._MinLength & & IResult < this._MaxLength) {return true;} return false;}} 3, modify the ObjectExtension extension class using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks Validation extension of namespace MyAttribute.Extension {/ object type / public static class ObjectExtension {/ A pair of object types extends the method / parameter of a Validate, and outputs verification information. If the verification passes, the empty string is output If the verification fails, output specific information / / public static bool Validate (this object obj,out string msg) {/ / get type Type type = obj.GetType (); / / get attribute PropertyInfo [] propertyInfos= type.GetProperties () Foreach (PropertyInfo prop in propertyInfos) {/ / determine whether the AbstractValidateAttribute attribute is defined on the attribute if (prop.IsDefined (typeof (AbstractValidateAttribute), true)) {/ / multiple attributes may be defined on the attribute So here use the array object [] attributeArray = prop.GetCustomAttributes (typeof (AbstractValidateAttribute), true) Foreach (AbstractValidateAttribute attribute in attributeArray) {if (! attribute.Check (prop.GetValue (obj) {msg = string.Format ($"property {prop.Name} check failed"); return false } / check whether the RangeAttribute attribute / / if (prop.IsDefined (typeof (RangeAttribute) / {/ / RangeAttribute attribute = (RangeAttribute) prop.GetCustomAttribute (typeof (RangeAttribute)) is defined on the attribute / / if (! attribute.Check (prop.GetValue (obj) / / {/ / msg = string.Format ($"property {prop.Name} range check failed"); / / return false / /} / /} / check whether the LengthAttribute attribute / / if (prop.IsDefined (typeof (LengthAttribute) / {/ / LengthAttribute attribute = (LengthAttribute) prop.GetCustomAttribute (typeof (LengthAttribute)) is defined on the attribute / / if (! attribute.Check (prop.GetValue (obj) / / {/ / msg = string.Format ($"property {prop.Name} length check failed"); / / return false / /} / /}} msg = ""; return true;}} 4. Run result:

After the above modification, if you want to add a feature later, you only need to override the Check () method of the base class in this class, and you don't need to modify the ObjectExtension extension class.

At this point, I believe you have a deeper understanding of "how to define C# features". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report