特性是什么?

特性本质是个类

特性是一种允许我们向程序的程序集添加元数据的语言结构

特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集中

它可以放置在几乎所有的声明中(类、变量、函数等等申明)

自定义特性

  1. 特性就是一个类,这个类必须继承 Attribute

  1. 类的名称以Attribute为后缀,这样能够表示这个类就是一个特性,当使用特性时,可以省略Attribute这个后缀。

public class MyCustomAttribute : Attribute
{
    public string info;
    public MyCustomAttribute(string info)
    {
        this.info = info;
    }
}
C#

特性的使用

语法:[特性名(参数列表)]

[MyCustom("类可以使用特性")]
public class Test
{
    [MyCustom("成员变量可以使用特性")]
    public int value;

    [MyCustom("成员方法可以使用特性")]
    public void TestFun([MyCustom("参数也可以使用特性")] int value)
    {
        this.value = value;
    }
}
C#

通过反射去使用特性

public class Program
{
    public void Main()
    {
        // 通过反射使用特性
        Test test = new Test();
        Type t = test.GetType();
        
        // 1. 判断是否用了某个特性
        // 参数一:特性的类型
        // 参数二:代表是否需要判断继承链
        if(t.IsDefined(typeof(MyCustomAttribute), false))
        {
            Debug.Log("该类型应用了MyCustom特性");
        }

        // 2. 获得Type元数据中的所有特性
        object[] array = t.GetCustomAttributes(true);
        for(int i = 0; i < array.Length; i++)
        {
            if (array[i] is MyCustomAttribute)
            {
                Debug.Log((array[i] as MyCustomAttribute).info);
            }
        }

    }
}
C#

限制自定义特性的使用范围

通过为特性类 加特性 限制其使用范围

// 参数一:AttributeTargets —— 特性能够用在哪些地方
// AttributeTargets.Class | AttributeTargets.Struct 要么应用于Class,要么应用于Struct。不能应用于其他
// 参数二:AllowMultiple —— 是否允许多个特性实例用在同一个目标上
// 参数三:Inherited —— 特性是否能被派生类和重写成员继承
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple =true, Inherited = false)]
public class MyCustom2Attribute : Attribute
{

}
Kotlin

系统自带特性

1. 过时特性

//参数一:调用过时方法时 提示的内容
//参数二:true-使用该方法时会报错  false-使用该方法时直接警告
[Obsolete("这是一个废弃的方法,请使用NewMethod方法", false)]
public void OldMethod()
{

}
C#

2. 调用者信息特性

//CallerFilePath特性:哪个文件调用?
//CallerLineNumber特性:哪一行调用?
//CallerMemberName特性:哪个函数调用?
//需要引用命名空间 using System.Runtime.CompilerServices;
public void SpeakCaller(string str, [CallerFilePath] string fileName = "",
        [CallerLineNumber] int line = 0, [CallerMemberName] string target = "")
{
    Console.WriteLine(str);
    Console.WriteLine(fileName);
    Console.WriteLine(line);
    Console.WriteLine(target);
}
C#

3. 条件编译特性

#define UNITY6
public class Program
{
    [Conditional("UNITY6")]
    static void Fun()
    {
        Console.WriteLine("Fun执行");
    }
}
C#

4. 外部dll包函数特性

用来标记非.Net(C#)的函数,表明该函数在一个外部的DLL中定义。

一般用来调用 C或者C++的Dll包写好的方法

需要引用命名空间 using System.Runtime.InteropServices

[DllImport("Test.dll")]
public static extern int Add(int a, int b);
C#