1. 特性

1.1        特性Attribute

特性就是一个类,继承自Attribute抽象类(该类无抽象方法、避免实例化),约定俗成用Attribute类结尾,标记时可省略掉Attribute。

用[]修饰,标记到字段,实际上就是调用构造函数,可以指定属性、字段。

AttributeTargets,枚举表示可修饰的对象(类、方法、属性等)

特性对程序运行和编译器有影响([Obsolete]影响编译)。

1.2        声明和使用Attribute,AttributeUsage

4.2.1 声明Attribute

public class CustomAttribute:Attribute//继承自Attribute

{

private int _Id = 0;

private string _Name = null;

public string Remark;//字段

public string Description { get; set; }//属性

public CustomAttribute()//构造函数重载

{

Console.WriteLine($"{this.GetType().Name}无参构造函数");

}

public CustomAttribute(string name)

{

Console.WriteLine($"{this.GetType().Name}.{name} string构造函数");

}

public CustomAttribute(int age)

{

Console.WriteLine($"{this.GetType().Name}.{age} age构造函数");

}

public void Show()

{

Console.WriteLine($"Name is :{this._Name},age is {this._Id},Remark is {this.Remark},Descripiton is {Description}");

}

}

}

4.2.2 使用Attribute

[Custom]//根据4.2.3的设置AttributeUsage设置,可以设置不同的元素、同一元素可以设置多个属性

public class People

{

public void Say()

{

Console.WriteLine("Hello everybody");

}

[Custom]

[Custom(116)]

public string Study(string name)

{

return $"{name} like study";

}

}

4.2.3 AttributeUsage

指定另一个属性类的用法。

[AttributeUsage(AttributeTargets.All,AllowMultiple =true, Inherited =true)]

4.2.3.1 AttributeTargets:

获取一组标识所指示的特性可以应用于哪些程序元素//

// 摘要:

//     特性可以应用于程序集。

Assembly = 1,

//

// 摘要:

//     特性可以应用于模块中。

Module = 2,

//

// 摘要:

//     特性可以应用于类。

Class = 4,

//

// 摘要:

//     特性可以应用于结构;即,类型值。

Struct = 8,

//

// 摘要:

//     特性可以应用于枚举。

Enum = 16,

//

// 摘要:

//     特性可以应用于构造函数。

Constructor = 32,

//

// 摘要:

//     特性可以应用于方法。

Method = 64,

//

// 摘要:

//     特性可以应用于属性。

Property = 128,

//

// 摘要:

//     特性可以应用于字段。

Field = 256,

//

// 摘要:

//     特性可以应用于事件。

Event = 512,

//

// 摘要:

//     特性可以应用于接口。

Interface = 1024,

//

// 摘要:

//     特性可以应用于参数。

Parameter = 2048,

//

// 摘要:

//     特性可以应用于委托。

Delegate = 4096,

//

// 摘要:

//     特性可以应用于返回的值。

ReturnValue = 8192,

//

// 摘要:

//     特性可以应用于泛型参数。

GenericParameter = 16384,

//

// 摘要:

//     特性可以应用于任何应用程序元素。

All = 32767

4.2.3.2 AllowMultiple

获取或设置一个布尔值,该值指示是否可以为一个程序元素指定多个实例所指示的特性

4.2.3.3 Inherited

该值确定指示的属性是否由派生类和重写成员继承,默认值为 true

1.3        运行中获取Attribute:额外信息 额外操作

4.3.1 自定义的Attribute

public class CustomAttribute:Attribute

{

private int _Id = 0;

private string _Name = null;

public string Remark;

public string Description { get; set; }

public CustomAttribute()

{

Console.WriteLine($"{this.GetType().Name}无参构造函数");

}

public CustomAttribute(string name)

{

Console.WriteLine($"{this.GetType().Name}.{name} string构造函数");

}

public CustomAttribute(int age)

{

Console.WriteLine($"{this.GetType().Name}.{age} age构造函数");

}

public void Show()

{

Console.WriteLine($"Name is :{this._Name},age is {this._Id},Remark is {this.Remark},Descripiton is {Description}");

}

}

4.3.2 定义触发

public class InvokeCenter

{

public static void ManagerPeople<T>(T t)

where T : People

{

Console.WriteLine($"Name is {t.Name},Age is {t.Age}");

t.Say();

t.Study("Olive");

Type type = t.GetType();

if(type.IsDefined(typeof(CustomAttribute),true))

{

object[] attributeArr = type.GetCustomAttributes(typeof(CustomAttribute), true);

foreach(CustomAttribute attr in attributeArr)

{

attr.Show();

}

foreach(var prop in type.GetProperties())

{

if(prop.IsDefined(typeof(CustomAttribute),true))

{

object[] propAttributeArr = prop.GetCustomAttributes(typeof(CustomAttribute), true);

foreach(CustomAttribute custom in propAttributeArr)

{

custom.Show();

}

}

}

foreach (var method in type.GetMethods())

{

if (method.IsDefined(typeof(CustomAttribute), true))

{

object[] propAttributeArr = method.GetCustomAttributes(typeof(CustomAttribute), true);

foreach (CustomAttribute custom in propAttributeArr)

{

custom.Show();

}

}

}

}

}

4.3.3 标记、触发

4.3.3.1标记

[Custom]

public class People

{

[Custom(30)]

public int Age { get; set; }

[Custom("墨遥")]

public string Name { get; set; }

[Custom("墨遥",Description ="你好啊", Remark ="周末")]

public void Say()

{

Console.WriteLine("Hello everybody");

}

[Custom]

[Custom(116)]

public string Study(string name)

{

return $"{name} like study";

}

}

4.3.3.2 触发

InvokeCenter.ManagerPeople<People>(new People() { Name = "Olive", Age = 30 });

1.4        Remark封装、Attribute验证

1.4.1  特性封装提供额外信息Remark封装

1.4.1.1      定义RemarkAttribute

[AttributeUsage(AttributeTargets.Field)]//该特性只能作用于字段上

public class RemarkAttribute:Attribute

{

public string Remark { get; private set; }

public RemarkAttribute(string remark)

{

this.Remark = remark;

}

}

1.4.1.2      定义枚举、标记特性

public enum UserState

{

[Remark("正常")]

Normal=0,

[Remark("已冻结")]

Frozen =1,

[Remark("已删除")]

Deleted =2

}

1.4.1.3      为枚举添加扩展方法

/// <summary>

/// 为Enum类型新增扩展方法,获取添加在字段上的特性的Remark信息

/// </summary>

public static class AttributeExtend

{

public static string GetRemark(this Enum value)

{

Type type = value.GetType();

var field = type.GetField(value.ToString());

if (field.IsDefined(typeof(RemarkAttribute), true))

{

RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true);

return attribute.Remark;

}

else

return value.ToString();

}

}

1.4.1.4      调用

UserState userState = UserState.Deleted;

userState.GetRemark();

1.4.2  特性封装提供额外行为Validate验证

1.4.2.1      定义抽象的ValidateAttribute

/// <summary>

/// 校验抽象类

/// </summary>

public abstract class AbstractValidateAttribute:Attribute

{

/// <summary>

/// 抽象校验方法,子类需要实现该方法

/// </summary>

/// <param name="obj"></param>

/// <param name="errorInfo">校验失败的提示,来自于Descripiton</param>

/// <returns></returns>

public abstract bool Validate(object obj,out string errorInfo);

/// <summary>

/// 用来表述校验规则

/// </summary>

public string Description { get; set; }

}

1.4.2.2      实现抽象的ValidateAttribute

1.4.2.2.1              LongAttribute(数据范围)

/// <summary>

/// 数据范围校验特性

/// </summary>

[AttributeUsage(AttributeTargets.Property)]

public class LongAttribute:AbstractValidateAttribute

{

private long _min = 0;

private long _max = 0;

public LongAttribute(long min,long max)

{

_min = min;

_max = max;

}

public override bool Validate(object obj, out string error)

{

error = Description;

return obj != null

&& long.TryParse(obj.ToString(), out long v)

&& v >= this._min

&& v <= this._max;

}

}

}

1.4.2.2.2              RequiredAttribute(必填)

/// <summary>

/// 必填校验特性

/// </summary>

[AttributeUsage(AttributeTargets.Property)]

public class RequiredAttribute:AbstractValidateAttribute

{

public override bool Validate(object obj,out string error)

{

error = Description;

return obj != null && !string.IsNullOrWhiteSpace(obj.ToString());

}

}

1.4.2.2.3              StringLengthAttribute(字符串长度)

/// <summary>

/// 字符串长度校验特性

/// </summary>

[AttributeUsage(AttributeTargets.Property)]

public class StringLengthAttribute:AbstractValidateAttribute

{

private int _min = 0;

private int _max = 0;

public StringLengthAttribute(int min, int max)

{

_min = min;

_max = max;

}

public override bool Validate(object obj, out string error)

{

error = Description;

return obj != null

&& obj.ToString().Length >= this._min

&& obj.ToString().Length <= this._max;

}

}

1.4.2.3      为类扩展校验方法

需要传入一个out类型的string参数,作为校验信息的汇总

public static  class AttributeExtend

{

public static bool Validate<T>(this T t,out string errorInfo)

{

Type type = t.GetType();

errorInfo = "";

bool result = true;

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))

{

string error = "";

if (!attribute.Validate(oValue, out error))

{

errorInfo += error + "\r\n";

result=false;

}

}

}

}

return result;

}

}

1.4.2.4      标记特性

[Custom("Olive",Description ="中国人", Remark ="Very Good")]

public class Chinese

{

[Required(Description ="ID为必填项")]

public int Id { get; set; }

[Required(Description = "Name为必填项")]

[StringLength(2,12,Description = "Name的长度为2——12")]

public string Name { get; set; }

[Required(Description = "Age为必填项")]

public int Age { get; set; }

[Required(Description = "QQ为必填项")]

[StringLength(5, 12,Description = "QQ的长度为5——12")]

public string QQ { get; set; }

[Long(10000,100000, Description = "Salary的范围为10000——100000")]

public int Salary { get; set; }

}

1.4.2.5      调用

Chinese chinese = new Chinese() { Id = 1, Name = "墨", Age = 30, QQ = "318950585318950585", Salary = 250000 };

var error = "";

if (chinese.Validate(out error))

{

Console.WriteLine("特性校验成功");

}

else

Console.WriteLine($"特性校验失败,失败原因是:{error}");

结果如下:

.NET知识梳理——4.特性Attribute的更多相关文章

  1. [C#] C# 知识回顾 - 特性 Attribute

    C# 知识回顾 - 特性 Attribute [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5911289.html 目录 特性简介 使用特性 特性 ...

  2. C# 知识特性 Attribute

    C#知识--获取特性 Attribute 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体关联后,可在运行时使用"反射"查询 ...

  3. C# 知识特性 Attribute,XMLSerialize,

    C#知识--获取特性 Attribute 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体关联后,可在运行时使用“反射”查询特性,获取特性集合方 ...

  4. c#知识梳理

    转:http://www.cnblogs.com/zhouzhou-aspnet/articles/2591596.html 本文是一个菜鸟所写,本文面向的人群就是像我这样的小菜鸟,工作一年也辛辛苦苦 ...

  5. [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute

    剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...

  6. [SQL] SQL 基础知识梳理(四) - 数据更新

    SQL 基础知识梳理(四) - 数据更新 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5929786.html 序 这是<SQL 基础知识梳理( ...

  7. [C# 基础知识梳理系列]专题六:泛型基础篇——为什么引入泛型

    引言: 前面专题主要介绍了C#1中的2个核心特性——委托和事件,然而在C# 2.0中又引入一个很重要的特性,它就是泛型,大家在平常的操作中肯定会经常碰到并使用它,如果你对于它的一些相关特性还不是很了解 ...

  8. C# 自定义特性Attribute

    一.特性Attribute和注释有什么区别 特性Attribute A:就是一个类,直接继承/间接继承Attribute B:特性可以在后期反射中处理,特性本身是没有什么*用的 C:特性会影响编译和运 ...

  9. Babel7知识梳理

    Babel7 知识梳理 对 Babel 的配置项的作用不那么了解,是否会影响日常开发呢?老实说,大多情况下没有特别大的影响(毕竟有搜索引擎). 不过呢,还是想更进一步了解下,于是最近认真阅读了 Bab ...

随机推荐

  1. everspin最新1Gb容量扩大MRAM吸引力

    everspin提供了8/16-bit的DDR4-1333MT/s(667MHz)接口,但与较旧的基于DDR3的MRAM组件一样,时序上的差异使得其难以成为DRAM(动态随机存取器)的直接替代品.   ...

  2. 吴裕雄--天生自然轻量级JAVA EE企业应用开发Struts2Sping4Hibernate整合开发学习笔记:Spring_autowire

    <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www. ...

  3. 查找第K大的值

    这种题一般是给定N个数,然后N个数之间通过某种计算得到了新的数列,求这新的数列的第K大的值 POJ3579 题意: 用$N$个数的序列$x[i]$,生成一个新序列$b$. 新的序列定义为:对于任意的$ ...

  4. C#_.net core 3.0自定义读取.csv文件数据_解决首行不是标题的问题_Linqtocsv改进

    linqtocsv文件有不太好的地方就是:无法设置标题的行数,默认首行就是标题,这不是很尴尬吗?   并不是所有的csv文件严格写的首行是标题,下面全是数据,我接受的任务就是读取很多.csv报表数据, ...

  5. Demrystv

    Determined Energetic Motivated Reliable Yes Stick To Victory

  6. 论文阅读笔记(二十三)【ECCV2018】:Robust Anchor Embedding for Unsupervised Video Person Re-Identification in the Wild

    Introduction 当前主要的非监督方法都采用相同的训练数据集,这些数据集在不同摄像头中是对称的,即不存在单个行人的错误项,这些方法将在实际场景中效果下降.在本方法中,作者引入了非对称数据,如下 ...

  7. Socket通讯探索(二)-socket集群

    前面我们在章节“Socket通讯探索(一)”中如何实现一个tcp连接,但是这仅仅是一个最初级的BIO实现,且没有添加线程池,实际应用中很少采用这种方式,因为不得不考虑当大量的Tcp连接建立的时候,服务 ...

  8. 洛谷题解 P1592 【互质】

    原题传送门 题目描述 输入两个正整数n和k,求与n互质的第k个正整数. 输入格式 仅一行,为两个正整数n(≤10^6)和k(≤10^8). 输出格式 一个正整数,表示与n互质的第k个正整数. 输入输出 ...

  9. XSS攻击解决办法 Spring mvc databinder

    XSS攻击解决办法 一.SpringMVC架构下@InitBinder方法 Controller方法的参数类型可以是基本类型,也可以是封装后的普通Java类型.若这个普通Java类型没有声明任何注解, ...

  10. TChart-图表编辑器的测试

    最近不知怎么的,想研究一下图表.先上效果图: 功能代码: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Class ...