面试 | .NET基础知识快速通关(11)
bigegpt 2024-10-13 01:17 5 浏览
本文为第十一篇,我们会对.NET的特性相关考点进行基础复习,全文会以Q/A的形式展现,即以面试题的形式来描述。
开头
特性机制可以帮助程序员以申明的方式进行编程,而不再需要考虑实现的细节。
1 能说说什么是特性吗?
特性是一种有别于普通命令式编程的编程方式,通常被称为申明式编程方式。所谓申明式编程方式就是指程序员只需要申明某个模块会有怎样的特性,而无需关心如何去实现。
下面的代码就是特性在ASP.NET MVC中的基本使用方式:
[HttpPost]
public ActionResult Add(UserInfo userInfo)
{
if (ModelState.IsValid)
{
// To do fun
}
return RedirectToAction("Index");
}
当一个特性被添加到某个元素上时,该元素就被认为具有了这个特性所代表的功能或性质,例如上述代码中Add方法在添加了HttpPost特性之后,就被认为只有遇到以POST的方式请求该方法时才会被执行。
Note:特性在被编译器编译时,和传统的命令式代码不同,它会被以二进制数据的方式写入模块文件的元数据之中,而在运行时再被解读使用。特性也是经常被反射机制应用的元素,因为它本身是以元数据的形式存放的。
2 .NET中如何自定义一个特性?
除了直接使用.NET中内建的所有特性之外,我们也可以建立自己的特性来实现业务逻辑。在上面反射工厂的实现中就使用到了自定义特性。具体来说,定义一个特性的本质就是定义一个继承自System.Attribute类的类型,这样的类型就被编译器认为是一个特性类型。
下面我们看看如何自定义一个特性并使用该特性:
① 定义一个继承自System.Attribute的类型MyCustomAttribute
/// <summary>
/// 一个自定义特性MyCustomAttribute
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
{
private string className;
public MyCustomAttribute(string className)
{
this.className = className;
}
// 一个只读属性ClassName
public string ClassName
{
get
{
return className;
}
}
}
一个继承自System.Attribute的类型,就是一个自定义特性,并且可以将其添加到适合的元素之上。特性将会被写入到元数据之中,所以特性的使用基本都是基于反射机制。
② 在入口方法中使用MyCustomAttribute
[MyCustom("UseMyCustomAttribute")]
public class UseMyCustomAttribute
{
public static void Main(string[] args)
{
Type t = typeof(UseMyCustomAttribute);
// 通过GetCustomAttributes方法得到自定义特性
object[] attrs = t.GetCustomAttributes(false);
MyCustomAttribute att = attrs[0] as MyCustomAttribute;
Console.WriteLine(att.ClassName);
Console.ReadKey();
}
}
关于自定义特性,有几点需要注意:
- 虽然没有强制规定,但按照约定最好特性类型的名字都以Attribute结尾;
- 在C#中为了方便起见,使用特性时都可以省略特性名字后的Attribute,例如上述代码中的[MyCustom("UseMyCustomAttribute")]代替了[MyCustomAttribute("UseMyCustomAttribute")];
- 特性类型自身也可以添加其他的特性;
3 .NET中特性可以在哪些元素上使用?
特性可以被用来使用到某个元素之上,这个元素可以是字段,也可以是类型。对于类、结构等元素,特性的使用可以添加在其定义的上方,而对于程序集、模块等元素的特性来说,则需要显式地告诉编译器这些特性的作用目标。
例如,在C#中,通过目标关键字加冒号来告诉编译器的使用目标:
// 应用在程序集
[assembly: MyCustomAttribute]
// 应用在模块
[module: MyCustomAttribute]
// 应用在类型
[type: MyCustomAttribute]
我们在设计自定义特性时,往往都具有明确的针对性,例如该特性只针对类型、接口或者程序集,限制特性的使用目标可以有效地传递设计者的意图,并且可以避免不必要的错误使用特性而导致的元数据膨胀。
AttributeUsage特性就是用来限制特性使用目标元素的,它接受一个AttributeTargets的枚举对象作为输入来告诉AttributeUsage西望望对特性做何种限定。例如上面展示的一个自定义特性,使用了限制范围:
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
{
.....
}
Note:一般情况下,自定义特性都会被限制适用范围,我们也应该养成这样的习惯,为自己设计的特性加上AttributeUsage特性,很少会出现使用在所有元素上的特性。即便是可以使用在所有元素上,也应该显式地申明[AttributeUsage(AttributesTargets.All)]来提高代码的可读性。
4 如何获知一个元素是否申明了某个特性?
在.NET中提供了很多的方法来查询一个元素是否申明了某个特性,每个方法都有不同的使用场合,但是万变不离其宗,都是基于反射机制来实现的。
首先,还是以上面的MyCustomAttribute特性为例,新建一个入口方法类Program:
/// <summary>
/// 一个自定义特性MyCustomAttribute
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
{
private string className;
public MyCustomAttribute(string className)
{
this.className = className;
}
// 一个只读属性ClassName
public string ClassName
{
get
{
return className;
}
}
}
[MyCustom("Program")]
class Program
{
static void Main(string[] args)
{
Type attributeType = typeof(MyCustomAttribute);
Type thisClass = typeof(Program);
}
}
(1)System.Attribute.IsDefined方法
// 使用IsDefined方法
bool isDefined = Attribute.IsDefined(thisClass, attributeType);
Console.WriteLine("Program类是否申明了MyCustomAttribute特性:{0}", isDefined);
(2)System.Attribute.GetCustomerAttribute方法
// 使用Attribute.GetCustomAttribute方法
Attribute att = Attribute.GetCustomAttribute(thisClass, attributeType);
if (att != null)
{
Console.WriteLine("Program类申明了MyCustomAttribute特性,特性的成员为:{0}", (att as MyCustomAttribute).ClassName);
}
(3)System.Attribute.GetCustomerAttributes方法
// 使用Attribute.GetCustomAttributes方法
Attribute[] atts = Attribute.GetCustomAttributes(thisClass, attributeType);
if (atts.Length > 0)
{
Console.WriteLine("Program类申明了MyCustomAttribute特性,特性名称为:{0}", ((MyCustomAttribute)atts[0]).ClassName);
}
(4)System.Reflection.CustomAttributeData类型
// 使用CustomAttributeData.GetCustomAttributes方法
IList<CustomAttributeData> attList = CustomAttributeData.GetCustomAttributes(thisClass);
if (attList.Count > 0)
{
Console.WriteLine("Program类申明了MyCustomAttribute特性");
// 注意:这里可以对特性进行分析,但无法得到其实例
CustomAttributeData attData = attList[0];
Console.WriteLine("该特性的名字是:{0}", attData.Constructor.DeclaringType.Name);
Console.WriteLine("该特性的构造方法有{0}个参数", attData.ConstructorArguments.Count);
}
下图是四种方式的执行结果:
这四种方法各有其特点,但都可以实现查询某个元素是否申明了某个特性的这一功能。其中,可以看到第(4)种方式,可以对特性进行分析,但无法得到其实例。另外,自定义特性被申明为sealed表示不可继承,这是因为在特性被检查时,无法分别制定特性和其派生特性,这一点需要我们注意。
5 一个元素是否可以重复声明同一个特性?
对于有些业务逻辑来说,一个特性反复地申明在同一个元素上是没有必要的,但同时对于另一些逻辑来说,又非常有必要对同一元素多次申明同一特性。很幸运,.NET的特性机制完美支持了这一类业务需求。
当一个特性申明了AttributeUsage特性并且显式地将AllowMultiple属性设置为true时,该特性就可以在同一元素上多次申明,否则的话编译器将报错。
例如下面一段代码,类型Program多次申明了MyCustomAttribute特性:
[MyCustom("Class1")]
[MyCustom("Class2")]
[MyCustom("Class3")]
public class Program
{
public static void Main(string[] args)
{
}
}
/// <summary>
/// 一个自定义特性MyCustomAttribute
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
private string className;
public MyCustomAttribute(string className)
{
this.className = className;
}
// 一个只读属性ClassName
public string ClassName
{
get
{
return className;
}
}
}
通常情况下,重复申明同一特性往往会传入不同的参数。
此外,如果不显式地设置AllowMultiple属性时多次申明同一特性会如何呢?
在这种情况下,编译器将会认为自定义特性不能多次申明在同一元素上,会出现以下的编译错误:
总结
本文总结复习了.NET的特性(Attribute)相关的重要知识点,希望能对你理解特性有所帮助。
参考资料(全是经典)
朱毅,《进入IT企业必读的200个.NET面试题》
张子阳,《.NET之美:.NET关键技术深入解析》
王涛,《你必须知道的.NET(第二版)》
相关推荐
- 或者这些Joplin插件也可以帮助你的笔记应用再一次强大
-
写在前面距离上次分享《搭建私有全平台多端同步笔记,群晖NAS自建JoplinServer服务》已过去一段时间,大家是否开始使用起来了呢?如果你和我一样已经使用过Joplin有一段时间了,那或许你也会...
- Three.JS教程4 threejs中的辅助类
-
一、辅助类简介Three.js提供了一些辅助类(Helpers)以帮助我们更容易地调试、可视化场景中的元素。ArrowHelepr:创建箭头辅助器;AxisHelper:创建坐标轴辅助器;BoxH...
- 第2章 还记得点、线、面吗(二)(第二章还能敲钟吗)
-
glbgltf模型(webvrmodel)-gltf模型下载定制,glb模型下载定制,三维项目电商网站在线三维展示,usdz格式,vr模型网,网页VR模型下载,三维模型下载,webgl网页模型下载我...
- 如何检查Linux系统硬件信息?从CPU到显卡,一网打尽!
-
你可能会问:“我为什么要关心硬件信息?”答案很简单:硬件是Linux系统的根基,了解它可以帮你解决很多实际问题。比如:性能调优:知道CPU核心数和内存大小,才能更好地调整程序运行参数。故障排查:系统卡...
- SpriteJS:图形库造轮子的那些事儿
-
从2017年到2020年,我花了大约4年的时间,从零到一,实现了一个可切换WebGL和Canvas2D渲染的,跨平台支持浏览器、SSR、小程序,基于DOM结构和支持响应式的,高...
- 平时积累的FPGA知识点(6)(fpga经典应用100例)
-
平时在FPGA群聊等积累的FPGA知识点,第六期:1万兆网接口,发三十万包,会出现掉几包的情况,为什么?原因:没做时钟约束,万兆网接口的实现,本质上都是高速serdes,用IP的话,IP会自带约束。...
- 芯片逻辑调度框架设计 都需要那些那些软件工具
-
设计芯片逻辑调度框架通常需要使用以下软件工具:1.逻辑设计工具:例如Vivado、Quartus、SynopsysDesignCompiler等,用于设计和实现逻辑电路。2.仿真工具:例如Mo...
- ZYNQ与DSP之间EMIF16通信(正点原子领航者zynq之fpga开发指南v3)
-
本文主要介绍说明XQ6657Z35-EVM高速数据处理评估板ZYNQ与DSP之间EMIF16通信的功能、使用步骤以及各个例程的运行效果。[基于TIKeyStone架构C6000系列TMS320C6...
- 好课推荐:从零开始大战FPGA(从零开始的冒险4399)
-
从零开始大战FPGA引子:本课程为“从零开始大战FPGA”系列课程的基础篇。课程通俗易懂、逻辑性强、示例丰富,课程中尤其强调在设计过程中对“时序”和“逻辑”的把控,以及硬件描述语言与硬件电路相对应的“...
- 业界第一个真正意义上开源100 Gbps NIC Corundum介绍
-
来源:内容由「网络交换FPGA」编译自「FCCM2020」,谢谢。FCCM2020在5月4日开始线上举行,对外免费。我们有幸聆听了其中一个有关100G开源NIC的介绍,我们对该文章进行了翻译,并对其中...
- 高层次综合:解锁FPGA广阔应用的最后一块拼图
-
我们为什么需要高层次综合高层次综合(High-levelSynthesis)简称HLS,指的是将高层次语言描述的逻辑结构,自动转换成低抽象级语言描述的电路模型的过程。所谓的高层次语言,包括C、C++...
- Xilinx文档编号及其内容索引(部分)
-
Xilinx文档的数量非常多。即使全职从事FPGA相关工作,没有几年时间不可能对器件特性、应用、注意事项等等有较为全面的了解。本文记录了我自使用Xilinx系列FPGA以来或精读、或翻阅、或查询过的文...
- Xilinx Vivado联合Modelsim软件仿真
-
引言:Xilinx公司Vivado开发软件自带仿真工具,可以实现一般性能的FPGA软件仿真测试,其测试执行效率以及性能都不如第三方专用仿真软件Modelsim强。本文我们介绍下如何进行Vivado20...
- 体育动画直播是怎么做出来的?从数据到虚拟赛场的科技魔法!
-
你是否见过这样的比赛直播?没有真实球员,却能看梅西带球突破?足球比赛变成动画版,但数据100%真实?电竞比赛用虚拟形象直播,选手操作实时同步?这就是体育动画直播——一种融合实时数据、游戏引擎和AI的...
- Dialogue between CPC and political parties of neighboring countries held in Beijing
-
BEIJING,May26(Xinhua)--TheCommunistPartyofChina(CPC)inDialoguewithPoliticalPartiesof...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)