C#特性(Attribute)

  一、什么是特性

  特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。

  特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。

  特性的语法如下:

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

  element

  特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。

  二、预定义特性

  Obsolete特性

  这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保持类中的旧方法,您可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)。

  语法如下:

  [Obsolete(

  message

  )]

  [Obsolete(

  message,

  iserror

  )]

  其中:

  请看下面的一个小例子:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  [Obsolete("请不要使用该类了,该类已经过时了,请使用什么代替")]

  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}";

  }

  }

  }

  上面的例子中,在Student类上面使用了Obsolete特性来标注该类已经过时了。编译代码结果:

  三、自定义特性

  .Net 框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任何目标元素相关。

  创建并使用自定义特性包含四个步骤:

  1、声明自定义特性

  在上面的例子中,使用F12查看Obsolete的定义:

  从上面的截图中可以看出,.NET框架中的预定义特性是继承自Attribute类,所以要自定义一个特性,只需要该类继承自Attribute即可,下面定义一个Custom自定义特性:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  ///

  /// 自定义Custom特性

  ///

  public class CustomAttribute :Attribute

  {

  }

  }

  注意:所有的特性默认以Attribute结尾,但声明的时候可以不以Attribute结尾。

  2、构建自定义特性

  每个特性必须至少有一个构造函数。必需的定位( positional)参数应通过构造函数传递。下面的代码演示了CustomAttribute类:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  ///

  /// 自定义Custom特性

  ///

  public class CustomAttribute :Attribute

  {

  ///

  /// 无参构造函数

  ///

  public CustomAttribute()

  {

  }

  ///

  /// 有参构造函数

  ///

  ///

  public CustomAttribute(string description)

  {

  this.Description = description;

  }

  ///

  /// 属性

  ///

  public string Description { get; set; }

  ///

  /// 字段

  ///

  public string Remark = null;

  public void Show()

  {

  Console.WriteLine("This Is CustomAttribute");

  }

  }

  }

  3、在目标程序元素上应用自定义特性

  通过把特性放置在紧接着它的目标(类、方法、属性、字段等)上面,来应用该特性:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  [Obsolete("请不要使用该类了,该类已经过时了")]

  [Custom("这是Custom自定义特性")]

  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}";

  }

  }

  }

  注意:

  1、如果在声明自定义特性的时候使用了Attribute结尾,那么应用自定义特性的时候可以把Attribute省略掉;如果声明的时候没有以Attribute结尾,那么应用自定义特性的时候就不能把Attribute省略掉。

  2、默认情况下相同的特性只能应用一次,如果想应用多次特性,那么需要给特性添加AttributeUsage特性,CustomAttribute特性修改如下:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  ///

  /// 自定义Custom特性

  ///

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

  public class CustomAttribute :Attribute

  {

  ///

  /// 无参构造函数

  ///

  public CustomAttribute()

  {

  }

  ///

  /// 有参构造函数

  ///

  ///

  public CustomAttribute(string description)

  {

  this.Description = description;

  }

  ///

  /// 属性

  ///

  public string Description { get; set; }

  ///

  /// 字段

  ///

  public string Remark = null;

  public void Show()

  {

  Console.WriteLine("This Is CustomAttribute");

  }

  }

  }

  其中,AttributeTargets是枚举值,F12转到定义可以查看AttributeTargets的所有枚举值:

  AttributeTargets的枚举值表示Custom特性可以应用在哪些目标上面。例如:AttributeTargets的枚举值是Class,则表示CustomAttribute只能应用在类上面。这里枚举值是All,表示可以在任何类型上面使用该特性。默认情况下枚举值是All。

  AllowMultiple表示该特性是否可以在类型上面多次使用:

  这里AllowMultiple的值为true,表示可以在类型上面多次使用该特性。如果为false,则表示只能使用一次。默认情况下是false。

  Inherited表示该特性是否可以由子类继承:

  默认情况下Inherited为true。

  这是在看Student类:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  [Obsolete("请不要使用该类了,该类已经过时了")]

  [Custom("这是Custom自定义特性")]//使用有参构造

  [Custom()]//使用无参构造

  public class Student

  {

  public int Id { get; set; }

  ///

  /// 在属性上面使用Custom特性

  ///

  [Custom("这是Name属性")]

  public string Name { get; set; }

  public string Accont { get; set; }

  public long QQ { get; set; }

  ///

  /// 在方法和参数上面使用Custom特性

  ///

  ///

  ///

  [Custom("这是Answer方法")]

  public string Answer([Custom("这是方法参数")]string name)

  {

  return $"This is {name}";

  }

  }

  }

  注意:如果一个类型上面多次使用了同一种特性,那么特性可以写在一起,中间用逗号隔开,例如上面的定义和下面的是同样的效果:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  [Obsolete("请不要使用该类了,该类已经过时了")]

  [Custom("这是Custom自定义特性"),Custom,Custom(),Custom(Remark ="备注")]

  public class Student

  {

  public int Id { get; set; }

  ///

  /// 在属性上面使用Custom特性

  ///

  [Custom("这是Name属性")]

  public string Name { get; set; }

  public string Accont { get; set; }

  public long QQ { get; set; }

  ///

  /// 在方法、方法参数、方法的返回值上面使用Custom特性

  ///

  ///

  ///

  [Custom("这是Answer方法")]//方法上面应用特性

  [return:Custom()] //方法的返回值应用特性

  public string Answer([Custom("这是方法参数")]string name)

  {

  return $"This is {name}";

  }

  }

  }

  注意:在Web API中FromBaby和FromUri就是给方法的参数应用特性。

  4、通过反射访问特性

  定义一个Manager类来管理特性:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Reflection;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute

  {

  ///

  /// 管理特性

  ///

  public class Manager

  {

  public static void Show(Student student)

  {

  // 获取类型

  Type type = typeof(Student); //或者使用student.GetType();

  // 找到类型上面的特性 type.IsDefined表示找类型上面的特性

  if (type.IsDefined(typeof(CustomAttribute), true))//检查有没有 性能高

  {

  //GetCustomAttribute 获取特性 type.GetCustomAttribute表示找到类型上面定义的特性,表示调用构造函数创建一个CustomAttribute类型的对象

  CustomAttribute attribute = (CustomAttribute)type.GetCustomAttribute(typeof(CustomAttribute), true);

  // attribute.Description表示特性类里面的属性 attribute.Remark表示特性类里面的字段

  Console.WriteLine($"{attribute.Description}_{attribute.Remark}");

  attribute.Show();

  }

  #region 获取ID属性上面定义的特性

  // 获取Id属性

  PropertyInfo property = type.GetProperty("Id");

  //检查Id属性上面是否定义了CustomAttribute特性

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

  {

  CustomAttribute attribute = (CustomAttribute)property.GetCustomAttribute(typeof(CustomAttribute), true);

  Console.WriteLine($"{attribute.Description}_{attribute.Remark}");

  attribute.Show();

  }

  #endregion

  #region 获取Answer()方法上面定义的特性

  // 获取Answer方法

  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 获取参数定义的特性

  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 获取返回值定义的特性

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

  }

  }

  }

  Main()方法里面调用:

  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";

  // 使用Manager类管理Student

  Manager.Show(student);

  Console.ReadKey();

  }

  }

  }

  结果:

  四、应用特性

  场景一:用户状态的枚举值,定义的是英文的字段,需要输出中文含义。枚举定义如下:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute.Extension

  {

  ///

  /// 枚举类型 用户状态

  ///

  public enum UserState

  {

  ///

  /// 正常

  ///

  Normal = 0,

  ///

  /// 冻结

  ///

  Frozen = 1,

  ///

  /// 删除

  ///

  Deleted = 2

  }

  }

  普通做法:根据枚举值进行判断,然后输出中文含义:

  UserState userState = UserState.Normal;

  switch(userState)

  {

  case UserState.Normal:

  Console.WriteLine("正常");

  break;

  case UserState.Frozen:

  Console.WriteLine("冻结");

  break;

  case UserState.Deleted:

  Console.WriteLine("删除");

  break;

  }

  这种写法违反开不原则,不利于以后的扩展,下面使用特性实现。

  先定义Remark特性:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  using System.Reflection;

  namespace MyAttribute.Extension

  {

  ///

  /// RemarkAttribute 特性

  ///

  public class RemarkAttribute :Attribute

  {

  private string _Remark = null;

  ///

  /// 有参构造

  ///

  ///

  public RemarkAttribute(string remark)

  {

  this._Remark = remark;

  }

  public string GetRemark()

  {

  return _Remark;

  }

  }

  }

  UserState枚举修改如下:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute.Extension

  {

  ///

  /// 枚举类型 用户状态

  ///

  public enum UserState

  {

  ///

  /// 正常

  ///

  [Remark("正常")]

  Normal = 0,

  ///

  /// 冻结

  ///

  [Remark("冻结")]

  Frozen = 1,

  ///

  /// 删除

  ///

  [Remark("删除")]

  Deleted = 2

  }

  }

  对Enum类型进行扩展:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Reflection;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute.Extension

  {

  public static class EnumExtension

  {

  ///

  /// Enum的扩展方法,静态类、静态方法 第一个参数前面添加this关键字

  ///

  ///

  ///

  public static string GetRemark(this Enum value)

  {

  // 获取类型

  Type type = value.GetType();

  // 获取字段

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

  // 判断字段上面是否定义了RemarkAttribute特性

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

  {

  // 创建实例

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

  // 返回RemarkAttribute特性里面的GetRemark()方法

  return attribute.GetRemark();

  }

  else

  {

  return value.ToString();

  }

  }

  }

  }

  Main()方法里面调用:

  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";

  // 使用Manager类管理Student

  //Manager.Show(student);

  UserState userState = UserState.Normal;

  //switch(userState)

  //{

  // case UserState.Normal:

  // Console.WriteLine("正常");

  // break;

  // case UserState.Frozen:

  // Console.WriteLine("冻结");

  // break;

  // case UserState.Deleted:

  // Console.WriteLine("删除");

  // break;

  //}

  Console.WriteLine(userState.GetRemark());

  Console.ReadKey();

  }

  }

  }

  结果:

  场景二、做数据校验

  Student中有QQ这个属性,范围是10000-999999999999,校验QQ属性的值在这个范围区间内。

  1、定义一个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 :Attribute

  {

  ///

  /// 最小范围

  ///

  private long _MinRange = 0;

  ///

  /// 最大范围

  ///

  private long _MaxRange = 0;

  public RangeAttribute(long min,long max)

  {

  this._MinRange = min;

  this._MaxRange = max;

  }

  ///

  /// 检查属性范围

  ///

  ///

  ///

  public bool Check(object value)

  {

  if(value!=null && !string.IsNullOrWhiteSpace(value.ToString()))

  {

  if(long.TryParse(value.ToString(),out long IResult))

  {

  if(IResult>this._MinRange && IResult

  {

  return true;

  }

  }

  }

  return false;

  }

  }

  }

  2、在Student类的QQ属性上面应用特性

  [Range(10001,999999999999)]

  public long QQ { get; set; }

  3、对Object类型进行扩展

  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)

  {

  if(prop.IsDefined(typeof(LongAttribute)))

  {

  LongAttribute attribute = (LongAttribute)prop.GetCustomAttribute(typeof(LongAttribute));

  if(!attribute.Check(prop.GetValue(obj)))

  {

  msg = prop.Name + "检查失败";

  return false;

  }

  }

  }

  msg = "";

  return true;

  }

  }

  }

  4、在Manager类里面使用Validate扩展方法

  // 验证

  string msg = string.Empty;

  bool tfResult= student.Validate(out msg);

  if(!tfResult)

  {

  Console.WriteLine(msg);

  }

  5、在Main()方法里面调用

  Student student = new Student();

  student.Id = 123;

  student.Name = "time";

  student.QQ = 9999;

  // 使用Manager类管理Student

  Manager.Show(student);

  结果:

  如果这时候Student里面增加了Name属性,并且要验证Name属性的长度,这时需要增加一个验证属性长度的特性:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute.Extension

  {

  ///

  /// 验证长度的特性,只能应用于字段和属性上面

  ///

  [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)]

  public class LengthAttribute:Attribute

  {

  ///

  /// 最小长度

  ///

  private int _MinLength = 0;

  ///

  /// 最大长度

  ///

  private int _MaxLength = 0;

  public LengthAttribute(int min, int max)

  {

  this._MinLength = min;

  this._MaxLength = max;

  }

  ///

  /// 检查属性长度

  ///

  ///

  ///

  public bool Check(object value)

  {

  if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))

  {

  if (long.TryParse(value.ToString(), out long IResult))

  {

  if (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类管理Student

  Manager.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

  {

  return true;

  }

  }

  }

  return false;

  }

  }

  }

  LengthAttribute类:

  using System;

  using System.Collections.Generic;

  using System.Linq;

  using System.Text;

  using System.Threading.Tasks;

  namespace MyAttribute.Extension

  {

  ///

  /// 验证长度的特性,只能应用于字段和属性上面

  ///

  [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)]

  public class LengthAttribute: AbstractValidateAttribute

  {

  ///

  /// 最小长度

  ///

  private int _MinLength = 0;

  ///

  /// 最大长度

  ///

  private int _MaxLength = 0;

  public LengthAttribute(int min, int max)

  {

  this._MinLength = min;

  this._MaxLength = 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._MinLength && IResult < this._MaxLength)

  {

  return true;

  }

  }

  }

  return false;

  }

  }

  }

  3、修改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)

  {

  // 判断属性上面是否定义了AbstractValidateAttribute特性

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

  {

  // 属性上面可能会定义多个特性,所以这里使用数组

  object[] attributeArray = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true);

  foreach(AbstractValidateAttribute attribute in attributeArray)

  {

  if (!attribute.Check(prop.GetValue(obj)))

  {

  msg = string.Format($"属性{ prop.Name}检查失败");

  return false;

  }

  }

  }

  //// 检查属性上面是否定义了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;

  }

  }

  }

  4、运行结果:

  经过上面的修改以后,如果以后要新增一个特性,那么该特性只需要在本类中重写基类的Check()方法即可,而不需要在修改ObjectExtension扩展类。

  到此这篇关于C#特性的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  您可能感兴趣的文章:

相关文章