前言:不管是自定义的一些特性,或者是C#中内置的特性,均继承自Attribute这个类,这个类也提供了一些方法,方便我们使用。

Attribute类有三个静态方法:
1.IsDefined,如果有指定的Attribute的实例与目标关联,则返回true。
2.GetCustomAttributes,返回一个数组,其中每个元素都是应用于目标的指定attribute类的一个实例。该方法通常用于已将AllowMultiple设为true的attribute,或者用于列出已应用的所有attribute。
3.GetCustomAttribute返回应用于目标的指定attribute类的一个实例。该方法通常用于已将AllowMultiple设置为false的attribute。

P.S.如果仅仅定义一个特性或者说给某个部分应用了特性是没有意义的,我们通过判断操作来对逻辑进行控制。

一、检测元素是否包含指定的特性

1.使用最简单的方法,就是使用上述中的IsDefined方法,最简单,使用如下(MSDN例子):

  1. public class TestClass
  2. {
  3. //表明此方法过时
  4. [Obsolete("This method is obsolete. Use Method2 instead.")]
  5. public void Method1()
  6. {}
  7. public void Method2()
  8. {}
  9. }
  1. static void Main(string[] args)
  2. {
  3. // 得到指定类型的Type对象
  4. Type clsType = typeof(TestClass);
  5. // 得到当前Method1方法的方法对象MethodInfo
  6. MethodInfo mInfo = clsType.GetMethod("Method1");
  7. // 判断当前的方法是否应用了ObsoleteAttribute特性
  8. bool isDef = Attribute.IsDefined(mInfo, typeof(ObsoleteAttribute));
  9. // 输出结果
  10. Console.WriteLine("The Obsolete Attribute {0} defined for {1} of class {2}.",
  11. isDef ? "is" : "is not", mInfo.Name, clsType.Name);
  12. // 如果存在此特性
  13. if (isDef)
  14. {
  15.       //得到当前MethodInfo中的ObsoleteAttribute特性对象
  16. ObsoleteAttribute obsAttr =
  17. (ObsoleteAttribute)Attribute.GetCustomAttribute(
  18. mInfo, typeof(ObsoleteAttribute));
  19. if (obsAttr != null)
  20. Console.WriteLine("The message is: \"{0}\".",
  21. obsAttr.Message);
  22. else
  23. Console.WriteLine("The message could not be retrieved.");
  24. }
  25. }
  26. }

2.输出某个类的所有特性,例子如下:

  1.   [assembly:CLSCompliant(true)]
  2. [Serializable]
  3. [DefaultMemberAttribute("Main")]
  4. [DebuggerDisplayAttribute("Richer", Name = "Super.Mario", Target = typeof(Program))]
  5. public sealed class Program
  6. {
  7. public Program() { }
  8. [CLSCompliant(true)]
  9. [STAThread]
  10. public static void Main(string[] args)
  11. {
  12. ShowAttributes1(typeof(Program));
  13.  
  14. MemberInfo[] members = typeof(Program).FindMembers(MemberTypes.Constructor | MemberTypes.Method,
  15. BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static,
  16. Type.FilterName, "*");
  17. foreach (var member in members)
  18. {
  19. ShowAttributes1(member);
  20. }
  21. Console.Read();
  22. }
  23.  
  24. static void ShowAttributes1(MemberInfo attributesTarget)
  25. {
  26. Attribute[] attributes = Attribute.GetCustomAttributes(attributesTarget);
  27. Console.WriteLine("Attributes applied to {0} : {1}", attributesTarget.Name, (attributes.Length == ? "None" : string.Empty));
  28.  
  29. foreach (var attribute in attributes)
  30. {
  31. Console.WriteLine("{0}", attribute.GetType().ToString());
  32. if (attribute is DefaultMemberAttribute)
  33. {
  34. Console.WriteLine("MemberName={0}", ((DefaultMemberAttribute)attribute).MemberName);
  35. }
  36. if (attribute is ConditionalAttribute)
  37. {
  38. Console.WriteLine("ConditionString={0}", ((ConditionalAttribute)attribute).ConditionString);
  39. }
  40. if (attribute is CLSCompliantAttribute)
  41. {
  42. Console.WriteLine("IsCompliant={0}", ((CLSCompliantAttribute)attribute).IsCompliant);
  43. }
  44. var dda = attribute as DebuggerDisplayAttribute;
  45. if (dda != null)
  46. {
  47. Console.WriteLine("Value={0},Name={1},Target={2}", dda.Value, dda.Name, dda.Target);
  48. }
  49. }
  50. }
      }
    }

不用太在意某一个特性是什么意思,旨在通过Type.FindMembers方法得到所有的成员,然后输出特性的信息。当然这里最主要的方法是GetCustomAttributes,上文已经解释过,用于获取指定对象的所有应用的特性,具体解释可以参看MSDN,最后将一个个特性的信息输出。

二、通过更为安全的方式进行特性的操作

之所以说是安全的方式操作,那是因为在调用Attribute的GetCustomAttribute或者GetCustomeAttributes方法时,这些方法会在内部调用attribute类的构造器,而且可能调用属性的set访问器方法。除此之外,首次访问一个类型会造成CLR调用类型的类型构造器(如果有)。在构造器、set访问器方法以及类型构造器中,可能包含每次查找一个attribute时都要执行的代码。这样的话,就相当于允许未知的代码在AppDomain中运行,所以是一个潜在的安全隐患。
使用System.Reflection.CustomAttributeData类,可以在查找attribute的同时禁止执行attribute中的代码。这个类定义了一个静态方法GetCustomeAttribute来获取与一个目标关联的attribute。该方法有四个重载版本:一个接受一个Assembly,一个接受一个Module,一个接受一个ParameterInfo,另一个接受MemberInfo。GetCustomAttributes方法相当于一个工厂方法,返回一个CustomAttributeData类型的集合。在集合中应用于指定目标的每个定制Attribute都有一个对应的元素。针对每个CustomAttributeData对象,都可以查询一些只读属性,判断attribute对象时如何构造和初始化的。具体地说,Constructor属性指出构造器方法要如何调用。ConstructorArguments属性以一个IList<CustomAttributeTypedArgument>实例的形式返回要传给这个构造器的实参。NamedArguments属性以一个IList<CustomAttributeNamedArgument>实例的形式,返回要设置的字段或者属性。注意,之所以说要,是因为不会实际地调用构造器和set访问器方法。

  1. [assembly:CLSCompliant(true)]
  2. [Serializable]
  3. [DefaultMemberAttribute("Main")]
  4. [DebuggerDisplayAttribute("Richer", Name = "Super.Mario", Target = typeof(Program))]
  5. public sealed class Program
  6. {
  7. public Program() { }
  8. [CLSCompliant(true)]
  9. [STAThread]
  10. public static void Main(string[] args)
  11. {
  12. ShowAttributes1(typeof(Program));
  13.  
  14. MemberInfo[] members = typeof(Program).FindMembers(MemberTypes.Constructor | MemberTypes.Method,
  15. BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static,
  16. Type.FilterName, "*");
  17. foreach (var member in members)
  18. {
  19. ShowAttributes2(member);
  20. }
  21. Console.Read();
  22. }
  23. static void ShowAttributes2(MemberInfo attributeTarget)
  24. {//通过禁止执行attribu类的任何方法,我们获得了增强的安全性。
  25. IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(attributeTarget);
  26. Console.WriteLine("Attributes applied to {0} : {1}", attributeTarget.Name, (attributes.Count == ? "None" : string.Empty));
  27. foreach (var attribute in attributes)
  28. {
  29. //显示所应用的每个Attribute的类型
  30. Type t = attribute.Constructor.DeclaringType;
  31. Console.WriteLine("{0}",t.ToString());
  32. Console.WriteLine("Constructor called={0}", attribute.Constructor);
  33.  
  34. IList<CustomAttributeTypedArgument> posArgs = attribute.ConstructorArguments;
  35. Console.WriteLine("Positional arguments passed to constructor:"+
  36. ((posArgs.Count==)? " None" : string.Empty));
  37. foreach (var arg in posArgs)
  38. {
  39. Console.WriteLine(" Type={0},Value={1}", arg.ArgumentType, arg.Value);
  40. }
  41.  
  42. IList<CustomAttributeNamedArgument> namedArgs = attribute.NamedArguments;
  43. Console.WriteLine(" Named arguments set after construction:" + ((namedArgs.Count == ) ? "None" : string.Empty));
  44. foreach (var namedArg in namedArgs)
  45. {
  46. Console.WriteLine(" Name={0},Type={1},Value={2}", namedArg.MemberInfo.Name, namedArg.TypedValue.ArgumentType,
  47. namedArg.TypedValue.Value);
  48. }
  49.  
  50. }
  51. }
  52. }

此种方式前半部分和上一种方法一样,得到类型的成员,然后通过方法进行输出显示。区别就在于获取特性的过程使用了CustomAttributeData对象得到指定成员的特性集合,然后通过ConstructorArguments得到参数列表(获取为由 CustomAttributeData 对象表示的特性实例指定的位置参数列表,也就是构造函数的参数。)。同时也通过NamedArguments属性得到特性的位置参数(获取为由 CustomAttributeData 对象表示的特性实例指定的命名参数列表。),也可以理解为就是一般的属性(即不是通过构造函数传递的)。

好了,本文主要简单介绍了如何去检测C#中各种成员是否包含指定的特性以及得到成员的所有特性,然后做出相应的操作。如果大家有好的方法,可以及时讨论哦。

C#中检测某个类(方法、程序集等各种部分)是否应用了指定的特性以及对特性的一些简单操作的更多相关文章

  1. javascript 中检测数据类型的方法

    typeof 检测数据类型 javascript 中检测数据类型有好几种,其中最简单的一种是 typeof 方式.typeof 方法返回的结果是一个字符串.typeof 的用法如下: typeof v ...

  2. 在PHP中检测一个类是否可以被foreach遍历

    在PHP中,我们可以非常简单的判断一个变量是什么类型,也可以非常方便的确定一个数组的长度从而决定这个数组是否可以遍历.那么类呢?我们要如何知道这个类是否可以通过 foreach 来进行遍历呢?其实,P ...

  3. JS中判断数组的方法

    JavaScript中检测对象的方法 1.typeof操作符 这种方法对于一些常用的类型来说那算是毫无压力,比如Function.String.Number.Undefined等,但是要是检测Arra ...

  4. JS中检测数据类型的四种方法

    1.typeof 用来检测数据类型的运算符->typeof value->返回值首先是一个字符串,其次里面包含了对应的数据类型,例如:"number"."st ...

  5. 【Android进阶】为什么要创建Activity基类以及Activity基类中一般有哪些方法

    现在也算是刚刚基本完成了自己的第一个商业项目,在开发的过程中,参考了不少人的代码风格,然而随着工作经验的积累,终于开始慢慢的了解到抽象思想在面向对象编程中的重要性,这一篇简单的介绍一下我的一点收获. ...

  6. 关于spring中Assert的应用(方法入参检测工具类)

    关于spring中Assert的应用(方法入参检测工具类) Web 应用在接受表单提交的数据后都需要对其进行合法性检查,如果表单数据不合法,请求将被驳回.类似的,当我们在编写类的方法时,也常常需要对方 ...

  7. 百度编辑器ueditor通过ajax方式提交,不需要事先转义字符的方法(异常:从客户端(xxx)中检测到有潜在危险的 Request.Form 值)

    最近项目中使用百度编辑神器ueditor,确实是很好用的一款编辑器.官网教程提供的与后端数据交互都是跟表单方式有关的,项目中使用的是ajax方式提交,因此出现了不少问题,现在记录备忘下. 环境:.ne ...

  8. MSIL实用指南-给字段、属性、方法、类、程序集加Attribute

    C#编程中可以给字段.方法.类以及程序集加特性即继承于Attribute的类.这里讲解怎么在IL中给它们加上特性. 生成字段的对应的类是FieldBuilder,生成属性的对应的类是PropertyB ...

  9. JS 中检测数组的四种方法

    今天和大家分享一下 JS 中检测是不是数组的四种方法,虽然篇幅不长,不过方法应该算是比较全面了. 1. instanceof 方法 instanceof 用于检测一个对象是不是某个类的实例,数组也是一 ...

随机推荐

  1. java rest框架jersey数组单记录问题解决

    JAVA数据接口采用jersey技术,可以返回xml,json等格式,可以根据客户端请求accept,如:Application/json,Application/xml 来得到不同的接口数据,非常好 ...

  2. React + Reflux

    React + Reflux 渲染性能优化原理   作者:ManfredHu 链接:http://www.manfredhu.com/2016/11/08/23-reactRenderingPrinc ...

  3. 设计模式之Birdge(桥接)模式

    1.出现原因 1.同一个类型,有两个变化的维度(两个维度的抽象:一个抽象部分的抽象,一个实现部分的抽象) 2.如何应对这种“多维度的变化”?如何利用面向对象技术来使得同一类型可以轻松地沿着两个方向变化 ...

  4. IIS8中 出现ashx 401:未授权,uploadify上传文件失败

    环境:阿里云服务器 windows2012  + IIS8 +asp.net 访问IIS 出现能正常访问aspx页面,但是通过ajax访问ashx上传文件的时候就出现ashx  Status Code ...

  5. android开发 根据Uri获取真实路径

    Uri uri = data.getData(); String[] proj = { MediaStore.Images.Media.DATA }; Cursor actualimagecursor ...

  6. 【Binary Tree Level Order Traversal】cpp

    题目: Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to ri ...

  7. 前端之JavaScript第一天学习(1)-JavaScript 简介

    javaScript 是世界上最流行的编程语言. 这门语言可用于 HTML 和 web,更可广泛用于服务器.PC.笔记本电脑.平板电脑和智能手机等设备. JavaScript 是脚本语言 JavaSc ...

  8. C语言面向对象风格编程

    前言 本文略谈C面向对象风格编程,如何使用过程式语言去模拟面向对象的特性?C面向对象的方式和形式很多,不一而足,本文的代码形式是模拟部分C++面向对象关键词并赋予其特性,这种方式对于初级程序员比较好理 ...

  9. 【BZOJ】【3163】【HEOI2013】Eden的新背包问题

    多重背包/思路题 多次询问,每次从所有物品中忽略一件,问最大收益…… 这题我用的zyf的一个“暴力”做法,就是先预处理出来g1[i][j]表示1~i号物品花了j块钱的最大价值,g2[i][j]表示i~ ...

  10. Springmvc jar包介绍

    spring.jar是包含有完整发布的单个jar 包,spring.jar中包含除了spring-mock.jar里所包含的内容外其它所有jar包的内容,因为只有在开发环境下才会用到 spring-m ...