[C#] 只是想简单说下特性

只是想简单说下特性

【博主】反骨仔    【原文地址】http://www.cnblogs.com/liqingwen/p/5911289.html

目录

说说特性

一、特性简介

  特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性。

  特性具有以下属性:

    (1)特性可向程序中添加元数据。元数据是有关在程序中定义的类型的信息。所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员。可以添加自定义特性,以指定所需的任何附加信息。

    (2)可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。

    (3)特性可以与方法和属性相同的方式接受参数。

    (4)程序可以使用反射检查自己的元数据或其他程序内的元数据。

二、使用特性

  特性可以放置在几乎所有的声明中(但特定的特性可能限制在其上有效的声明类型)。在 C# 中,特性的指定方法为:将括在方括号中的特性名置于其应用到的实体的声明上方。它必须位于所应用于的元素的紧前面并与该元素在同一行。

 1     [Serializable]  //使用特性 SerializableAttribute
 2     internal class MyClass
 3     {
 4         [DllImport("user32.dll")]   //使用特性 DllImportAttribute
 5         private static extern void Do();
 6
 7         #region 一个声明上可放置多个特性
 8
 9         private void MethodA([In][Out]ref double n) { }
10         private void MethodB([In, Out]ref double n) { }
11
12         #endregion 一个声明上可放置多个特性
13
14         #region 某些特性对于给定实体可以指定多次
15
16         [Conditional("DEBUG"), Conditional("TEST1")]
17         private void TraceMethod() { }
18
19         #endregion 某些特性对于给定实体可以指定多次
20     }

  【注意】根据约定,所有特性名称都以单词“Attribute”结束,以便将它们与“.NET Framework”中的其他项区分。但是,在代码中使用特性时,不需要指定 attribute 后缀。

三、特性参数

  许多特性都有参数,而这些参数可以是定位参数、未命名参数或命名参数。任何定位参数都必须按特定顺序指定并且不能省略,而命名参数是可选的且可以按任意顺序指定。首先指定定位参数。例如,这三个特性是等效的:

1 [DllImport("user32.dll")]
2 [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)]
 1 //示例:将特性应用于方法、方法参数和方法返回值
 2
 3 //默认:应用于方法
 4 [SomeAttr]
 5 int Method1() { return 0; }
 6
 7 //指定应用于方法
 8 [method: SomeAttr]
 9 int Method2() { return 0; }
10
11 //指定应用于返回值
12 [return: SomeAttr]
13 int Method3() { return 0; }

五、特性的常见用途

  以下列表包含特性的几个常见用途:

    (1)在 Web 服务中,使用 WebMethod 特性来标记方法,以指示该方法应该可通过 SOAP 协议进行调用。

    (2)描述当与本机代码进行交互操作时如何封送方法参数。有关更多信息。

    (3)描述类、方法和接口的 COM 属性。

    (4)使用 DllImportAttribute 类调用非托管代码。

    (5)在标题、版本、说明或商标方面描述您的程序集。

    (6)描述要持久性序列化类的哪些成员。

    (7)描述如何映射类成员和 XML 节点以便进行 XML 序列化。

    (8)描述方法的安全要求。

    (9)指定用于强制安全性的特性。

    (10)由实时 (JIT) 编译器控制优化,以便易于调试代码。

    (11)获取有关调用方的信息的方法。

创建自定义特性

  通过定义一个特性类,可以创建您自己的自定义特性。该特性类直接或间接地从 Attribute 派生,有助于方便快捷地在元数据中标识特性定义。

 1     /// <summary>
 2     /// 角色特性
 3     /// </summary>
 4     /// RoleAttribute:特性的名称,继承 Attribute,为自定义特性
 5     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
 6     public class RoleAttribute : Attribute
 7     {
 8         private string _name;
 9
10         /// <summary>
11         /// 启用标识
12         /// </summary>
13         /// IsEnable:命名参数
14         public bool IsEnable { get; set; }
15
16         /// <summary>
17         /// 构造函数
18         /// </summary>
19         /// <param name="name"></param>
20         /// name:定位参数
21         public RoleAttribute(string name)
22         {
23             _name = name;
24         }
25     }
1     [Role("Me", IsEnable = true)]   //调用特性的方式
2     public class OurClass
3     {
4
5     }

  构造函数的参数是自定义特性的定位参数,任何公共的读写字段或属性都是命名参数。【注意】 AttributeUsage 特性,在这里它使得 Role 特性仅在类和 struct 声明中有效。

1     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]  //AllowMultiple:该值指示能否为一个程序多次使用该特性
2     public class RoleAttribute : Attribute
3     {
4         //... ...
5     }
1     [Role("You")]            //在同一个类上多次使用
2     [Role("Me", IsEnable = true)]
3     public class OurClass
4     {
5         //... ...
6     }

  【注意】如果特性类包含一个属性,则该属性必须为读写属性。

使用反射访问特性

  如果没有检索自定义特性的信息和对其进行操作的方法,则定义自定义特性并将其放置在源代码中就没有意义。使用反射,可检索用自定义特性定义的信息。主要方法是 GetCustomAttributes,它返回对象数组,这些对象在运行时等效于源代码特性。

 1     /// <summary>
 2     /// 角色特性
 3     /// </summary>
 4     /// RoleAttribute:特性的名称,继承 Attribute,为自定义特性
 5     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
 6     public class RoleAttribute : Attribute
 7     {
 8         private string _name;
 9         /// <summary>
10         /// 启用标识
11         /// </summary>
12         public bool IsEnable { get; set; }
13
14         /// <summary>
15         /// 构造函数
16         /// </summary>
17         /// <param name="name"></param>
18         public RoleAttribute(string name)
19         {
20             _name = name;
21         }
22     }

RoleAttribute.cs

1     [Role("Me", IsEnable = true)]
2     public class OurClass
3     {
4         //... ...
5     }

  概念上等效于

1     RoleAttribute role = new RoleAttribute("Me");
2     role.IsEnable = true;

  但是,直到查询 OurClass 来获取特性后才会执行此代码。对 OurClass 调用 GetCustomAttributes 会导致按上述方式构造并初始化一个 RoleAttribute 对象。如果该类具有其他特性,则按相似的方式构造其他特性对象。然后 GetCustomAttributes 返回 RoleAttribute 对象和数组中的任何其他特性对象。之后就可以对此数组进行迭代,确定根据每个数组元素的类型所应用的特性,并从特性对象中提取信息。

  这里,定义一个自定义特性,将其应用于若干实体并通过反射进行检索。

 1     /// <summary>
 2     /// 角色特性
 3     /// </summary>
 4     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
 5     public class RoleAttribute : Attribute
 6     {
 7         private readonly string _name;
 8
 9         /// <summary>
10         /// 启用标识
11         /// </summary>
12         public bool IsEnable { get; set; }
13
14         /// <summary>
15         /// 构造函数
16         /// </summary>
17         /// <param name="name"></param>
18         public RoleAttribute(string name)
19         {
20             _name = name;
21         }
22
23         public string GetName()
24         {
25             return _name;
26         }
27     }
 1     class MyClass1
 2     {
 3
 4     }
 5
 6     [Role("Me")]
 7     class MyClass2
 8     {
 9
10     }
11
12     [Role("Me"), Role("You", IsEnable = true)]
13     class MyClass3
14     {
15
16     }
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Output(typeof(MyClass1));
 6             Output(typeof(MyClass2));
 7             Output(typeof(MyClass3));
 8
 9             Console.Read();
10         }
11
12         /// <summary>
13         /// 输出
14         /// </summary>
15         /// <param name="t"></param>
16         static void Output(Type t)
17         {
18             Console.WriteLine($"Class: {t}");
19
20             var attributes = t.GetCustomAttributes();
21             foreach (var attribute in attributes)
22             {
23                 var attr = attribute as RoleAttribute;
24
25                 if (attr == null)
26                 {
27                     return;
28                 }
29
30                 Console.WriteLine($"    Name: {attr.GetName()}, IsEnable: {attr.IsEnable}");
31             }
32         }
33     }

--预览版,整理完毕后发布到首页--

时间: 2024-08-05 07:06:16

[C#] 只是想简单说下特性的相关文章

只是想简单说下序列化

[博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902005.html 目录 序列化的含义 通过序列化保存对象数据 众说纷纭 一.序列化的含义 序列化是将对象处理为字节流以存储对象或传输到内存.数据库或文件.其主要目的是保存对象的状态,以便可以在需要时重新创建对象.相反的过程称为反序列化. 1.1 序列化的工作方式 此图显示序列化的整个过程. 图1.1-1 对象被序列化为流.流传递的不仅是数据,还包括有关对象类型的信息,如对象的版本.区域性和程

简单聊下IO复用

没图,不分析API Java中IO API的发展:Socket -> SocketChannel -> AsynchronousSocketChannelServerSocket -> ServerSocketChannel -> AsynchronousServerSocketChannel 同步/阻塞 -> 同步/非阻塞(多路复用) -> 异步 想简单聊下多路复用.多路复用需要配合Reactor模式,前者解决技术上的问题,后者解决软件工程的问题. 技术上的问题,是将

在AJAX里 使用【 XML 】 返回数据类型 实现简单的下拉菜单数据

在AJAX里 使用XML返回数据类型 实现简单的下拉菜单数据 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <

我把适配想简单了

十六.十七号两天连着校庆.十八号是中学的开放日,百十周年,十分隆重.五几届六几届的都来了. 班里就凑了俩人,我在北京加班,没去.十九号早起一想不正确,得去,起来买火车票就回去了. 平时是不让进大门儿的,我想都没想FQ头就进去了,周日,我如入无人之境.逛了一下午. 校园里,每一处,都深烙着回顾.还是那些地方,仅仅是物是人非. 学妹出差未能赶上这盛会.让我带纪念品给她,一定要,不给不行.我仅仅好托我班主任.前一天去的同学带给我一枚纪念徽章,昨天送来的时候在学校蹭了我一顿. 十年前,一班同学四散全球,

简单聊下Unicode和UTF-8

今晚听同事分享提到这个,简单总结下. ## Unicode字符集 Unicode的出现是因为ASCII等其他编码码不够用了,比如ASCII是英语为母语的人发明的,只要一个字节8位就能够表示26个英文字母了,但是当跨区域进行信息交流的时候,尤其是Internet的出现,除了“A”,“B”,“C",还有“你”,“我”,“他”需要表示,一个字节8位显然不够用,够因此Unicode就被发明出来,Unicode的最大码位0x10FFFF,有21位.中文对应的Unicode编码见http://www.chi

jQuery实现简单的下拉可输入组合框

[写在前面的话]网站上很多用各种插件,比如依赖bootstrap的bootstrap-select插件等.虽然这些框架可以实现很多功能,但因为在实际项目中,可能只会用到其中的某个功能,若是一概引入,会导致整个js加载过于笨重.比如前面提到的bootstrap-select插件,在不压缩的情况下,达到300多k.因此,为了实现一个可填写的下拉框有点得不偿失. 基于这种原因,于是私下用jquery写了一个比较简单的下拉可填写组合框. CSS code: 1 .container{ 2 margin:

Example017简单的下拉框

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>简单的下拉框</title> <style> * { padding: 0; margin: 0; } .main { width: 1200px; height: 300px; margin: 0 auto; } h3 { margin-lef

Javascript实现简单的下拉二级菜单

在线演示;http://jsfiddle.net/Web_Code/ThhbG/embedded/result/ <span style="font-size:14px;"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <

jsp简单练习-简单的下拉表单

<%@ page contentType="text/html; charset=gb2312" %> <html> <body> <form name="form1" action="SwitchApp.jsp" method="post"> 请选择一种颜色: <select name="ys"> <option value="r