C# 特性

    xiaoxiao2022-07-14  143

    特性有什么用?

     

    [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 类型的构造函数 ,但是使用 类的 属性 会报错 ,因为 特性早在编译时确定,不能用变量

     

     

     

     

     

    最新回复(0)