.NET开发技术栈: 特性 Attributes
特性介绍
我们经常看到这样的代码
[Serializable] class Test { }
这种在类,字段,属性,方法等编程元素上以[ ] 标记的东东就是特性(Attribute)。
写在[] 中的特性其实就是一个类, 该类除了继承自 Attribute类, 与其他的普通类没有什么区别, 有很多自带的特性, 我们也可以通过定义这样的类来定义自己的特性。
特性类约定俗称一般以Attribute结尾, 当以Attribute结尾时,标记的时候可以省略Attribute。
比如 CustomTagAttribute 标记时可以这么写[CustomTag], 而CustomAttributeTag 标记时不能写成 [CustomTag]。
标记了这玩意之后我们可以在程序运行时通过反射读取
[ClassAttribute("类上的参数")] public class Hero { [PropAttribute("属性上的参数")] public string name { get; set; } [FieldAttribute("字段上的参数")] public int age; [MethodAttribute("方法上的参数")] public void Attack() { Console.WriteLine($"{name}发起攻击"); } } /// <summary> /// 自定义特性 /// AttributeUsage:在定义特性的时候,对特性的约束 /// AllowMultiple =true:允许多次标记 /// Inherited =true:约束当前特性是否可以继承 /// AttributeTargets.All:当前特性可以标记在所有的元素上 /// /// </summary> [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)] public abstract class MyAttribute : Attribute { public string param; public abstract void Show(); } public class ClassAttribute : MyAttribute { public ClassAttribute(string param) { this.param = param; } public override void Show() { Console.WriteLine($"【调用方法】标记在类上的特性, 参数:{param}"); } } public class FieldAttribute : MyAttribute { public FieldAttribute(string param) { this.param = param; } public override void Show() { Console.WriteLine($"【调用方法】标记在字段上的特性, 参数{param}"); } } public class PropAttribute : MyAttribute { public PropAttribute(string param) { this.param = param; } public override void Show() { Console.WriteLine($"【调用方法】标记在属性上的特性, 参数{param}"); } } public class MethodAttribute : MyAttribute { public MethodAttribute(string param) { this.param = param; } public override void Show() { Console.WriteLine($"【调用方法】标记在方法上的特性, 参数{param}"); } } static void Main(string[] args) { var hero = new Hero(); // 获取标记在类上的特性 var type = hero.GetType(); if (type.IsDefined(typeof(MyAttribute), true)) //获取其前先判断 foreach (MyAttribute attr in type.GetCustomAttributes()) //把所有标记的特性都实例化了 { Console.WriteLine($"【访问字段】传入的参数: {attr.param}"); //访问特性类中的属性,字段 attr.Show(); //调用特性类中的方法 } //获取标记在属性或字段上的特性 foreach (PropertyInfo prop in type.GetProperties()) { if (prop.IsDefined(typeof(MyAttribute), true)) { foreach (MyAttribute attr in prop.GetCustomAttributes()) { Console.WriteLine($"【访问字段】传入的参数: {attr.param}"); attr.Show(); } } } //获取标记在方法上的特性 foreach (MethodInfo method in type.GetMethods()) { if (method.IsDefined(typeof(MyAttribute), true)) { foreach (MyAttribute attr in method.GetCustomAttributes()) { Console.WriteLine($"【访问字段】传入的参数: {attr.param}"); attr.Show(); } } }
}
特性目标
可以通过在特性类上标记AttributeUsage特性来限制当前特性可以标记在什么地方, 防止胡乱调用, 该特性可以传一个枚举参数 AttributeTargets, 该枚举的定义如下:
public enum AttributeTargets { Assembly = 0x0001, Module = 0x0002, Class = 0x0004, Struct = 0x0008, Enum = 0x0010, Constructor = 0x0020, Method = 0x0040, Property = 0x0080, Field = 0x0100, Event = 0x0200, Interface = 0x0400, Parameter = 0x0800, Delegate = 0x1000, All = Assembly │ Module │ Class │ Struct │ Enum │ Constructor │ Method │ Property │ Field │ Event │ Interface │ Parameter │ Delegate, ClassMembers = Class │ Struct │ Enum │ Constructor │ Method │ Property │ Field │ Event │ Delegate │ Interface, }
总结
特性必须结合反射使用,通过特性我们可以在执行正常的逻辑中额外加入一些信息或者功能,这样可以使程序设计得更灵活, 更具扩展性。
浙公网安备 33010602011771号