目录
一.特性概念
特性是一种允许我们向程序的程序集添加元数据的语言结构.
是用于保存程序结构信息的某种特殊类型的类.
特性提供功能强大的方法以将声明信息与C#代码(类型,方法,属性等)相关联.
特性与程序实体关联后,即可在运行时使用反射查询特性信息.
特性的目的是告诉编译器把程序结构的某族元数据嵌入程序集中.
它可以放置在几乎所有的声明中(类,变量,函数等等声明).
概括:
特性本质是个类.
我们可以利用特性类为元数据添加额外信息.
之后可以通过反射来获取这些额外信息.
二.自定义特性
继承特性基类 Attribute
//自定义特性的命名,通常后面加上Attribute
class MyCustomAttribute : Attribute
{
public string info;
public MyCustomAttribute(string info)
{
this.info = info;
}
}
三.特性的使用
基本语法: [特性名(参数列表)]
本质上就是在调用特性类的构造函数.
写在类,函数,变量上一行,表示它们具有该特性信息.
(接上一段代码)
[MyCustom("test")]
class MyClass
{
[MyCustom("一个函数")]
private int value;
[MyCustom("一个函数")]
public void TestFunc()
{
}
public void TestFunc([MyCustom("一个参数")] float f)
{
}
}
static void Main(string[] args)
{
MyClass mc = new MyClass();
Type t = mc.GetType();
//t = typeof(MyClass);
//t = Type.GetType("特性.MyClass");
//判断是否使用某种特性
//第一个参数填特性类,第二个参数表示是否查找其继承类是否使用了特性
//属性和事件忽略第二个参数
if(t.IsDefined(typeof(MyCustomAttribute),false))
{
//该方法只能判断MyClass类是否使用了该特性
//类里面的成员是否使用是判断不了的
Console.WriteLine("使用特性MyCustomAttribute");
}
//用反射来获取特性的额外信息
//参数表示是否查找继承类
//获取元数据所有特性
object[] array = t.GetCustomAttributes(true);
for(int i = 0;i< array.Length;i++)
{
if(array[i] is MyCustomAttribute)
{
Console.WriteLine((array[i] as MyCustomAttribute).info);
}
}
}
四.限制自定义特性的使用范围
为特性类再加上特性,就能限制其使用范围.
//参数一: 使用地方,这里表示类或结构体,用位或| 连接
//参数二: 使用允许多个特性实例用在同一个目标上(若为true,则一个目标可以重复加一样的特性)
//参数三: 特性是否能被派生类和重写成员继承,若否,则派生类不会有父类的一些特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true, Inherited = true)]
class MyCustom2Attribute : Attribute
{
}
五.系统自带特性
过时特性Obsolete.提示用户使用的成员已经过时,建议使用新的方法
class TestClass
{
//参数一: 调用方法时,提示的内容
//参数二: true-使用方法时报错,false-使用方法时警告
[Obsolete("该方法已过时",false)]
public void OldFunc()
{
}
public void NewFunc()
{
}
}
六.系统自带特性 - 调用者信息特性
获得是哪个文件调用: CallerFilePath
获得是哪一行调用: CallerLineNumber
获得是哪个函数调用: CallerMemberName
需要命名空间 System.Runtime.CompilerServices
public void TestFunc([CallerFilePath]string str = "")
{
Console.WriteLine(str);
//调用时,会输出调用的文件
//该特性自动为str赋了文件路径的默认值
//可以配合异常捕获来打印错误信息
}
七.系统自带特性 - 条件编译特性
条件编译特性: Conditional
配合#define使用
需要命名空间System.Diagnostics
主要用在一些有时想执行,有时不想执行的代码上
#define FUNC
[Conditional("FUNC")]
public void Func()
{
//该函数只有在FUNC被预处理定义了才会有用
//没有预处理,即使写了调用的位置,也不会调用
//没有预处理就没有编译它
}
static void Main(string[] args)
{
Func();
}
八.系统自带特性 - 外部dll包函数特性
DllImport
需要命名空间System.Runtime.InteropServices
用来标记非.Net(C#)的函数,表明该函数在一个外部dll中定义
一般用来调用C或C++的dll包
//[DllImport("dll包文件名或路径")]
[DllImport("Test.dll")]
public static extern void Function(int a);
//注意,必须要加static extern
//函数的参数返回值要和dll对应函数匹配
//相当与把dll函数映射到c#内
资料来源<唐老狮C#教程>