翼度科技»论坛 编程开发 .net 查看内容

第32篇 .Net特性Attribute的高级使用

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
今天给大家讲讲.net中特性的高级使用

1.什么是特性
  1. 特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。
  2. 用[]来标识,在.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
复制代码
2.预定义特性


  • AttributeUsage
  • Conditional
  • obsolete
2.1 AttributeUsage
使用AttributeUsage特性,必须集成Attribute抽象类;
  1. [AttributeUsage(AttributeTargets.Property)]//只能标记在属性上
  2. public class MyCustomAttribute: Attribute
  3. {
  4. }
复制代码
AttributeUsage 使用语法详细如下:
  1. [AttributeUsage(AttributeTargets.Class |//特性只能运用于类上
  2. AttributeTargets.Constructor |//特性只能运用于构造函数上
  3. AttributeTargets.Field |//特性只能运用于字段上
  4. AttributeTargets.Method |//特性只能运用于方法上
  5. AttributeTargets.Property, //特性只能运用于属性上
  6. AllowMultiple = true)]//true:可以为程序元素指定有多个实例
复制代码
其中:
参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
2.2 Conditional
这个预定义特性标记了一个条件方法,
它会引起方法调用的条件编译,取决于指定的值,比如 Debug 或 Trace。例如,当调试代码时显示变量的值。
规定该特性的语法如下:
  1. public class MyTest
  2.         {
  3.                 [Conditional("DEBUG")]
  4.                 public static void Message(string msg)
  5.                 {
  6.                         Console.WriteLine(msg);
  7.                 }
  8.         }
  9. class Program
  10.         {
  11.                 static void function1()
  12.                 {
  13.                         MyTest.Message("In Function 1.");
  14.                         function2();
  15.                 }
  16.                 static void function2()
  17.                 {
  18.                         MyTest.Message("In Function 2.");
  19.                 }
  20.                 static void Main(string[] args)
  21.                 {
  22.                         MyTest.Message("In Main function.");
  23.                         function1();
  24.                         Console.ReadLine();
  25.            }
  26. }
复制代码
当上面的代码被编译和执行时,它会产生下列结果:

2.3 Obsolete 过时
这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保持类中的旧方法,您可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)。
规定该特性的语法如下:
[Obsolete(message)]
[Obsolete(message, iserror)]
其中:
参数 message,是一个字符串,描述项目为什么过时的原因以及该替代使用什么。
参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。
下面的实例演示了该特性:
  1. public class MyTest
  2.         {
  3.                 [Obsolete("该方法已过期,你可使用xxx最新方法")]
  4.                 public static void Message(string msg)
  5.                 {
  6.                         Console.WriteLine(msg);
  7.                 }
  8.         }
复制代码
当编译程序时会出现如下效果,通常该特性用于在方法过期上、版本变更等等
  1. public class MyTest
  2.         {
  3.                 [Obsolete("该方法已经不可使用,请使用最新XXX方法",true)]
  4.                 public static void Message(string msg)
  5.                 {
  6.                         Console.WriteLine(msg);
  7.                 }
  8.         }
复制代码
当编译程序时会出现如下效果,可导致程序无法生成

3.自定义特性

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

  • 声明自定义特性
  • 构建自定义特性
  • 在目标程序元素上应用自定义特性
  • 通过反射访问特性
最后一个步骤包含编写一个简单的程序来读取元数据以便查找各种符号。元数据是用于描述其他数据的数据和信息。该程序应使用反射来在运行时访问特性。
声明自动以特性
一个新的自定义特性应派生自 System.Attribute 类。例如:
  1. /// <summary>
  2.         /// 自定义日志打印
  3.         /// </summary>
  4.         [AttributeUsage(AttributeTargets.Method)]
  5.         public class PrintLogAttribute: Attribute
  6.         {
  7.                 private string _userName;
  8.                 private string _msg;
  9.                 public PrintLogAttribute(string userNaame, string msg)
  10.                 {
  11.                         this._userName = userNaame;
  12.                         this._msg = msg;
  13.                         Console.WriteLine($"{userNaame}于【{DateTime.Now.ToString("yyyy-MM-dd")}】{msg}");
  14.                 }
  15.                 public string GetMsg()
  16.                 {
  17.                         return $"{this._userName}于【{DateTime.Now.ToString("yyyy-MM-dd")}】{this._msg}";
  18.                 }
  19.         }
  20.        
  21. public  class PrintLogTest
  22.         {
  23.                 [PrintLog("张三","学习Attribute")]
  24.                 public   void Study()
  25.                 {
  26.                         Console.WriteLine("张三在学习....");
  27.                 }
  28.                 [PrintLog("张三", "SayHello")]
  29.                 public  string SayHello()
  30.                 {
  31.                         return "hello";
  32.                 }
  33.         }
  34. class Program
  35.         {
  36.                 static void Main(string[] args)
  37.                 {
  38.                         PrintLogTest test=new PrintLogTest();
  39.                         test.Study();
  40.                         Type type = test.GetType();
  41.                         var methods = type.GetMethods();//获取所有公开方法
  42.                         foreach (MemberInfo item in methods)
  43.                         {
  44.                                 if (item.IsDefined(typeof(PrintLogAttribute), true))//判断该方法是否被PrintLogAttribute标记
  45.                                 {
  46.                                         PrintLogAttribute attribute = item.GetCustomAttribute(typeof(PrintLogAttribute)) as PrintLogAttribute;//实例化PrintLogAttribute
  47.                                         var msg = attribute.GetMsg();
  48.                                         Console.WriteLine($"得到标记信息:{msg}");
  49.                                 }
  50.                         }
  51.                         Console.ReadKey();
  52.                 }
  53.         }
复制代码
执行Main方法,执行如下:

4.Attribute特性的作用

使用面向抽象编程的思想进行优化,添加一个AbstractCustomAttribute抽象类,所有的校验类都继承AbstractCustomAttribute
  1. /// <summary>
  2.         ///
  3.         /// </summary>
  4.         public abstract class AbstractCustomAttribute: Attribute//继承Attribute特性类
  5.         {
  6.                 /// <summary>
  7.                 /// 定义校验抽象方法
  8.                 /// </summary>
  9.                 /// <param name="value">需要校验的值</param>
  10.                 /// <returns></returns>
  11.                 public abstract bool Validate(object value);
  12.         }
复制代码
RequiredAttribute、StringLengthAttribute自定义验证特性代码如下:
  1. /// <summary>
  2.         /// 自定义验证,验证不为空
  3.         /// </summary>
  4.         [AttributeUsage(AttributeTargets.Property)]
  5.         public class RequiredAttribute : AbstractCustomAttribute
  6.         {
  7.                 /// <summary>
  8.                 /// 重写Validate校验方法
  9.                 /// </summary>
  10.                 /// <param name="value">需要校验的参数</param>
  11.                 /// <returns></returns>
  12.                 public override bool Validate(object value)
  13.                 {
  14.                         return value != null && !string.IsNullOrWhiteSpace(value.ToString());
  15.                 }
  16.         }
  17.         /// <summary>
  18.         /// 自定义验证,验证字符长度
  19.         /// </summary>
  20.         [AttributeUsage(AttributeTargets.Property)]
  21.         public class StringLengthAttribute: AbstractCustomAttribute
  22.         {
  23.                 private int _MaxLength;
  24.                 private int _MinLength;
  25.                 /// <summary>
  26.                 ///
  27.                 /// </summary>
  28.                 /// <param name="MinLength">最小长度</param>
  29.                 /// <param name="MaxLength">最大长度</param>
  30.                 public StringLengthAttribute(int MinLength,int MaxLength)
  31.                 {
  32.                         this._MaxLength = MaxLength;
  33.                         this._MinLength = MinLength;
  34.                 }
  35.                 /// <summary>
  36.                 /// 重写Validate校验方法
  37.                 /// </summary>
  38.                 /// <param name="value">需要校验的参数</param>
  39.                 /// <returns></returns>
  40.                 public override bool Validate(object value)
  41.                 {
  42.                         return value != null && value.ToString().Length >= _MinLength && value.ToString().Length <= _MaxLength;
  43.                 }
  44.         }
复制代码
修改UserEntity实体类,添加自定义验证失败的错误信息
  1. public static class CustomValidateExtend
  2.         {
  3.                 /// <summary>
  4.                 /// 校验
  5.                 /// </summary>
  6.                 /// <typeparam name="T"></typeparam>
  7.                 /// <returns></returns>
  8.                 public static bool Validate<T>(this T entity) where T:class
  9.                 {
  10.                         Type type = entity.GetType();
  11.                         foreach (var item in type.GetProperties())
  12.                         {
  13.                                 if (item.IsDefined(typeof(AbstractCustomAttribute), true))//此处是重点
  14.                                 {
  15.                                         //此处是重点
  16.                                         foreach (AbstractCustomAttribute attribute in item.GetCustomAttributes(typeof(AbstractCustomAttribute), true))
  17.                                         {
  18.                                                 if (attribute == null)
  19.                                                 {
  20.                                                         throw new Exception("StringLengthAttribute not instantiate");
  21.                                                 }
  22.                                                 if (!attribute.Validate(item.GetValue(entity)))
  23.                                                 {
  24.                                                         return false;
  25.                                                 }
  26.                                         }
  27.                                 }
  28.                         }
  29.                         return true;
  30.                 }
  31.         }
复制代码
测试代码:
  1. /// <summary>
  2.         /// 校验结果实体类
  3.         /// </summary>
  4.         public class ValidateResultEntity
  5.         {
  6.                 /// <summary>
  7.                 /// 是否校验成功
  8.                 /// </summary>
  9.                 public bool IsValidateSuccess { get; set; }
  10.                 /// <summary>
  11.                 /// 校验不通过的字段信息存储字段
  12.                 /// </summary>
  13.                 public List<FieidEntity> ValidateMessage { get; set; }
  14.         }
  15.         /// <summary>
  16.         /// 字段信息
  17.         /// </summary>
  18.         public class FieidEntity
  19.         {
  20.                 /// <summary>
  21.                 /// 字段名称
  22.                 /// </summary>
  23.                 public string FieidName { get; set; }
  24.                 /// <summary>
  25.                 /// 字段类型
  26.                 /// </summary>
  27.                 public string FieidType { get; set; }
  28.                 /// <summary>
  29.                 /// 验证错误时提示信息
  30.                 /// </summary>
  31.                 public string ErrorMessage { get; set; }
  32.         }
复制代码

最终我们做到了通过特性进行校验字段数据,不再写那种繁琐又臭又长的判断代码了。以上代码还可以继续优化,还可以使用泛型缓存提高其性能。
最后介绍一波微软的模型验证,
引用【System.ComponentModel.DataAnnotations】
里面有:
[Required]
[Range]
........
详情可查看【模型验证】
使用ActionFilterAttribute过滤器我们可以进行校验操作,核心代码如下:
  1. /// <summary>
  2.         /// 自定义验证,验证不为空
  3.         /// </summary>
  4.         [AttributeUsage(AttributeTargets.Property)]
  5.         public class RequiredAttribute : AbstractCustomAttribute
  6.         {
  7.                 private string _ErrorMessage = "";
  8.                 public RequiredAttribute()
  9.                 {
  10.                 }
  11.                 public RequiredAttribute(string ErrorMessage)
  12.                 {
  13.                         this._ErrorMessage = ErrorMessage;
  14.                 }
  15.                 /// <summary>
  16.                 /// 重写Validate校验方法
  17.                 /// </summary>
  18.                 /// <param name="value">需要校验的参数</param>
  19.                 /// <returns></returns>
  20.                 public override FieidEntity Validate(object value)
  21.                 {
  22.                         if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
  23.                         {
  24.                                 return null;
  25.                         }
  26.                         return new FieidEntity()
  27.                         {
  28.                                 ErrorMessage = string.IsNullOrWhiteSpace(_ErrorMessage) ? "字段不能为空" : _ErrorMessage,
  29.                         };
  30.                 }
  31.         }
  32.         /// <summary>
  33.         /// 自定义验证,验证字符长度
  34.         /// </summary>
  35.         [AttributeUsage(AttributeTargets.Property)]
  36.         public class StringLengthAttribute: AbstractCustomAttribute
  37.         {
  38.                 private int _MaxLength;
  39.                 private int _MinLength;
  40.                 private string _ErrorMessage;
  41.                 /// <summary>
  42.                 ///
  43.                 /// </summary>
  44.                 /// <param name="MinLength">最小长度</param>
  45.                 /// <param name="MaxLength">最大长度</param>
  46.                 public StringLengthAttribute(int MinLength,int MaxLength,string ErrorMessage="")
  47.                 {
  48.                         this._MaxLength = MaxLength;
  49.                         this._MinLength = MinLength;
  50.                         this._ErrorMessage = ErrorMessage;
  51.                 }
  52.                 /// <summary>
  53.                 /// 重写Validate校验方法
  54.                 /// </summary>
  55.                 /// <param name="value">需要校验的参数</param>
  56.                 /// <returns></returns>
  57.                 public override FieidEntity Validate(object value)
  58.                 {
  59.                         if (value != null && value.ToString().Length >= _MinLength && value.ToString().Length <= _MaxLength)
  60.                         {
  61.                                 return null;
  62.                         }
  63.                         return new FieidEntity()
  64.                         {
  65.                                 ErrorMessage = string.IsNullOrWhiteSpace(_ErrorMessage) ? $"字段长度必须大于等于{_MinLength}并且小于等于{_MaxLength}" : _ErrorMessage,
  66.                         };
  67.                 }
  68.         }
复制代码
来源:https://www.cnblogs.com/chenshibao/p/18466367
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具