C# 特性

1、特性

特性是一种允许我们向程序的程序集添加元数据的语言结构,用于保存程序结构信息的某种特殊类型的类

特性提供功能强大的方法以将声明信息与C#代码(类型、方法、属性等)相关联。

特性与程序实体关联后,即可在运行时使用反色和查询特性信息

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

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

即:特性本质是一个类,可以利用特性类为元数据添加额外信息,之后可以通过反射来获取这些额外信息

2、自定义特性

继承特性基类 Attribute

// 命名规则: 特性意义(例如:MyCustom)+Attribute
class MyCustomAttribute : Attribute {
    // 特性中的成员,一般根据需求来写
    public string info;

    public MyCustomAttribute(string info) {
        this.info = info;
    }

    public void TestFun() {
        Console.WriteLine("特性的方法");
    }
}

3、特性的使用

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

本质上就是在调用特性类的构造函数

写在类、函数、变量的上一行,表示它们具有该特性的信息。特性可以有多个,即使相同(看第4点,限制自定义特性的适用范围)。

// 后面的 Attribute 会被系统省略
[MyCustom("自定义特性,MyClass这个类是干嘛的")]
class MyClass {
    [MyCustom("这是一个变量")]
    public int value;

    [MyCustom("这是一个干嘛的函数")]
    public void TestFun([MyCustom("这是一个参数")]int v) {

    }
}

在使用时

MyClass mc = new MyClass();
Type t = typeof(MyClass);

// 判断是否使用了某个特性
// 参数一:特性的类型
// 参数二:搜索继承链,从父类中找是否存在这个特性(属性和事件忽略此参数)
if (t.IsDefined(typeof(MyCustomAttribute), false)) {
    Console.WriteLine("该类应用了MyCustom特性");
}

这里只会检测type关联的类是否存在特性,对于类中的成员是否存在特性不进行判断,需要单独获得成员的type

// 得到特性信息
object[] obj = t.GetCustomAttributes(true);
for(int i = 0; i < obj.Length; ++i) {
    if (obj[i] is MyCustomAttribute) {
        // 打印特性的信息
        Console.WriteLine((obj[i] as MyCustomAttribute).info);
        // 执行特性类中的方法
        (obj[i] as MyCustomAttribute).TestFun();
    }
}

4、限制自定义特性的适用范围

通过为特性类夹特性,限制其适用范围

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

} 

5、系统自带特性

(1)过时特性

[Obsolete]

用于提示用户使用的方法等成员已经过时,建议使用新方法

一般加在函数前的特性

class TestClass {
    // 参数一:调用过时方法时提示的内容
    // 参数二:true 使用该方法时会报错; false 使用该方法时警告
    [Obsolete("OldFunc方法已经过时,请使用Func方法", false)]
    public void OldFunc(string str) {

    }

    public void Func(string str) {

    }
}

(2)调用者信息特性

需要引用命名空间:using System.Runtime.CompilerServices;

哪个文件调用:[CallerFilePath]

哪一行调用:[CallerLineNumber]

哪个函数调用:[CallerMemberName]

一般作为函数参数特性

例如在某个类中有这样一个函数:

public void SpeakCaller(string str, [CallerFilePath]string fileName = "",
    [CallerLineNumber]int line = 0, [CallerMemberName]string target = "") {

}

那么在后面参数不传入的情况下,会自动补值,但是一定要是缺省参数的格式,否则参数必须要自己传入,特性便失去了意义。

配合try...catch...可以帮助查错

(3)条件编译特性

[Conditional]

它会和预处理指令#define配合使用

需要引用命名空间 using System.Diagnostics;

主要可以用在一些调试代码上,有时想执行有时不想执行的代码

[Conditional("Fun")]
static void Fun() {
    Console.WriteLine("Fun函数");
}

在这里如果没有#define Fun,那么调用Fun()是没有效果的。注意!!define命令必须放在最前面(using前面)

(4)外部Dll包函数特性

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

[DllImport("dll包的文件名/路径")]

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

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

[DllImport("Test.dll")]
public static extern int Add(int a, int b); // Test.dll包中有这样一个方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值