[C#] C# 知识回顾 - 特性 Attribute
C# 知识回顾 - 特性 Attribute
【博主】反骨仔 【原文地址】http://www.cnblogs.com/liqingwen/p/5911289.html
目录
一、特性简介
特性具有以下属性:
(1)特性可向程序中添加元数据。元数据是有关在程序中定义的类型的信息。所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员。可以添加自定义特性,以指定所需的任何附加信息。
(2)可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。
(3)特性可以与方法和属性相同的方式接受参数。
(4)程序可以使用反射检查自己的元数据或其他程序内的元数据。
二、使用特性
特性可以放置在几乎所有的声明中(但特定的特性可能限制在其上有效的声明类型)。在 C# 中,特性的指定方法为:将括在方括号中的特性名置于其应用到的实体的声明上方。它必须位于所应用于的元素的紧前面并与该元素在同一行。
[Serializable] //使用特性 SerializableAttribute
internal class MyClass
{
[DllImport("user32.dll")] //使用特性 DllImportAttribute
private static extern void Do(); #region 一个声明上可放置多个特性 private void MethodA([In][Out]ref double n) { }
private void MethodB([In, Out]ref double n) { } #endregion 一个声明上可放置多个特性 #region 某些特性对于给定实体可以指定多次 [Conditional("DEBUG"), Conditional("TEST1")]
private void TraceMethod() { } #endregion 某些特性对于给定实体可以指定多次
}
【注意】根据约定,所有特性名称都以单词“Attribute”结束,以便将它们与“.NET Framework”中的其他项区分。但是,在代码中使用特性时,不需要指定 attribute 后缀。
三、特性的参数
许多特性都有参数,而这些参数可以是定位参数、未命名参数或命名参数。任何定位参数都必须按特定顺序指定并且不能省略,而命名参数是可选的且可以按任意顺序指定。首先指定定位参数。例如,这三个特性是等效的:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
第一个参数(DLL 名称)是定位参数并且总是第一个出现,其他参数为命名参数。在这种情况下,两个命名参数均默认为 false,因此可将其省略。
四、特性的目标
特性的目标是应用该特性的实体。例如,特性可以应用于类、特定方法或整个程序集。默认情况下,特性应用于它后面的元素。但是,您也可以显式标识要将特性应用于方法还是它的参数或返回值。
若要显式标识特性目标,语法:
[target : attribute-list]
C# | 适用对象 |
assembly | 整个程序集 |
module | 当前程序集模块 |
field | 在类或结构中的字段 |
event | event |
method | 方法或 get 和 set 属性访问器 |
param | 方法参数或 set 属性访问器参数 |
property | 属性 |
return | 方法、属性索引器或 get 属性访问器的返回值 |
type | 结构、类、接口、枚举或委托 |
//示例:将特性应用于程序集和模块
[assembly: AssemblyTitle("assembly 4.6.1")]
[module: CLSCompliant(true)]
//示例:将特性应用于方法、方法参数和方法返回值 //默认:应用于方法
[SomeAttr]
int Method1() { return ; } //指定应用于方法
[method: SomeAttr]
int Method2() { return ; } //指定应用于返回值
[return: SomeAttr]
int Method3() { return ; }
五、特性的常见用途
以下列表包含特性的几个常见用途:
(1)在 Web 服务中,使用 WebMethod 特性来标记方法,以指示该方法应该可通过 SOAP 协议进行调用。
(2)描述当与本机代码进行交互操作时如何封送方法参数。有关更多信息。
(3)描述类、方法和接口的 COM 属性。
(4)使用 DllImportAttribute 类调用非托管代码。
(5)在标题、版本、说明或商标方面描述您的程序集。
(6)描述要持久性序列化类的哪些成员。
(7)描述如何映射类成员和 XML 节点以便进行 XML 序列化。
(8)描述方法的安全要求。
(9)指定用于强制安全性的特性。
(10)由实时 (JIT) 编译器控制优化,以便易于调试代码。
(11)获取有关调用方的信息的方法。
六、创建自定义的特性
通过定义一个特性类,可以创建您自己的自定义特性。该特性类直接或间接地从 Attribute 派生,有助于方便快捷地在元数据中标识特性定义。
/// <summary>
/// 角色特性
/// </summary>
/// RoleAttribute:特性的名称,继承 Attribute,为自定义特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class RoleAttribute : Attribute
{
private string _name; /// <summary>
/// 启用标识
/// </summary>
/// IsEnable:命名参数
public bool IsEnable { get; set; } /// <summary>
/// 构造函数
/// </summary>
/// <param name="name"></param>
/// name:定位参数
public RoleAttribute(string name)
{
_name = name;
}
}
[Role("Me", IsEnable = true)] //调用特性的方式
public class OurClass
{ }
构造函数的参数是自定义特性的定位参数,任何公共的读写字段或属性都是命名参数。【注意】 AttributeUsage 特性,在这里它使得 Role 特性仅在类和 struct 声明中有效。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] //AllowMultiple:该值指示能否为一个程序多次使用该特性
public class RoleAttribute : Attribute
{
//... ...
}
[Role("You")] //在同一个类上多次使用
[Role("Me", IsEnable = true)]
public class OurClass
{
//... ...
}
【注意】如果特性类包含一个属性,则该属性必须为读写属性。
七、使用反射访问特性
使用反射,可检索用自定义特性定义的信息。主要方法是 GetCustomAttributes,它返回对象数组,这些对象在运行时等效于源代码特性。
/// <summary>
/// 角色特性
/// </summary>
/// RoleAttribute:特性的名称,继承 Attribute,为自定义特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class RoleAttribute : Attribute
{
private string _name;
/// <summary>
/// 启用标识
/// </summary>
public bool IsEnable { get; set; } /// <summary>
/// 构造函数
/// </summary>
/// <param name="name"></param>
public RoleAttribute(string name)
{
_name = name;
}
}
RoleAttribute.cs
[Role("Me", IsEnable = true)]
public class OurClass
{
//... ...
}
概念上等效于
RoleAttribute role = new RoleAttribute("Me");
role.IsEnable = true;
但是,直到查询 OurClass 来获取特性后才会执行此代码。对 OurClass 调用 GetCustomAttributes 会导致按上述方式构造并初始化一个 RoleAttribute 对象。如果该类具有其他特性,则按相似的方式构造其他特性对象。然后 GetCustomAttributes 返回 RoleAttribute 对象和数组中的任何其他特性对象。之后就可以对此数组进行迭代,确定根据每个数组元素的类型所应用的特性,并从特性对象中提取信息。
这里,定义一个自定义特性,将其应用于若干实体并通过反射进行检索。
/// <summary>
/// 角色特性
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
public class RoleAttribute : Attribute
{
private readonly string _name; /// <summary>
/// 启用标识
/// </summary>
public bool IsEnable { get; set; } /// <summary>
/// 构造函数
/// </summary>
/// <param name="name"></param>
public RoleAttribute(string name)
{
_name = name;
} public string GetName()
{
return _name;
}
}
class MyClass1 { } [Role("Me")]
class MyClass2 { } [Role("Me"), Role("You", IsEnable = true)]
class MyClass3 { }
class Program
{
static void Main(string[] args)
{
Output(typeof(MyClass1));
Output(typeof(MyClass2));
Output(typeof(MyClass3)); Console.Read();
} /// <summary>
/// 输出
/// </summary>
/// <param name="t"></param>
static void Output(Type t)
{
Console.WriteLine($"Class: {t}"); var attributes = t.GetCustomAttributes();
foreach (var attribute in attributes)
{
var attr = attribute as RoleAttribute; if (attr == null)
{
return;
} Console.WriteLine($" Name: {attr.GetName()}, IsEnable: {attr.IsEnable}");
}
}
}
传送门
《只是想简单说下表达式树 - Expression Trees》
【参考】微软官方文档
[C#] C# 知识回顾 - 特性 Attribute的更多相关文章
- [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?
你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...
- [C#] C# 知识回顾 - 学会处理异常
学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...
- [C#] C# 知识回顾 - 学会使用异常
学会使用异常 在 C# 中,程序中在运行时出现的错误,会不断在程序中进行传播,这种机制称为“异常”. 异常通常由错误的代码引发,并由能够更正错误的代码进行 catch. 异常可由 .NET 的 CLR ...
- [C#] C# 知识回顾 - 异常介绍
异常介绍 我们平时在写程序时,无意中(或技术不够),而导致程序运行时出现意外(或异常),对于这个问题, C# 有专门的异常处理程序. 异常处理所涉及到的关键字有 try.catch 和 finally ...
- [.NET] C# 知识回顾 - Event 事件
C# 知识回顾 - Event 事件 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6060297.html 序 昨天,通过<C# 知识回顾 - ...
- [.NET] C# 知识回顾 - 事件入门
C# 知识回顾 - 事件入门 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6057301.html 序 之前通过<C# 知识回顾 - 委托 de ...
- [.NET] C# 知识回顾 - 委托 delegate (续)
C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...
- [C#] C# 知识回顾 - 委托 delegate
C# 知识回顾 - 委托 delegate [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6031892.html 目录 What's 委托 委托的属性 ...
- [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute
剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...
随机推荐
- 前端框架 EasyUI (2)页面布局 Layout
在 Web 程序中,页面布局对应用程序的用户体验至关重要. 在一般的信息管理类的 Web 应用程序中,页面结构通常有一个主工作区,然后在工作区上下左右靠近边界的区域设置一些边栏,用于显示信息或放置一些 ...
- Java中的多态
1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal {public abstract void Say();} 子类: public class ...
- JavaScript权威指南 - 数组
JavaScript数组是一种特殊类型的对象. JavaScript数组元素可以为任意类型,最大容纳232-1个元素. JavaScript数组是动态的,有新元素添加时,自动更新length属性. J ...
- 如何利用ETW(Event Tracing for Windows)记录日志
ETW是Event Tracing for Windows的简称,它是Windows提供的原生的事件跟踪日志系统.由于采用内核(Kernel)层面的缓冲和日志记录机制,所以ETW提供了一种非常高效的事 ...
- 使用SecureCRT连接虚拟机(ubuntu)配置记录
这种配置方法,可以非常方便的操作虚拟机里的Linux系统,且让VMware在后台运行,因为有时候我直接在虚拟机里操作会稍微卡顿,或者切换速度不理想,使用该方法亲测本机效果确实ok,特此记录. Secu ...
- 解构C#游戏框架uFrame兼谈游戏架构设计
1.概览 uFrame是提供给Unity3D开发者使用的一个框架插件,它本身模仿了MVVM这种架构模式(事实上并不包含Model部分,且多出了Controller部分).因为用于Unity3D,所以它 ...
- js学习之类型识别
用来判别类型的方法有好多,整理了一下4种方法,平时用的时候,在不同情景下,还是要结合着使用的. 方法一 typeof:可以识别标准类型,除了Null:不能识别具体的对象类型,除了Function &l ...
- [原]Cachedb 网络模块文档
Cachedb 网络模块文档 整体结构 多路复用 (epoll 模块) 事件驱动 (事件封装) 缓冲管理 (上层buffer管理) 设计思想 层次化的设计,每一个模块只调用上一个模块的接口,并将耦合聚 ...
- Jvm 内存浅析 及 GC个人学习总结
从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...
- 负载均衡——nginx理论
nginx是什么? nginx是一个强大的web服务器软件,用于处理高并发的http请求和作为反向代理服务器做负载均衡.具有高性能.轻量级.内存消耗少,强大的负载均衡能力等优势. nginx架构? ...