[Obsolete("请不要使用这个类!")] public class Child: Parent { }
在类上面使用 特性,然后重新编译就会有如下输出
如果使用 obsolete 的重载方法
由此
再者:
[Serializable] public class Child: Parent {}表示该类可以序列化
Attribute:
特性就是直接或者间接继承 于 attribute
约定俗称 特性 都以 Attribute 结尾,在书写的时候就像 MVC 的控制器省略 Collector 一样省略 Attribute
自己写一个特性:
//[AttributeUsage(AttributeTargets.All,AllowMultiple =true)] class CustomAttribute:Attribute { public CustomAttribute() { } public CustomAttribute(int num) { } public CustomAttribute(string str) { } }使用: 发现给一个类添加多个特性会报错
需要取消代码上的 注释,就可以添加多个重复特性
AttributeUsage 特性是用于特性的特性 ,
第一个参数决定了可以用于什么类型的对象 例如 class 类 ,delegate 委托,Method 方法等
第二个参数决定能否重复修饰
第三个参数 决定 子类中该特性是否生效
[AttributeUsage(AttributeTargets.All,AllowMultiple =true,Inherited =true)]特性的用法:
[Custom("字符串")] [Custom(Remark ="随便")] [Custom(Remark = "随便",Decision ="特性的字段可以这样赋值")] [return:Custom, Custom(Remark = "返回值也可以重复修饰", Decision = "特性的字段可以这样赋值")]//修饰返回值 public string CommonSay([Custom, Custom(Remark = "参数也可以重复修饰", Decision = "参数也可以重复修饰")] string str)//修饰参数 { Console.WriteLine("子级的普通方法"+str); return str; }通过反编译工具会发现在IL语言中 特性会 进入到标记的目标内部
这个.custom 我们无法在C#中访问到 ,我们自己写的特性似乎没任何用处
[Serializable] [Obsolete] 是系统自带的特性, 把他们带上反编译会产生什么呢?
用反射来获取特性:
public class InvokeCenter { public static void ManagerStudent<T>(T user) where T : Child { Console.WriteLine( $"{user.Id}_{user.Name}"); user.Study(); user.Answer(); var type = user.GetType(); //用反射获取类上的Custom 特性 if (type.IsDefined(typeof(CustomAttribute),true)) { object[] oAttributeArray = type.GetCustomAttributes(typeof(CustomAttribute),true); foreach (CustomAttribute attr in oAttributeArray) { attr.Show(); } } //用反射获取属性上的Custom 特性 foreach (var prop in type.GetProperties()) { if (prop.IsDefined(typeof(CustomAttribute), true)) { object[] attr = prop.GetCustomAttributes(typeof(CustomAttribute), true); foreach (CustomAttribute item in attr) { item.Show(); } } } //用反射获取属性上的Custom 特性 foreach (var method in type.GetMethods()) { if (method.IsDefined(typeof(CustomAttribute), true)) { object[] attr = method.GetCustomAttributes(typeof(CustomAttribute), true); foreach (CustomAttribute item in attr) { item.Show(); } } } } }特性代码:
[AttributeUsage(AttributeTargets.All,AllowMultiple =true,Inherited =true)] class CustomAttribute:Attribute { public CustomAttribute() { Console.WriteLine($"{this.GetType().Name}的无参构造函数"); } public CustomAttribute(int num) { Console.WriteLine($"{this.GetType().Name}的int构造函数"); this.Id = num; } public CustomAttribute(string str) { Console.WriteLine($"{this.GetType().Name}的string构造函数"); this.Name = str; } public int Id { get; set; } public string Name { get; set; } public string Remark { get; set; } public string Decision { get; set; } public void Show() { Console.WriteLine($"Id:{this.Id},Name:{this.Name},Remark:{this.Remark},Decision:{this.Decision}"); } }使用特性的类
[Custom] [Custom(123)] [Custom("456")] [Custom("456",Remark ="哈哈哈哈")] [Custom("456", Remark = "哈哈哈哈",Decision ="你好!")] public abstract class Parent { private void PrivSaySomeWord() { Console.WriteLine("我是一个私有方法!"); } private string PrivProp { get; set; } } [Serializable] [Obsolete] [Custom] public class Child: Parent { [Custom] public int Id { get; set; } [Custom] public string Name { get; set; } [Custom] public void Study() { Console.WriteLine("我在学习!"); } public void Answer() { Console.WriteLine("我在回答!"); } [Custom("字符串")] [Custom(Remark ="随便")] [Custom(Remark = "随便",Decision ="特性的字段可以这样赋值")] [return:Custom, Custom(Remark = "返回值也可以重复修饰", Decision = "特性的字段可以这样赋值")]//修饰返回值 public string CommonSay([Custom, Custom(Remark = "参数也可以重复修饰", Decision = "参数也可以重复修饰")] string str)//修饰参数 { Console.WriteLine("子级的普通方法"+str); return str; } }调用:
var child = new Child(); InvokeCenter.ManagerStudent(child); Console.ReadLine();结果:
如上特性本身是没有用的,需要依赖 第三方 例如 上面的类 InvokeCenter 类 去主动检测和使用
特性 是在编译时确定的 :有 string 类型的构造函数 ,但是使用 类的 属性 会报错 ,因为 特性早在编译时确定,不能用变量
