c#中的特性Atrtribute和反射

特性(Attribute)

特性概述

特性即 Attribute ,网页翻译也叫属性。他在c#代码中是一个类,名称通常为 xxxAttribute 。用于对程序片段(方法、类、属性)等附加一些额外信息,这些信息可以通过反射被获取,以便做一些逻辑处理。通常与筛选器、AOP等结合使用。

官方文档:利用特性扩展元数据 | Microsoft Learn

Attribute与注释的区别

注释是对程序源代码的一种说明,主要目的是给人看的,在程序被编译的时候会被编译器所丢弃,因此,它丝毫不会影响到程序的执行。

Attribute是程序代码的一部分,它不但不会被编译器丢弃,而且还会被编译器编译进程序集(Assembly)的元数据(Metadata)里。.NET中元数据是指程序集中的命名空间、类、方法、属性等信息。在程序运行的时候,随时可以通过反射(Reflection)从元数据中提取出这些附加信息,并以之决策程序的运行。

如何自定义特性

Attribute 类

自定义特性即自定义一个继承自 System.Attribute 的类,并且类名要以Attribute结尾,安全起见,建议对类用Sealed修饰。

当我们为目标(类|方法|属性等)应用特性时,其实是在指定应该是用哪个构造函数来创建特性的实例。列在特性中的参数其实就是其构造函数的参数。如果应用的特性的构造函数没参数,可以省略括号。

使用形式上即:[特性名(参数列表)]就是有点像调用构造函数那样,只不过两边加了中括号,而且无参时可以只要特性名。特性名用类名,或者类名去掉Attribute的部分。形式如下:

//加入已经预先定义好了一个ConditionalAttribute特性。
//长记法
[ConditionalAttribute("Li")]
[ConditionalAttribute("NoBug")]
public static void Func()
{Console.WriteLine("Created by Li, NoBug"); }
//短记法
[Conditional("Li")]
[Conditional("NoBug")]
public static void Func()
{Console.WriteLine("Created by Li, NoBug"); }
//换序
[Conditional("NoBug")]
[Conditional("Li")]
public static void Func()
{Console.WriteLine("Created by Li, NoBug"); }
//单括号叠加
[Conditional("NoBug"),Conditional("Li")]
public static void Func()
{Console.WriteLine("Created by Li, NoBug"); }

AttributeUsage 类

该特性在自定义特性(类)时使用,用于限制自定义特性的目标类型(即可以对谁使用)。其有三个重要属性:

  • ValidOn:规定自定义特性可对谁使用。用AttributeTarget枚举类型赋值。

  • Inherited:指示特性是否会应用到被装饰类型的子类。Bool类型;

  • AllowMutiple:指示目标是否会被应用多个特性的实例。Bool类型,默认false;

该特性有一个重要的构造函数,接受单个AttibuteTarget枚举类型位置参数,用此参数设置ValidOn字段。

获取一个类中有哪些特性,用到Type类的两个方法:

IsDefined和GetCustomAttributes。前者返回bool型,后者返回object [ ] .

具体如何自定义特性,参考:

C# 特性(Attribute) - 智者见智 - 博客园 (cnblogs.com)

编写自定义特性 | Microsoft Learn

一些.net预设的特性

ObsoleteAttribute

用来指定类的成员或方法已经过时,在程序使用这个成员的时候会给出提示,默认是编译警告。

关于还有哪些预设的特性,如果有哪位网友有相关文章推荐,或晓得官方文档介绍地址,还请评论里留言下,不胜感激。

特性相关概念或知识

  • 反射(Reflection)技术
  • 筛选器
  • AOP

反射(Reflection)技术

反射是什么

通常,反射用于动态获取对象的类型、属性和方法等信息,反射机制允许程序在执行过程中动态地添加各种功能。

c#中,通过 is 、 as 、typeof 这三个关键字可以在程序执行期间判定对象类型

is 运算符:判断两个类型或对象实例是否兼容

bool res= A is B;

A和B是某个类型或某个类型的实例。如果A是B的一个实例,或者A继承自B,则结果res为true,否则为false。通常 is 运算符检验两个类型是否可以转换。

as 运算符:不会抛异常的类型转换

var res= A as B;

A和B是某个类型或某个类型的实例。如果A是B的一个实例,或者A继承自B,则结果res为B类型的一个实例,否则为null。as 运算符在运行期间执行类型转换,并且能够使得类型转换失败不抛异常,而返回一个null值

typeof 方法:

var res= typeof (a) ;

a是某个类型的一个实例对象。typeof 可以返回与具体类型相关的System.Type对象,一旦获得给定类型的Type对象,就可以通过使用该对象(res)定义的各种属性,字段,方法来获取类型 (a) 的具体信息,比如 a 的属性,方法等。

反射的核心类:System.Type

程序在运行时,可以查看其它程序集或其本身的元数据 ,一个运行的程序查看本身的元数据或其它程序的元数据的行为叫反射。我们使用Type类来反射数据,要用到System.Reflection命名空间。

Type是抽象类,派生于System.Reflection.MemberInfo抽象类。在运行时,CLR创建从Type( Runtim Type )派生的类的实例,Type包含了类型信息。有关Type的重要事项:

a) 对于程序中用到的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象。

b) 程序中用到的每一个类型都会关联到独立的Type类的对象。

c) 不管创建的类型 有多少个实例,只有一个Type类型对象会关联到所有这些实例。

我们可以从Type对象获取需要了解的有关类型的几乎所有信息。

获取Type对象的两种方式

  • Type t = 类实例 . GetType ( ) ;

  • Type t = typeof ( 类实例名 );


更新于:2023-05-03

posted @   AI大胜  阅读(107)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示