C#基础知识学习 之 ☀️ 特性(Attribute) 的含义和用法

简介: C# 特性🔥(Attribute)什么是特性🙏特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。

C# 特性🔥(Attribute)

什么是特性🙏

特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。

特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。


特性作用🎅

用以将元数据或声明信息与代码(程 序集、类型、⽅方法、属性等)相关联


特性描述🎄

特性可向程序中添加元数据

可以将一个或多个特性应用到整个程序集,模块或较小的程序元素(如类和属性)—一个程序元素可以添加多个特性

特性可以与⽅方法和属性相同的⽅方式接受参数—特性可以接受参数

程序可以使用反射检查自己的元数据或其他程序内的元数据

特性(元数据)是在编译之后就定义好的

元数据🎁(Meta Data)

描述:元数据是一种⼆进制信息,⽤用以对存储在公共语⾔言运⾏行行库可移植 可执⾏文件 (PE) 文件或存储在内存中的程序进行描述。将您的代

码编译为 PE 文件时,便便会将元数据插入到该文件的一部分中,而 将代码转换为 Microsoft 中间语言 (MSIL)

并将其插⼊入到该文件的 另一部分中。在模块或程序集中定义和引用的每个类型和成员都

将在元数据中进行说明。当执⾏代码时,运⾏库将元数据加载到内存中,并引用它来发现有关代码的类、成员、继承等信息。


image.png


预定义特性💬

AttributeUsage🎉

这个重要还难!

描述:预定义特性 AttributeUsage 主要⽤用于标示⾃自定义特性可以 应⽤用到哪些类型的程序元素上,这个信息由第⼀一个参数给出

实例:

[AttributeUsage(     
validon,//规定特性可被放置的语言元素,它是枚举器 AttributeTargets 的值的组合,默认值是 AttributeTargets.All   
AllowMultiple=allowmultiple, //如果为 true,则该特性可以在同一个元素多次使⽤用,默认值是 false(不不可多次使⽤用)    
Inherited=inherited//如果为 true,则该特性可被派生类继承,默认值是 false(不被继承) )]
1.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[AttributeUsage(AttributeTargets.Class,AllowMultiple =true,Inherited =true)]
public class AuthorAttribute : Attribute
{
    public string author;
    public string lastDate;//最后修改的日期
    public string LastDate
    {
        get
        {
            return lastDate;
        }
        set
        {
            lastDate = value;
        }
    }
    //当前特性的构造函数
    public AuthorAttribute(string author)
    {
        this.author = author;
    }
}
[AttributeUsage(AttributeTargets.Method,AllowMultiple =true)]
public class MyConditionAttribute : Attribute
{
    public MyConditionAttribute()
    { 
    }
}
[Author("Albert",lastDate = "1010.6.13"),Author("Tom",lastDate ="1010.10.13")]
public class UserAttributeDemo : MonoBehaviour
{
    public static  string log="abc";
    [MyCondition]
    public static void ShowLog()
    {
        Debug.Log(log);
    }
}
2.using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;
[AddComponentMenu("My/UsesAttributeObserver")]
[RequireComponent(typeof(Rigidbody),typeof(BoxCollider))]//组件依赖
public class UsesAttributeObserver : MonoBehaviour
{
    [Header("日志延迟时间")]
    [Range(0,1000)]
    public float  logelayTime=100;
    [SerializeField]//让私有字段也可以显示到监视器面板上
    private string name;
    [ColorUsage(false)]
    public Color col;
    private void Start()
    {
        InvokeMethodByAttribute(typeof(MyConditionAttribute),"ShowLog",true,true);
    }
    /// <summary>
    /// 执行某个方法依据某个特性
    /// </summary>
    /// <param name="methodClasstype">方法所在的类的类型</param>
    /// <param name="methodName">方法名</param>
    /// <param name="isStatic">是否静态</param>
    /// <param name="isPublic">是否公有</param>
    /// <param name="methodObj">成员方法所在对象</param>
    /// 
    private void InvokeMethodByAttribute(Type methodClasstype, string methodName,bool isStatic,bool isPublic,object methodObj=null)
    {
        BindingFlags staticFlags = isStatic ? BindingFlags.Static : BindingFlags.Instance;
        BindingFlags publicFlags = isPublic ? BindingFlags.Public  : BindingFlags.NonPublic;
        //获取到该方法
        MethodInfo info= methodClasstype.GetMethod(methodName, staticFlags | publicFlags);
        //获取MyConditionAttribute类型的特性
        object[] atts= info.GetCustomAttributes(typeof(MyConditionAttribute), false);
        if (atts.Length>0)
        {
            //info.Invoke();
        }
        Debug.Log("");
    }
    void PrintAttributeMsg()
    {
        //获取类型
        Type type = typeof(UserAttributeDemo);
        //得到该类型的不可继承的特性对象
        object[] atts= type.GetCustomAttributes(false);
        for (int i = 0; i < atts.Length; i++)
        {
            //判断
           if(atts[i]is AuthorAttribute)
            {
                //将特性转换为该类型
                AuthorAttribute authorObj = atts[i] as AuthorAttribute;
                Debug.Log(authorObj.author);
                Debug.Log(authorObj.lastDate);
            }
        }
    }
}

image.png

Conditional🎉

**就是类似于一个密钥,在方法前添加了[Conditional(“ZAY”)]特性后,使用时需要在最前边声明一个 #define ZAY 才能正常使用添加此特性的方法 **


描述:这个预定义特性标记了了⼀一个条件方法,其执行依赖于它顶的预处理标识符。 它会引起方法调⽤用的条件编译,取决于指定的值,比如 Debug 或 Trace。

[Conditional("ABC")]
1.using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
public class ConditionalDemo
{
    [Conditional("ZAY")]
    public static void ShowMe()
    {
        Debug.Log("Show Me!");
    }
}
public class HasConditionDemo : MonoBehaviour
{
    void Start()
    {
    }
}
2.
#define ZAY
using UnityEngine;
public class UseConditionalDemo : MonoBehaviour
{
    void Start()
    {
        ConditionalDemo.ShowMe();
    }
}

image.pngObsolote🎉

可以标记此方法已过时,也可以将方法设置为直接不可用

描述: 这个预定义特性标记了不应被使⽤用的程序实体。它可以让您通知编译器器丢弃某个特定的⽬目 标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保持类中的旧方法,您可以通过显示一个应该使⽤用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)。


示例:

[Obsolete]
[Obsolete("当前方法已过时,请使用新的方法")]
[Obsolete("过时了",false)]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class DemoFrame
{
    //[Obsolete]
    //[Obsolete("当前方法过时了,请使用NewDemoShowMe()替换他")]
    [Obsolete("当前方法过时了,请使用NewDemoShowMe()替换他",false)]
    public static void OldDemoShowMe()
     {
        Debug.Log("OldDemoShoeMe");
      }
    public static void NewDemoShowMe()
    {
      Debug.Log("NewDemoShowMe");
     }
}
public class UseObsoleteDemo : MonoBehaviour
{
    void Start()
    {
        DemoFrame.NewDemoShowMe();
    }
}

image.png自定义特性🎈

.Net 框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任何目标元素相关。

创建并使用自定义特性包含四个步骤:


声明自定义特性

构建自定义特性

在目标程序元素上应用自定义特性

通过反射访问特性

最后一个步骤包含编写一个简单的程序来读取元数据以便查找各种符号。元数据是用于描述其他数据的数据和信息。该程序应使用反射来在运行时访问特性


示例:

我这里是在Unity里做的测试,特性的用处也更多

//添加到菜单里
[AddComponentMenu("My/UsesAttributeObserver")]
//组件依赖
[RequireComponent(typeof(Rigidbody),typeof(BoxCollider))]
[SerializeField]//让私有字段也可以显示到监视器面板上
private string name;

下面是自定义特性的介绍图

image.png

特性(Attribute) 也常跟 反射(Reflection) 进行配合工作,下次再简单介绍一下反射的定义和用法


image.png

下面是MSDN中对特性用途的描述:

在 Web 服务中,使用 WebMethod 特性来标记方法,以指示该方法应该可通过 SOAP 协议进行调用。 有关更多信息,请参见WebMethodAttribute。


描述当与本机代码进行交互操作时如何封送方法参数。有关更多信息,请参见 MarshalAsAttribute。


描述类、方法和接口的 COM 属性。


使用 DllImportAttribute 类调用非托管代码。


在标题、版本、说明或商标方面描述您的程序集。


描述要持久性序列化类的哪些成员。


描述如何映射类成员和 XML 节点以便进行 XML 序列化。


描述方法的安全要求。


指定用于强制安全性的特性。


由实时 (JIT) 编译器控制优化,以便易于调试代码。


获取有关调用方的信息的方法。


image.png

image.png

相关文章
|
1月前
|
安全 C#
C# List基本用法
C# List基本用法
|
1月前
|
C#
C# Dev chartControl的用法
C# Dev chartControl的用法
|
2月前
|
Java 调度 C#
C#学习系列相关之多线程(一)----常用多线程方法总结
C#学习系列相关之多线程(一)----常用多线程方法总结
|
2月前
|
C#
C#学习相关系列之数据类型类的三大特性(二)
C#学习相关系列之数据类型类的三大特性(二)
|
2月前
|
C#
C#学习相关系列之yield和return的区别
C#学习相关系列之yield和return的区别
|
2月前
|
C#
C#学习系列相关之多线程(二)----Thread类介绍
C#学习系列相关之多线程(二)----Thread类介绍
|
2月前
|
C#
C#学习相关系列之数据类型类----嵌套类和嵌套方法(三)
C#学习相关系列之数据类型类----嵌套类和嵌套方法(三)
|
2月前
|
存储 C# 索引
C#学习相关系列之数据类型类的定义(一)
C#学习相关系列之数据类型类的定义(一)
|
21天前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
|
21天前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。