0


C# 特性(Attribute)超详细教程

文章目录

0.前篇

学习本文前建议先阅读我的关于反射的博文:
https://editor.csdn.net/md/?articleId=139095147

1.特性概念

特性是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。

2.特性的声明和使用

2.1 特性定义语法

特性在声明时以

Attribute

结尾,在使用时可省去Attribute

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

参数说明:

  • positional_parameters: 表示特性必须具备的信息。
  • name_paramete:表示特性可选的信息。
  • element: 在这里表示特性目标。

代码示例:
特性声明:

publicclassTestAttribute:Attribute{publicint Parm {get;set;}privateint id;privatestring name;publicTestAttribute(){}publicTestAttribute(int id,string name){this.id = id;this.name = name;}}

特性使用:

[Test]// 使用无参构造函数publicclassTestClass1{}[Test(Parm =123)]// 使用无参构造函数 + 指定参数publicclassTestClass2{}[Test(1,"test")]// 使用有参构造函数publicclassTestClass3{}

2.2 特性目标

特性目标指的是应用特性的实体。例如,特性目标可以是类、特定方法或整个程序集。一般情况,特性应用于紧跟在它后面的元素。不过,C# 特性支持显示标识,例如可以显示标识为将特性应用于方法,或者是应用于其参数或返回值。

显示标识特性目标的语法如下:

[target : attribute-list]
  • target:表示指定的特性目标值。
  • attribute-list:表示要应用的特性列表。

下表展示常用的 target 值:
目标值适用对象assembly整个程序集module当前程序集模块field类或结构中的字段event事件method方法或 get 和 set 属性访问器param方法参数或 set 属性访问器参数propertyProperty(属性)return方法、属性索引器或 get 属性访问器的返回值type结构、类、接口、枚举或委托
代码示例:

// 默认: 应用于方法[Test]intMethod1(){return0;}// 显示指定应用于方法[method:Test]intMethod2(){return0;}// 应用于参数intMethod3([Test]string contract){return0;}// 应用于返回值[return:Test]intMethod4(){return0;}

3.预定义特性

3.1 AttributeUsage

特性 AttributeUsage 描述了如何使用一个自定义特性类。注意,使用特性修饰的类 AttributeUsage 必须是 System.Attribute 的直接或间接派生类,否则将发生编译时错误。

AttributeUsage 特性的语法如下:

[AttributeUsage(validon, AllowMultiple = allowmultiple, Inherited = inherited)]
  • validon: 表示可被应用的特性目标值。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
  • AllowMultiple: 可选,allowmultiple 选项为其提供一个布尔值。表示特性是否能被重复放置多次
  • Inherited:可选,inherited 选项为其提供一个布尔值。表示 能否被派生类所继承。

示例代码:

[AttributeUsage(AttributeTargets.Class, AllowMultiple =false, Inherited =false)]publicclassExampleAttribute:Attribute{publicExampleAttribute(string name){}}

3.2 Conditional

特性 Conditional 是有条件的意思。使用特性修饰的方法也就是条件方法,条件方法的执行依赖于指定的预处理标识符。预处理标识符影响着方法调用的条件编译,这种影响取决于指定的值。例如事先用预处理器指令定义了一个 Test 字符,当条件方法指定的值也为 Test 时, 则该方法会被执行。

语法:

[Conditional(conditionalSymbol)]
  • 参数 conditionalSymbol 表示指定的预处理标识符。
#define TestusingSystem;publicclassExample{[Conditional("Test")]staticvoidMethod1(){
        Console.WriteLine("Method1");}staticvoidMethod2(){
        Console.WriteLine("Method2");}staticvoidMain(){Method1();Method2();}}

输出:

Method1
Method2

注释掉 #define Test 输出

Method2

3.3 其它预定义特性

特性说明

[Obsolete]

标记已过时的代码,使得在使用过时成员时发出警告或错误信息。

[Serializable]

用于标记类,表示该类可以序列化,即可以在网络上传输或者在文件中存储。

[DllImport]

用于指示要在程序中调用非托管代码(通常是 DLL)的方法。

[Conditional]

与预处理指令 ‘#if’ 和 ‘#endif’ 结合使用,根据定义的条件编译代码。

[AttributeUsage]

用于指定自定义特性的使用方式,如允许的目标类型和是否允许多次应用等。

[Conditional]

根据条件编译代码,类似于预处理指令,但是使用 Attribute。

[DefaultValue]

为属性或字段设置默认值。

[Description]

为属性或者事件提供一个描述,通常在设计时使用。

4.MyAttributeHelper(特性使用帮助类)

usingSystem.Reflection;namespaceMing.Utils{publicstaticclassMyAttributeHelper{/// <summary>/// 获取该类型下所有的带Attribute的方法/// </summary>/// <typeparam name="T">特性类型</typeparam>/// <param name="type"></param>/// <returns></returns>publicstaticList<MethodInfo>GetAllMethods<T>(Type type)whereT:class,new(){var res =newList<MethodInfo>();
            res = type.GetMethods().Where(t => t.GetCustomAttributes(typeof(T),false).Any()).ToList();return res;}/// <summary>/// 获取该类型下所有的带Attribute的属性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>publicstaticList<PropertyInfo>GetAllPropertys<T>(Type type)whereT:class,new(){var res =newList<PropertyInfo>();
            res = type.GetProperties().Where(t => t.GetCustomAttributes(typeof(T),false).Any()).ToList();return res;}/// <summary>/// 获取程序集所有带 T 特性的类class/// </summary>/// <typeparam name="T">特性类型</typeparam>/// <returns>程序集下所有带 T 特性的类class</returns>publicstaticList<Type>GetAllTypes<T>()whereT:Attribute{var res =newList<Type>();//Assembly存放所有的程序集
            res = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetCustomAttributes(typeof(T),false).Any())//我们找到所有程序集中带有T特性的Type类型.ToList();return res;}/// <summary>/// 获取类上的特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>publicstaticTGetAttribute<T>(Type type)whereT:Attribute,new(){var res =newT();
            res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取方法上的特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>publicstaticTGetAttribute<T>(MethodInfo type)whereT:Attribute,new(){var res =newT();
            res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取属性上的特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>publicstaticTGetAttribute<T>(PropertyInfo type)whereT:Attribute,new(){var res =newT();
            res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 返回带有Attribute的类型元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <returns></returns>publicstaticList<(Type type, Att att)>GetAll_TypeAndAtt<Att>()whereAtt:Attribute,new(){var res =newList<(Type type, Att att)>();var typeLists =GetAllTypes<Att>();foreach(var item in typeLists){var att =GetAttribute<Att>(item);
                res.Add((item, att));}return res;}/// <summary>/// 返回带有Attribute的变量元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>publicstaticList<(PropertyInfo property, Att att)>GetAll_PropertyAndAtt<Att>(Type type)whereAtt:Attribute,new(){var res =newList<(PropertyInfo type, Att att)>();var typeLists =GetAllPropertys<Att>(type);foreach(var item in typeLists){var att =GetAttribute<Att>(item);
                res.Add((item, att));}return res;}/// <summary>/// 返回带有Attribute的方法元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>publicstaticList<(MethodInfo method, Att att)>GetAll_MethodAndAtt<Att>(Type type)whereAtt:Attribute,new(){var res =newList<(MethodInfo type, Att att)>();var typeLists =GetAllMethods<Att>(type);foreach(var item in typeLists){var att =GetAttribute<Att>(item);
                res.Add((item, att));}return res;}}}

5.特性应用

5.1 添加说明信息并获取

/// <summary>/// 备注特性/// </summary>publicclassRemarkAttribute:Attribute{privatestring Remark {get;set;}publicRemarkAttribute(string Remark){this.Remark = Remark;}publicstringGetRemark(){returnthis.Remark;}}// 枚举publicenumESex{[Remark("男")]
    male =1,[Remark("女")]
    female =2,}/// <summary>/// Enum扩展方法/// </summary>publicstaticclassEnumExtension{publicstaticstringGetRemark(thisEnum model){if(model isESex){Type type =typeof(ESex);FieldInfo fi = type.GetField(model.ToString());object[] attributes = fi.GetCustomAttributes(true);foreach(var attr in attributes){if(attr isRemarkAttribute){RemarkAttribute remark =(RemarkAttribute)attr;return remark.GetRemark();}}}returnstring.Empty;}}

使用:

Console.WriteLine(ESex.male.GetRemark());// 男

5.2 数据验证

可参考:
https://www.cnblogs.com/jiangxifanzhouyudu/p/11107734.html
(1)基类抽象特性

usingSystem;namespaceMyAttribute.ValidateExtend{publicabstractclassAbstractValidateAttribute:Attribute{publicabstractboolValidate(object oValue);}}

(2)子类特性实现–数字长度

usingSystem;namespaceMyAttribute.ValidateExtend{[AttributeUsage(AttributeTargets.Property)]publicclassLongAttribute:AbstractValidateAttribute{privatelong _Min =0;privatelong _Max =0;publicLongAttribute(long min,long max){this._Min = min;this._Max = max;}publicoverrideboolValidate(object oValue){return oValue !=null&&long.TryParse(oValue.ToString(),outlong lValue)&& lValue >=this._Min
                && lValue <=this._Max;}}}

(3)子类特性实现–可空

namespaceMyAttribute.ValidateExtend{publicclassRequiredAttribute:AbstractValidateAttribute{publicoverrideboolValidate(object oValue){return oValue !=null&&!string.IsNullOrWhiteSpace(oValue.ToString());}}}

(4)子类特性实现–字符串长度

usingSystem;namespaceMyAttribute.ValidateExtend{[AttributeUsage(AttributeTargets.Property)]publicclassStringLengthAttribute:AbstractValidateAttribute{privateint _Min =0;privateint _Max =0;publicStringLengthAttribute(int min,int max){this._Min = min;this._Max = max;}publicoverrideboolValidate(object oValue){return oValue !=null&& oValue.ToString().Length >=this._Min
                && oValue.ToString().Length <=this._Max;}}}

(5)泛型扩展方法

usingSystem;namespaceMyAttribute.ValidateExtend{publicstaticclassAttributeExtend{publicstaticboolValidate<T>(thisT t){Type type = t.GetType();foreach(var prop in type.GetProperties()){if(prop.IsDefined(typeof(AbstractValidateAttribute),true)){object oValue = prop.GetValue(t);foreach(AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute),true)){if(!attribute.Validate(oValue))returnfalse;}}}returntrue;}}}

(6)常规类字段定义

usingSystem;namespaceMyAttribute.ValidateExtend{publicstaticclassAttributeExtend{publicstaticboolValidate<T>(thisT t){Type type = t.GetType();foreach(var prop in type.GetProperties()){if(prop.IsDefined(typeof(AbstractValidateAttribute),true)){object oValue = prop.GetValue(t);foreach(AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute),true)){if(!attribute.Validate(oValue))returnfalse;}}}return tue;}}}

(7)类调用扩展方法验证字段

usingMyAttribute.EnumExtend;usingMyAttribute.ValidateExtend;usingSystem;namespaceMyAttribute{/// <summary>/// main方法调用/// </summary>classProgram{staticvoidMain(string[] args){try{#region 特性实现数据验证,并且可扩展{//通过特性去提供额外行为//数据验证--到处都需要验证StudentVip student =newStudentVip(){
                        Id =123,
                        Name ="无为",
                        QQ =729220650,
                        Salary =1010000};if(student.Validate()){
                        Console.WriteLine("特性校验成功");}//1 可以校验多个属性//2 支持多重校验//3 支持规则的随意扩展}#endregion}catch(Exception ex){
                Console.WriteLine(ex.Message);}
            Console.Read();}}}
标签: c# windows 服务器

本文转载自: https://blog.csdn.net/weixin_45136016/article/details/139151930
版权归原作者 明明明h 所有, 如有侵权,请联系我们删除。

“C# 特性(Attribute)超详细教程”的评论:

还没有评论