C#基础--Attribute(标签) 和 reflect(反射) 应用

  1.Attribute的定义与作用:

公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为.比如在WCF中常用的序列化。比如添加的[DataMenber]就是一种标签。以及xml序列化也是一样的。

2.Reflect的定义与作用

反射可以用于观察并修改程序在运行时的执行。一个reflection-oriented程序组件可以监测一个范围内的代码执行情况,可以根据期望的目标与此相关的范围修改本身。这通常是通过在运行时动态分配程序代码实现。在面向对象的编程语言如Java中,反射允许在编译期间不知道接口的名称,字段、方法的情况下在运行时检查类、接口、字段和方法。它还允许的实例化新对象和调用的方法。(摘抄至维基百科). 其实可以简单理解为,通过反射可以很轻易的获取到一个类中的所有方法属性字段状态。

3.为了更方便的认识反射以及Attribute的应用,下面有个例子.

业务背景如下: 有个Person对象,目前只有Name和Num属性,然后要用方法校验Person对象的合法性。

判断规则:  1.Name必填,若Name为空,则提示"Name不能为空";

2.Num可以为空,但是若有数据的话必须由数字组成,若为非数字字符串则弹出"格式不正确".

          3.Address可以为空,若有数据的话长度不能超过12,若超过12则提示"Address 长度不能超过12"

需要考虑: 对于Person类,以后熟悉的判断规则可能会变化,也可能增加属性,减少属性。

  4.解决方案一:

对于常规解决方案,可能大家会想到。目前只有Name,Address,Num三个属性,每次我就写三个代码段分别对Name,Address,Num验证。如果增加属性, 比如增加了公共属性EmailAddress,那么就必须添加验证字符串是否是邮箱的代码,若删除了某个属性,就吧判断该属性是否合格的代码删除掉不进行判断。这个也是我最开始想到的方法。不过这样不好的地方是可维护性不好。改动太大了。而且会导致重复代码。不如如果需求改成Address不能为空了。那么在判断address是否合法的时候还要去添加判断不能为空的情况。

5.解决方案二:

为了解决方案一的问题,其实我们可以通过Attribute和反射来实现。思路如下:

5.1 首先我们创建一个PersonCheckAttribute对象,他继承与System.Attribute.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ReflectTest.Model
{
    public class PersonCheckAttribute:Attribute
    {

        // 三个bool变量用于确定是有要验证这些信息
        private bool checkEmpty = false; //是否为空
        private bool checkMaxLength = false; //最大长度
        private bool checkRegex = false; //用正则表达式验证参数(是邮箱,是否刷数字)

        private int maxLength = 0;
        private string regexStr = string.Empty;

        public bool CheckEmpty
        {
            get { return this.checkEmpty; }
            set { this.checkEmpty = value; }
        }

        public bool CheckMaxLength
        {
            get { return this.checkMaxLength; }
            set { this.checkMaxLength = value; }
        }

        public bool CheckRegex
        {
            get { return this.checkRegex; }
            set { this.checkRegex = value; }
        }

        public int MaxLength
        {
            get { return this.maxLength; }
            set { this.maxLength = value; }
        }

        public string RegexStr
        {
            get { return this.regexStr; }
            set { this.regexStr = value; }
        }
    }
}

5.2 然后我们来添加Person类。注意里面的标签。

Tips:我在里面打了标签,对于5.1的PersonCheckAttribute类中bool变量用来确定是否要进行验证,公共属性用来存取判断参数。
  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ReflectTest.Model
{
    public class Person
    {
        [PersonCheck(CheckEmpty=true)]
        public string Name { get; set; }

        [PersonCheck(CheckRegex = true, RegexStr = "^[0-9]*[1-9][0-9]*$")]
        public string Num { get; set; }

        [PersonCheck(CheckMaxLength = true, MaxLength = 12)]
        public string Address { get; set; }
    }
}

5.3 属性已经搞定,下面来看看,如何通过反射来获取类的公共属性,以及每个属性的Attribute。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ReflectTest.Model;
using System.Reflection;
using System.Text.RegularExpressions;

namespace ReflectTest.Business
{
    public class PersonCheck
    {
        // 获取所有的错误提示
        public static string GetErrorMessage(Person person)
        {
            PropertyInfo[] propertyInfos = person.GetType().GetProperties(); // 获取一个类的所有属性
            string errorMsg = string.Empty;

            //对所有公用属性(Name,Num,Address)遍历
            foreach (PropertyInfo info in propertyInfos)
            {
                errorMsg += GetSignalPropertity(info, person);
            }
            return errorMsg;
        }

        // 获取单个公共属性的Attribute.也就是model类里面的[PersonCheck]信息
        private static string GetSignalPropertity(PropertyInfo propertyInfo,Person person)
        {
            // 因为对于此示例,每个Properties(属性)只有一个Attribute(标签),所以用了first()来获取,
            // 不过有一点,就是必须在属性里面添加[PersonCheck]标签,但是可以不设置表情里面的字段.因为没有的.GetCustomAttributes()返回为null.指向first会报错.
            PersonCheckAttribute attribute = propertyInfo.GetCustomAttributes().First() as PersonCheckAttribute;
            string errorMsg = string.Empty;

            //以下的if语句是判断标签里面的设置,设置了什么就执行什么数据校验
            if (attribute.CheckEmpty)
            {
                 string obj = propertyInfo.GetValue(person) as string;
                 if (string.IsNullOrEmpty(obj))
                 {
                     errorMsg += Environment.NewLine + string.Format("{0} 不能为空", propertyInfo.Name);
                 }
            }

            if (attribute.CheckMaxLength)
            {
                string obj = propertyInfo.GetValue(person) as string;
                if (obj != null && obj.Length > attribute.MaxLength)
                {
                    errorMsg += Environment.NewLine + string.Format("{0} 最大长度为{1}", propertyInfo.Name, attribute.MaxLength);
                }
            }

            // 对于判断数字邮箱都可以通过正则表达式
            if (attribute.CheckRegex)
            {
                string obj = propertyInfo.GetValue(person) as string;
                Regex regex = new Regex(attribute.RegexStr);
                if (obj != null && !regex.IsMatch(obj))
                {
                    errorMsg += Environment.NewLine + string.Format("{0} 格式不对", propertyInfo.Name);
                }
            }

            return errorMsg;
        }
    }
}

5.4 下面来看运行结果。

5.4.1 若Person p = new Person(){Num=“abc”};调用GetErrorMessage(Person person)方法后运行结果如下。Person不能为空.
    

5.4.2 若Person p = new Person(){Num=“123”,Address=“chengdu,Tianfu SoftwarePark”};调用GetErrorMessage(Person person)方法后运行结果如下。Person不能为空.

  

  6.分析反射的好处:

如果需求修改,Address不能为空了,我只需要在Address的标签里面设置CheckEmpty=true,而不需要重新修改逻辑代码。同理,如果要给Person类添加属性EmailAddress,那么只需要在Person类里面添加属性EmailAddress设置标签为【PersonCheck(CheckRegexStr = true,regexStr="*")】,*未判断是否是合法有效的正则表达式即可。

  7.总结:

其实小弟也是刚接触反射。有很多东西也是一知半解。目前对反射的认识也就这么多,有其他大牛应用更多这方面的,如果有什么好的想法和资料也请大家分享一下,相互学习,相互提升。代码链接:http://download.csdn.net/detail/u010093618/8088327

  

时间: 2024-08-08 06:14:48

C#基础--Attribute(标签) 和 reflect(反射) 应用的相关文章

C#基础---Attribute(标签) 和 reflect(反射) 应用二

以前我有写过一篇有关,打标签和反射的应用,主要用于类中字段的验证.下面是连接 C#基础---Attribute(标签) 和 reflect(反射) 应用. 这个项目迭代发现公司项目里面发现老代码对业务扩展比较大的地方又通过打标签和反射做了一个小的框架,感觉挺实用的.于是想一想模仿一下就搬到博客园上.写得可能不好,也请各位博友指点. 背景: [为了方便,自己还是模拟一个背景吧, 感觉不是很恰当,不过自己的Demo里面自己这样写的.当然跟公司的比起来肯定不够完善]   每个人都会吃饭,可是每个国家吃

复习java基础第七天(反射)

一:目标 Ø理解 Class 类 Ø理解 Java 的类加载机制 Ø学会使用 ClassLoader 进行类加载 Ø理解反射的机制 Ø掌握 Constructor.Method.Field 类的用法 Ø理解并掌握动态代理 1.Class类 –对象照镜子后可以得到的信息:某个类的数据成员名.方法和构造器.某个类到底实现了哪些接口. 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象. 一个 Class 对象包含了特定某个类的有关信息. –  Class 对象只能由系统建立对象.

h5标签基础 meta标签

<meta>标签位于<head>标签里面,具体作用有如下: 1.设置网页编码 eg: <meta charset="utf-8"/>  ,//utf-8是包含了全世界字符的一个编码集合,例如一个中文网站在国外搭建后依旧不会乱码,会使用英文显示出来 2.增强Seo ,百度抓取强度 · <meta name="keywords" content="h5基础,h5标签meta的使用,h5增加抓取强度"/>

GO_09:GO语言基础之reflect反射

反射reflection 1. 反射可以大大的提高程序的灵活性,使得 interface{} 有更大的发挥余地 2. 反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息 3. 反射会将匿名字段作为独立字段(匿名字段本质) 4. 想要利用反射修改对象状态,前提是 interface.data 是 settable,即 pointer-interface 5. 通过反射可以"动态"调用方法 示例一: 举例说明反射使用 TypeOf 和 ValueOf 来取得传入类型的

Java基础学习笔记【12】Reflect反射(2)

使用反射来创建对象(1)public T newInstance():只能创建非private,无参的构造方法的对象:好比 new 类() 1 2 Class<Teacher> clz = Teacher.class; Teacher t2 = clz.newInstance(); (2)先得到一个构造器,调用构造器里的一个方法, T newInstance(Object... initargs) . initargs表示构造器的需要的实际参数 1 2 3 Constructor<Tea

Java基础学习笔记【11】Reflect反射(1)

InputStreamReader将字节流转换为字符流 在java1.7中新增了Files,Paths对流,路径操作的工具类,内部就是输入输出流等的操作 Syso加只能提示可以快速代码System.out.println(): 反射创建Class的三种方式:(1)使用 class的属性得到Class对象 1 2 Class<String> c = String.class;//String.class就表示JVM里的一份表示String类的字节码 Class<String> c2

java反射基础知识(四)反射应用实践

反射基础 p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没有接触过的话,建议先看一下官方文档的Quick Start. 在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的反射类Class,在Java中我们有三种方法可以获取一个对象的反射类. 通过getClass方法 在Java中,每一个Object都有一个getClass()方法,通过getClass方法我们可以获取到这个对象对应的反射类: 1 2 String s = "ziwenxie"; Class

3.JAVA语言基础部分&mdash;Class类与反射

什么是Java反射机制? JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的以及动态调用对象的方法的功能称为Java的反射机制. 反射机制提供了哪些功能? 在运行时判定任意一个对象所属的类 在运行时构造任意一个类的对象: 在运行时判定任意一个类所具有的成员变量和方法: 在运行时调用任意一个对象的方法: 生成动态代理: Java反射机制类: java.lang.Class; //类 java.lang.re

golang 使用reflect反射结构体

"反射结构体"是指在程序执行时,遍历结构体中的字段以及方法. 1.反射结构体 下面使用一个简单的例子说明如何反射结构体. 定义一个结构体,包括3个字段,以及一个方法. 通过reflect包,首先查看这个结构体对应的动态类型reflect.Type和动态值reflect.Value,并查看这个结构体对应的基本类型. 接着查看结构体的字段数量,并遍历每个字段. 打印每个字段的类型.值.以及tag标签. 最后,调用结构体中的方法,并打印返回结果. 具体代码如下. package main i