C#中检测某个类(方法、程序集等各种部分)是否应用了指定的特性以及对特性的一些简单操作
2013-12-14 20:49
901 查看
前言:不管是自定义的一些特性,或者是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例子):
2.输出某个类的所有特性,例子如下:
不用太在意某一个特性是什么意思,旨在通过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访问器方法。
此种方式前半部分和上一种方法一样,得到类型的成员,然后通过方法进行输出显示。区别就在于获取特性的过程使用了CustomAttributeData对象得到指定成员的特性集合,然后通过ConstructorArguments得到参数列表(获取为由 CustomAttributeData 对象表示的特性实例指定的位置参数列表,也就是构造函数的参数。)。同时也通过NamedArguments属性得到特性的位置参数(获取为由 CustomAttributeData 对象表示的特性实例指定的命名参数列表。),也可以理解为就是一般的属性(即不是通过构造函数传递的)。
好了,本文主要简单介绍了如何去检测C#中各种成员是否包含指定的特性以及得到成员的所有特性,然后做出相应的操作。如果大家有好的方法,可以及时讨论哦。
Attribute类有三个静态方法:
1.IsDefined,如果有指定的Attribute的实例与目标关联,则返回true。
2.GetCustomAttributes,返回一个数组,其中每个元素都是应用于目标的指定attribute类的一个实例。该方法通常用于已将AllowMultiple设为true的attribute,或者用于列出已应用的所有attribute。
3.GetCustomAttribute返回应用于目标的指定attribute类的一个实例。该方法通常用于已将AllowMultiple设置为false的attribute。
P.S.如果仅仅定义一个特性或者说给某个部分应用了特性是没有意义的,我们通过判断操作来对逻辑进行控制。
一、检测元素是否包含指定的特性
1.使用最简单的方法,就是使用上述中的IsDefined方法,最简单,使用如下(MSDN例子):
public class TestClass { //表明此方法过时 [Obsolete("This method is obsolete. Use Method2 instead.")] public void Method1() {} public void Method2() {} }
static void Main(string[] args) { // 得到指定类型的Type对象 Type clsType = typeof(TestClass); // 得到当前Method1方法的方法对象MethodInfo MethodInfo mInfo = clsType.GetMethod("Method1"); // 判断当前的方法是否应用了ObsoleteAttribute特性 bool isDef = Attribute.IsDefined(mInfo, typeof(ObsoleteAttribute)); // 输出结果 Console.WriteLine("The Obsolete Attribute {0} defined for {1} of class {2}.", isDef ? "is" : "is not", mInfo.Name, clsType.Name); // 如果存在此特性 if (isDef) { //得到当前MethodInfo中的ObsoleteAttribute特性对象 ObsoleteAttribute obsAttr = (ObsoleteAttribute)Attribute.GetCustomAttribute( mInfo, typeof(ObsoleteAttribute)); if (obsAttr != null) Console.WriteLine("The message is: \"{0}\".", obsAttr.Message); else Console.WriteLine("The message could not be retrieved."); } } }
2.输出某个类的所有特性,例子如下:
[assembly:CLSCompliant(true)] [Serializable] [DefaultMemberAttribute("Main")] [DebuggerDisplayAttribute("Richer", Name = "Super.Mario", Target = typeof(Program))] public sealed class Program { public Program() { } [CLSCompliant(true)] [STAThread] public static void Main(string[] args) { ShowAttributes1(typeof(Program)); MemberInfo[] members = typeof(Program).FindMembers(MemberTypes.Constructor | MemberTypes.Method, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static, Type.FilterName, "*"); foreach (var member in members) { ShowAttributes1(member); } Console.Read(); } static void ShowAttributes1(MemberInfo attributesTarget) { Attribute[] attributes = Attribute.GetCustomAttributes(attributesTarget); Console.WriteLine("Attributes applied to {0} : {1}", attributesTarget.Name, (attributes.Length == 0 ? "None" : string.Empty)); foreach (var attribute in attributes) { Console.WriteLine("{0}", attribute.GetType().ToString()); if (attribute is DefaultMemberAttribute) { Console.WriteLine("MemberName={0}", ((DefaultMemberAttribute)attribute).MemberName); } if (attribute is ConditionalAttribute) { Console.WriteLine("ConditionString={0}", ((ConditionalAttribute)attribute).ConditionString); } if (attribute is CLSCompliantAttribute) { Console.WriteLine("IsCompliant={0}", ((CLSCompliantAttribute)attribute).IsCompliant); } var dda = attribute as DebuggerDisplayAttribute; if (dda != null) { Console.WriteLine("Value={0},Name={1},Target={2}", dda.Value, dda.Name, dda.Target); } } } } }
不用太在意某一个特性是什么意思,旨在通过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访问器方法。
[assembly:CLSCompliant(true)] [Serializable] [DefaultMemberAttribute("Main")] [DebuggerDisplayAttribute("Richer", Name = "Super.Mario", Target = typeof(Program))] public sealed class Program { public Program() { } [CLSCompliant(true)] [STAThread] public static void Main(string[] args) { ShowAttributes1(typeof(Program)); MemberInfo[] members = typeof(Program).FindMembers(MemberTypes.Constructor | MemberTypes.Method, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static, Type.FilterName, "*"); foreach (var member in members) { ShowAttributes2(member); } Console.Read(); } static void ShowAttributes2(MemberInfo attributeTarget) {//通过禁止执行attribu类的任何方法,我们获得了增强的安全性。 IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(attributeTarget); Console.WriteLine("Attributes applied to {0} : {1}", attributeTarget.Name, (attributes.Count == 0 ? "None" : string.Empty)); foreach (var attribute in attributes) { //显示所应用的每个Attribute的类型 Type t = attribute.Constructor.DeclaringType; Console.WriteLine("{0}",t.ToString()); Console.WriteLine("Constructor called={0}", attribute.Constructor); IList<CustomAttributeTypedArgument> posArgs = attribute.ConstructorArguments; Console.WriteLine("Positional arguments passed to constructor:"+ ((posArgs.Count==0)? " None" : string.Empty)); foreach (var arg in posArgs) { Console.WriteLine(" Type={0},Value={1}", arg.ArgumentType, arg.Value); } IList<CustomAttributeNamedArgument> namedArgs = attribute.NamedArguments; Console.WriteLine(" Named arguments set after construction:" + ((namedArgs.Count == 0) ? "None" : string.Empty)); foreach (var namedArg in namedArgs) { Console.WriteLine(" Name={0},Type={1},Value={2}", namedArg.MemberInfo.Name, namedArg.TypedValue.ArgumentType, namedArg.TypedValue.Value); } } } }
此种方式前半部分和上一种方法一样,得到类型的成员,然后通过方法进行输出显示。区别就在于获取特性的过程使用了CustomAttributeData对象得到指定成员的特性集合,然后通过ConstructorArguments得到参数列表(获取为由 CustomAttributeData 对象表示的特性实例指定的位置参数列表,也就是构造函数的参数。)。同时也通过NamedArguments属性得到特性的位置参数(获取为由 CustomAttributeData 对象表示的特性实例指定的命名参数列表。),也可以理解为就是一般的属性(即不是通过构造函数传递的)。
好了,本文主要简单介绍了如何去检测C#中各种成员是否包含指定的特性以及得到成员的所有特性,然后做出相应的操作。如果大家有好的方法,可以及时讨论哦。
相关文章推荐
- Visual Studio 2017中使用正则修改部分内容 如何使用ILAsm与ILDasm修改.Net exe(dll)文件 C#学习-图解教程(1):格式化数字字符串 小程序开发之图片转Base64(C#、.Net) jquery遍历table为每一个单元格取值及赋值 。net加密解密相关方法 .net关于坐标之间一些简单操作
- 文章标题 Java中io流的一些简单操作(包含文件复制,向硬盘中写入文本文件,以及io流高级应用序列化和反序列化)
- C#中使用Char类中的方法对字符进行各种操作,判断是否为字母、数字、标点符号、分隔符或空白。
- mongodb的一些基本操作以及c++驱动的简单方法
- C# 检测操作系统是否空闲,实现系统空闲后做一些操作
- C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志
- 简单文件操作python 修改文件指定行的方法
- c#操作Excel 一些问题 字符变为null解决方法
- C# 多线程 简单使用方法以及常用参数
- EasyJoyStick使用以及两种操作杆 EasyJoyStick的使用方法,简单的不能再简单 Hedgehog Team-》Easy Touch -》Add Easy Touch For C#
- C# 类型转换的一些简单方法
- ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml) 用javascript在客户端删除某一个cookie键值对 input点击链接另一个页面,各种操作。 C# 往线程里传参数的方法总结 TCP/IP 协议 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图 (转)值得学习百度开源70+项目
- C#基础--.net平台的重要组成部分以及.net程序简单的编译原理
- 复习struts2之基于XML配置文件实现指定方法的输入校验以及基于XML校验的一些特点
- Nubia Z5S官方4.4 UI2.0音频Audio部分简单分析(也适用于其他8974/8064机型)以及减少破音出现几率的方法
- c#简单判断是否是闰年的方法代码
- 获取iframe中的内容、查找获取指定元素(关于用c++调用WEBBROWSER控件,使用相关接口操作web页面元素的一些方法)
- mysql-5.7.20实用下载、安装和配置方法,以及简单操作
- C#操作word的一些基本方法(word打印,插入文件,插入图片,定位页眉页脚,去掉横线)
- 数据结构(1)-栈的特性以及简单应用