【Unity|C#】基础篇(13)——特性(Attribute)

【学习资料】

  《C#图解教程》(第24章)https://www.cnblogs.com/moonache/p/7687551.html
  电子书下载:https://pan.baidu.com/s/1mhOmBG0

  • 参考文章 

    C# 特性(Attribute)(建议看一看嗷)https://www.cnblogs.com/zhaoyl9/p/12027938.html

 

【内容】 

    • 特性的用途
    • 特性与注释的区别
    • 内置特性
      • Obsolete(废弃特性)
      • Conditional(条件编译特性)
      • 调试者信息特性(CallerFilePath、CallerLineNumber、CallerMemberName)
      • DebuggerStepThrough(跳过调试特性)
      • 更多内置特性
    • 全局特性
    • 自定义特性
      • 命名规范
      • 使用反射访问特性
    • 限制特性的使用(AttributeUsage)

 


 【笔记】

  • 用途
    • 允许我们向程序集的元数据中的成员上 声明一些特殊的信息(附加信息),是用于保存程序结构信息的 某种特殊类型的类(特性也是类)
    • 主要消费者为:编译器、CLR(反射)、浏览器(编辑器里的dll对象信息查看器)
    • 特性的作用
      • 告诉编译器如何编译
      • 序列化
      • 程序的安全特征(如数据验证)
      • 防止即时编译器对程序代码进行优化从而代码容易调试
      • 等等
    • 注:在程序运行前,特性就已经存在了

 

  • 与注释的区别

    图片来源:https://www.cnblogs.com/zhaoyl9/p/12027938.html

 

  • 内置特性 
    • Obsolete(废弃特性)
      • 语法: Obsolete(string message, bool error=false) ,其中error传入true,则编译器显示报错
      • 定义在 程序结构(类、结构、成员等等)
      • 将其标记为过期;在编译器的错误列表中,会显示警告、或错误
      • [Obsolete("func1 已过时")]
        public void Func1() { }
        [Obsolete("func2 已废弃", true)]
        public void Func2() { }
        
        void Start()
        {
            Func1();
            Func2();
        }
      • 查看错误列表
    • Conditional(条件编译特性)
      • 语法: Conditional(string conditionString) ,参数为 编译符号 名称
      • 定义在 方法
      • 如果编译符号未定义,那么编译器会移除该方法的所有调用
      • #define HELLO // 定义符号 HELLO 
        using UnityEngine;
        
        public class LearnCS : MonoBehaviour
        {
            [System.Diagnostics.Conditional("HELLO")]
            public void Func1() { Debug.Log("Func1"); }
            [System.Diagnostics.Conditional("WORLD")]
            public void Func2() { Debug.Log("Func2"); }
        
            void Start()
            {
                Func1();
                Func2(); // 编译时会被移除
            }
        }
      • 输出结果:只输出 Fun1
    • 调试者信息特性(CallerFilePath、CallerLineNumber、CallerMemberName)
      • 定义在 方法参数
      • 编译器会自动给参数赋值:调用方法的文件路径、调用方法的行号、调用方法的方法名
      • public static void MyTrace(string message,
                                [CallerFilePath] string fileName = "",
                                [CallerLineNumber] int lineNumber = 0,
                                [CallerMemberName] string callingMember = "")
        {
            Debug.Log(string.Format("File:         {0}", fileName));
            Debug.Log(string.Format("Line:         {0}", lineNumber));
            Debug.Log(string.Format("Called From:  {0}", callingMember));
            Debug.Log(string.Format("Message:      {0}", message));
        }
      • 输出结果
    • DebuggerStepThrough(跳过调试特性)
      • 定义在 类、结构、构造函数、方法
      • 在单步调试时(Step Into),不会进入方法体内,而是直接跳过
      • 例1:断点在13行,进行单步调试(Step Into,VS的快捷键为F11),可以进入Func1方法体内
      • 例2: 断点在13行,进行单步调试(Step Info,VS快捷键为F11),直接会跳到14行

    • 更多内置特性

 

  • 全局特性

     传送门:https://www.cnblogs.com/liqingwen/p/5944391.html

 

  • 自定义特性
    • 继承基类: System.Attribute 
    • 命名规范
      • 以 Attribute 结尾,使用时不需要加这个后缀
      • 如:MyAttributeAttribute,使用为 [MyAttribute]
    • 像类一样声明一个特性,并通过反射获取特性的属性
    • using UnityEngine;
      using System;
      
      public class MyAttributeAttribute : System.Attribute
      {
          public string name { get; } // 名字
          public string date { get; } // 日期
          public MyAttributeAttribute(string name, string date)
          {
              this.name = name;
              this.date = date;
          }
      }
      
      public class LearnCS : MonoBehaviour
      {
          [Obsolete("MyTest 已过时")]
          [MyAttribute("heihei", "2020-2-2")]
          public class MyTest
          { }
      
          void Start()
          {
              // 通过Type的 GetCustomAttributes
              Type t = typeof(MyTest);
              var myAttribute11 = t.GetCustomAttributes(true);
              var myAttribute12 = t.GetCustomAttributes(typeof(MyAttributeAttribute), true);
              
              // 通过Attribute的 GetCustomAttribute
              var myAttribute21 = Attribute.GetCustomAttribute(typeof(MyTest), typeof(MyAttributeAttribute));
      
              // 通过Attribute的 GetCustomAttributes
              var myAttribute31 = Attribute.GetCustomAttributes(typeof(MyTest));
              var myAttribute32 = Attribute.GetCustomAttributes(typeof(MyTest), typeof(MyAttributeAttribute));
      
              // 
              foreach(var att in myAttribute11)
              {
                  //将特性对象转化为动物特性对象
                  MyAttributeAttribute myAtt = att as MyAttributeAttribute;
                  if (myAtt != null)
                  {
                      Debug.Log("name=" + myAtt.name + " , date=" + myAtt.date);
                  }
              }
              Debug.Log("End");
          }
      }
    • 运行结果

 

  • 限制特性的使用(AttributeUsage)
    • 定义在特性类型前,用来限制特性的使用目标
    • 例如:只允许类使用,属性方法都不能使用该特性
    • [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited =true)]
      public class MyAttributeAttribute : System.Attribute
      {
          public string name { get; } // 名字
          public string date { get; } // 日期
          public MyAttributeAttribute(string name, string date)
          {
              this.name = name;
              this.date = date;
          }
      }
    • 公共属性

    • 构造函数的 AttributeTargets枚举限制

 

posted @ 2020-02-08 19:36  夏天的风92  阅读(1211)  评论(0)    收藏  举报