zoukankan      html  css  js  c++  java
  • Attribute

        • 1.什么是特性
        • 2.应用特性
        • 3.预定义的保留的特性
          • 3.1 Obsolete特性
          • 3.2 Conditional特性
          • 3.3 调用者信息特性
          • 3.4 DebuggerStepThrough特性
        • 4.特性的其他内容
          • 4.1 多个特性
          • 4.2 其他类型的目标
          • 4.3 全局特性
        • 5.自定义特性
          • 5.1 声明自定义特性
          • 5.2 使用特性的构造函数
          • 5.3 指定构造函数
          • 5.4 构造函数中的位置参数和命名参数
          • 5.5 限制特性的使用
        • 6.访问特性
          • 6.1 使用IsDefined方法
          • 6.2 使用GetCustomAttributes方法

    1.什么是特性

    特性(attribute)是一种允许向程序的程序集增加元数据的语言结构,它是用于保存程序结构信息的某种特殊类型的类。

    • 将应用了特性的程序结构叫做目标
    • 设计用来获取和使用元数据的程序叫做特性的消费者
      image

    2.应用特性

    特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集,可以通过把特性应用到结构来实现。

    • 在结构前放置特性片段来应用特性
    • 特性片段被方括号包围,其中是特性名和特性的参数列表
    [ Serializable ] // 特性
    public class MyClass {...} 
    [ MyAttribute("Simple Class", "Version 0.0.1") ] // 带有参数的特性
    public class MyOtherClass {...}
    

    3.预定义的保留的特性

    3.1 Obsolete特性

    可以使用Obsolete特性将程序结构标注为过期,并在代码编译时显示有用的警告信息。

    class Program
    {
        [Obsolete("Use new method!")]
        static void OldPrint()
        {
            Console.WriteLine("hello");
        }
        static void Main()
        {
            OldPrint();
            Console.ReadKey();
        }
    }
    

    即使OldPrint被标注为过期,Main方法还是会调用它, output

    hello
    

    但是在编译过程中,编译器生成警告信息 waring

    Warning	CS0618	'Program.OldPrint()' is obsolete: 'Use new method!'	ConsoleApp1	C:UserskylewDesktopConsoleApp1ConsoleApp1Program.cs	12	Active
    
    

    另外一个Obsolete特性的重载接受了bool类型的第二个参数,用来指定目标是否应该被标记为错误而不仅仅是警告。

    [Obsolete("Use new method!", true)] // 标记为错误
    

    3.2 Conditional特性

    Conditional特性允许包括或排斥特定方法的所有调用。

    #define DoTrace
    using System;
    using System.Diagnostics;
    
    class Program
    {
        [Conditional("DoTrace")]
        static void Print1()
        {
            Console.WriteLine("1111");
        }
        static void Print2()
        {
            Console.WriteLine("2222");
        }
        static void Main()
        {
            Print1();
            Print2();
            Console.ReadKey();
        }
    }
    

    output

    1111
    2222
    

    如果注释掉第一行来取消DoTrace的定义,
    output

    2222
    

    3.3 调用者信息特性

    调用者信息特性可以访问文件路径、代码行数、调用成员的名称等源代码信息。

    • 这三个特性为CallerFilePath、CallerLineNumber、CallerMenberName
    • 这些特性只能用于方法中的可选参数
    using System;
    using System.Runtime.CompilerServices;
    
    class Program
    {
        public static void MyTrace(string message,
            [CallerFilePath] string fileName = "",
            [CallerLineNumber] int lineNumber = 0,
            [CallerMemberName] string callingMenber = "")
        {
            Console.WriteLine($"File:{fileName}");
            Console.WriteLine($"Line:{lineNumber}");
            Console.WriteLine($"Called From:{callingMenber}");
            Console.WriteLine($"Message:{message}");
        }
        public static void Main()
        {
            MyTrace("simple message");
            Console.ReadKey();
        }
    }
    

    output

    File:C:UserskylewDesktopConsoleApp1ConsoleApp1Program.cs
    Line:19
    Called From:Main
    Message:simple message
    

    3.4 DebuggerStepThrough特性

    在单步调试时,希望调试器不进入某些方法,仅仅执行该方法,然后继续调试下一行。

    using System;
    using System.Diagnostics;
    
    class Program
    {
        [DebuggerStepThrough]
        public static int Method() // 单步调试时不进入方法体,直接执行该方法
        {
            int sum = 0;
            for (int i = 0; i < 10; i++)
                sum += i;
            return sum;
        }
        public static void Main()
        {
            Console.WriteLine("start");
            Console.WriteLine($"sum = {Method()}");
            Console.ReadKey();
        }
    }
    

    4.特性的其他内容

    4.1 多个特性

    [ Serializable ] 
    [ MyAttribute("simple class", "version 0.0.1") ] // 多层结构
    
    [ MyAttribute("simple class", "version 0.0.1"), Serializable ] // 逗号分隔
    

    4.2 其他类型的目标

    [ MyAttribute("simple class", "version 0.0.1") ] // 字段上的特性
    public int MyField;
    
    [ Obsolete ] // 方法上的特性
    [ MyAttribute("simple class", "version 0.0.1") ] 
    public void Print() {...}
    

    还可以显示的标注特性,从而将它用到特殊的目标结构,

    [ method: MyAttribute("simple class", "version 0.0.1") ] 
    [ return: MyAttribute("simple class", "version 0.0.1") ] 
    public void Print() {...}
    

    特性目标:

    eventfieldmethodparam
    method param property return
    type typevar assembly module

    4.3 全局特性

    assembly和module用来将特性设置在程序集或模块级别:

    • 程序集级别的特性必须放置在任何命名空间之外,并且通常放置在AssemblyInfo.cs文件中
    • AssemblyInfo.cs文件通常包含有关公司、产品以及版权信息的元数据
    [assembly: Assembly(MyTitle)]
    

    5.自定义特性

    5.1 声明自定义特性

    • 声明一个派生自System.Attribute的类
    • 特性名称以后缀Attribute结尾
    • 建议声明一个sealed的特性类
    public sealed class MyAttributeAttribute: System.Attribute // 使用时可简写为MyAttribute
    {...}
    

    由于特效持有目标的信息,所有特性类的公共成员只能是:

    • 字段
    • 属性
    • 构造函数

    5.2 使用特性的构造函数

    每一个特性至少必须有一个公共构造函数,若不声明构造函数,编译器会产生一个隐式、公共且无参的构造函数。

    public MyAttributeAttribute(string desc, string ver) 
    {
        Description = desc;
        VersionNumber = ver;
    }
    

    5.3 指定构造函数

    为目标应用特性时,实际上是在指定应该使用哪个构造函数。

    [MyAttribute("hello")] // 使用一个字符串的构造函数
    public int MyField;
    
    [MyAttribute("hello", "world")] // 使用两个字符串的构造函数
    public void MyMethod() {...}
    
    [MyAttribute] // 无参时可省略括号 
    

    5.4 构造函数中的位置参数和命名参数

    [MyAttribute("hello", Reviewer = "Kyle", Ver = "0.0.1")]
                位置参数             命名参数      命名参数
    
    public sealed class MyAttributeAttribute:System.Attribute
    {
        public string Description;
        public string Ver;
        public string Reviewer;
        public MyAttributeAttribute(string desc)
        {
            Description = desc;
        }
    }
    [MyAttribute("hello", Reviewer = "Kyle", Ver = "0.0.1")]
    class MyClass
    { ... }
    

    5.5 限制特性的使用

    使用AttributeUsage特性来限制特性使用在某个目标类型上。

    [AttributeUsage(AttributeTargets.Method)]
    public sealed class MyAttributeAttribute:System.Attribute
    { ... }
    

    AttributeUsage有三个重要的公共属性:

    名字意义默认值
    ValidOn 保存特性能应用到目标类型的列表。构造函数的第一个参数必须是AttributeTarget类型的枚举值  
    Inherited 一个布尔值,它指示特性是否会被装饰类型的派生类所继承 true
    AllowMultiple 一个指示目标是否被应用多个特性的示例的布尔值 false
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)]
    public sealed class MyAttributeAttribute:System.Attribute
    { ... }
    

    AttributeTarget枚举成员:

    AllAssemblyClassConstructor
    Delegate Enum Event Field
    GenericParameter Interface Method Module
    Parameter Property RetrunValue Struct

    一个AttributeUsage的具体用法:

    [AttributeUsage(AttributeTargets.Class, // 只能应用到类上
                    Inherited = false, // 不会被应用它的派生类所继承
                    AllowMultiple = false)] // 不能有多个MyAttribute实例应用到同一目标上
    public sealed class MyAttributeAttribute:System.Attribute
    { ... }
    

    6.访问特性

    6.1 使用IsDefined方法

    使用Type对象的IsDefined方法来检测某个特性是否应用到了某个类上。

    [AttributeUsage(AttributeTargets.Class,
        Inherited = false,
        AllowMultiple = false)]
    public sealed class MyAttributeAttribute:System.Attribute
    {
        public string Description;
        public string Ver;
        public string Reviewer;
        public MyAttributeAttribute(string desc)
        {
            Description = desc;
        }
    }
    [MyAttribute("hello", Reviewer = "Kyle", Ver = "0.0.1")]
    class MyClass { }
    class Program
    {
        static void Main()
        {
            MyClass mc = new MyClass();
            Type t = mc.GetType();
            bool isDefined = t.IsDefined(typeof(MyAttributeAttribute), false);
            if (isDefined)
                Console.WriteLine($"MyAttribute is applied to type {t.Name}");
            Console.ReadKey();
        }
    }
    

    output

    MyAttribute is applied to type MyClass
    

    6.2 使用GetCustomAttributes方法

    GetCustomAttributes方法返回应用到结构的特性的数组。

    • 实际返回的对象时object的数组,因此要强制转换为相应的特性类型
    • 布尔参数指定是否搜索继承树来检查特性
      object[] AttArr = t.GetCustomAttributes(false);
    • 调用GetCustomAttributes方法后,每一个与目标相关联的特性的实例就会被创建
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class MyAttributeAttribute:System.Attribute
    {
        public string Description;
        public string Ver;
        public string Reviewer;
        public MyAttributeAttribute(string desc,string ver)
        {
            Description = desc;
            Ver = ver;
        }
    }
    [MyAttribute("hello", "0.0.1")]
    class MyClass { }
    class Program
    {
        static void Main()
        {
            Type t = typeof(MyClass);
            object[] AttArr = t.GetCustomAttributes(false);
            foreach (Attribute a in AttArr)
            {
                MyAttributeAttribute attr = a as MyAttributeAttribute;
                if (null != attr)
                {
                    Console.WriteLine($"Description: {attr.Description}");
                    Console.WriteLine($"Version: {attr.Ver}");
                    Console.WriteLine($"Reviewer: {attr.Reviewer}");
                }
            }
            Console.ReadKey();
        }
    }
    

    output

    Description: hello
    Version: 0.0.1
    Reviewer:
  • 相关阅读:
    PHP后门新玩法:一款猥琐的PHP后门分析
    中国菜刀批量导出数据
    渗透测试:反弹与转发小结
    怎样用Java自制优秀的图片验证码?这样!
    6条 Tips 为你照亮 GitHub 寻宝之路
    如何搭建一个“不可告人的”私人专属网盘?教程拿去
    6个炫酷又好用的 Python 工具,个个都很奔放呀
    20个Java练手项目,献给嗜学如狂的人
    如何自己动手写一个搜索引擎?我是一份害羞的教程🙈
    GitHub上个最有意思的项目合集(技术清单系列)
  • 原文地址:https://www.cnblogs.com/jizhiqiliao/p/10649169.html
Copyright © 2011-2022 走看看