小白详细解析C#反射特性实例

  套用MSDN上对于反射的定义:反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。

地址:https://msdn.microsoft.com/zh-cn/library/ms173183(VS.80).aspx

  贴上示例代码:

首先程序入口代码Program

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            UserInf userss = new UserInf();
            userss.U_UserID = "aw12311";
            userss.U_Psw = "123";
            userss.U_UserName = "aw";
            userss.U_City = "武汉";
            userss.U_Popedom = 1;
            userss.U_Sex = 1;
            userss.U_BirthTime = 19900114;
            userss.U_AddDataTime = DateTime.Now;

            DateIsTableAttribute<UserInf> t = new DateIsTableAttribute<UserInf>();

            t.insertDate(userss);

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

将要被反射的程序类UserInf

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

namespace WindowsFormsApp1
{
    [Table("Consumers")]
    public class UserInf
    {
        private string _UserID;
        /// <summary>
        /// 登陆ID
        /// </summary>
        [Field("ConsumerID", DbType.String, 12)]
        public string U_UserID
        {
            get { return _UserID; }
            set { _UserID = value; }
        }

        private string _Psw;
        /// <summary>
        /// 登陆密码
        /// </summary>
        [Field("ConsumerPwd", DbType.String, 12)]
        public string U_Psw
        {
            get { return _Psw; }
            set { _Psw = value; }
        }

        private string _UserName;
        /// <summary>
        /// 用户别称
        /// </summary>
        [Field("ConsumerName", DbType.String, 50)]
        public string U_UserName
        {
            get { return _UserName; }
            set { _UserName = value; }
        }

        private string _City;
        /// <summary>
        /// 所住城市
        /// </summary>
        [Field("UserCity", DbType.String, 50)]
        public string U_City
        {
            get { return _City; }
            set { _City = value; }
        }

        private int _Popedom;
        /// <summary>
        /// 权限
        /// </summary>
        [Field("popedom", DbType.Int32, 0)]
        public int U_Popedom
        {
            get { return _Popedom; }
            set { _Popedom = value; }
        }

        private DateTime _AddDataTime;
        /// <summary>
        /// 注册时间
        /// </summary>
        [Field("addDataTime", DbType.Date, 0)]
        public DateTime U_AddDataTime
        {
            get { return _AddDataTime; }
            set { _AddDataTime = value; }
        }

        private int _Sex;
        /// <summary>
        /// 性别
        /// </summary>
        [Field("Sex", DbType.Int32, 0)]
        public int U_Sex
        {
            get { return _Sex; }
            set { _Sex = value; }
        }

        private int _BirthTime;
        /// <summary>
        /// 出身日期;
        /// </summary>
        [Field("BirthTime", DbType.String, 9)]
        public int U_BirthTime
        {
            get { return _BirthTime; }
            set { _BirthTime = value; }
        }
    }
}

将要被反射的程序类中引伸的自定义特性类:包括预定义特性[AttributeUsage(...)]和自定义特性类具体内容

  1、自定义特性类TableAttribute

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

namespace WindowsFormsApp1
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]

    public class TableAttribute : Attribute
    {
        private string _TableName;

        /// <summary>
        /// 映射的表名
        /// </summary>
        public string TableName
        {
            get { return _TableName; }
        }

        /// <summary>
        /// 定位函数映射表名;
        /// </summary>
        /// <param name="table"></param>
        public TableAttribute(string table)
        {
            _TableName = table;
        }
    }
}

  2、自定义特性类FieldAttribute

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

namespace WindowsFormsApp1
{
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public class FieldAttribute : Attribute
    {
        private string _Fields;
        /// <summary>
        /// 字段名称 keleyi.com
        /// </summary>
        public string Fields
        {
            get { return _Fields; }
        }

        private DbType _Dbtype;
        /// <summary>
        /// 字段类型
        /// </summary>
        public DbType Dbtype
        {
            get { return _Dbtype; }

        }

        private int _ValueLength;
        /// <summary>
        /// 字段值长度
        /// </summary>
        public int ValueLength
        {
            get { return _ValueLength; }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="fields"> 字段名</param>
        /// <param name="types"> 字段类型</param>
        /// <param name="i"> 字段值长度</param>
        public FieldAttribute(string fields, DbType types, int i)
        {
            _Fields = fields;
            _Dbtype = types;
            _ValueLength = i;
        }
    }
}

最后使用Type类型将封装的程序集的类型绑定到现有对象,并利用当前对象访问、检测和修改封装的程序集中特性

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;

namespace WindowsFormsApp1
{
    public class DateIsTableAttribute<T>
    {
        public string insertDate(T types)
        {
            string cmdtxt = "insert into ";
            string cmdparVar = null;
            Type userAttu = types.GetType();
            TableAttribute tables = (TableAttribute)userAttu.GetCustomAttributes(false)[0];//UserInf中的Table结点
            cmdtxt += tables.TableName + "(";
            PropertyInfo[] info = userAttu.GetProperties();
            foreach (PropertyInfo prs in info)
            {
                object[] attu = prs.GetCustomAttributes(false);
                foreach (Attribute abute in attu)
                {
                    if (abute is FieldAttribute)
                    {
                        FieldAttribute midle = abute as FieldAttribute;
                        cmdtxt += midle.Fields + ",";
                        object obj = prs.GetGetMethod().Invoke(types, null);
                        if (midle.Dbtype == DbType.Int32)
                            cmdparVar += obj + ",";
                        else
                            cmdparVar += "‘" + obj + "‘,";
                    }
                }
            }
            cmdparVar = cmdparVar.Substring(0, cmdparVar.Length - 1);
            cmdtxt = cmdtxt.Substring(0, cmdtxt.Length - 1) + ")";return cmdtxt;
        }
    }
}

由于我使用窗口程序测试,没有设置测试结果的显示。可以将程序使用控制台实现,将cmdparVar和cmdtxt显示出来。

断点运行可以看到

cmdparVar值:‘aw12311‘,‘123‘,‘aw‘,‘武汉‘,1,‘2018/8/18 16:43:17‘,1,‘19900114‘
cmdtxt值:insert into Consumers(ConsumerID,ConsumerPwd,ConsumerName,UserCity,popedom,addDataTime,Sex,BirthTime)利用Type类型读取到了传入程序集中的变量值。

程序结构分析:Program为程序入口UserInf为将要被反射的类:自定义了一个类属性“Table”,Table类属性附加了一个参数。自定义了变量属性“Field”,Field变量属性附加了3个参数。自定义特性类TableAttribute:对UserInf的类属性“Table”重新构建并获取自定义附加参数。自定义特性类FieldAttribute:对UserInf的变量属性“Field”重新构建并获取自定义附加参数。
程序过程分析:一、入口程序往UserInf的各个变量进行赋值。二、将UserInf传入模板类DateIsTableAttribute,模板类DateIsTableAttribute实现用Type反射UserInf属性。

以下进行DateIsTableAttribute详细解析:
    public class DateIsTableAttribute<T>  //实例化模板类DateIsTableAttribute时,传入T类型
    {
        public string insertDate(T types) //用传入T类型新建types变量
        {
            string cmdtxt = "insert into ";
            string cmdparVar = null;
            Type userAttu = types.GetType(); //获取types的类型(即传入的T类型)的当前实例传给Type类型userAttu,即反射的定义
            TableAttribute tables = (TableAttribute)userAttu.GetCustomAttributes(false)[0];//获取已实例化Type类型userAttu中的直接结点并调用派生自attribute的类TableName(传入为自定义的特性)        //并强制转换为TableAttribute类型        //转换成TableAttribute类型是为了更好调用自定义的附加参数,比如下面tables的TableName值。
            cmdtxt += tables.TableName + "(";
            PropertyInfo[] info = userAttu.GetProperties();//获取传入的当前实例中的所有公共属性
            foreach (PropertyInfo prs in info)//遍历所有带有attribute公共属性的元数据变量
            {
                object[] attu = prs.GetCustomAttributes(false);//获取此元数据中派生自Attribute类的结点
                foreach (Attribute abute in attu)//遍历元数据中的自定义结点
                {
                    if (abute is FieldAttribute)//若为Field结点
                    {
                        FieldAttribute midle = abute as FieldAttribute;//强制转换当前attibute属性
                        cmdtxt += midle.Fields + ",";//读取属性值
                        object obj = prs.GetGetMethod().Invoke(types, null);
                        if (midle.Dbtype == DbType.Int32)
                            cmdparVar += obj + ",";
                        else
                            cmdparVar += "‘" + obj + "‘,";
                    }
                }
            }
            cmdparVar = cmdparVar.Substring(0, cmdparVar.Length - 1);
            cmdtxt = cmdtxt.Substring(0, cmdtxt.Length - 1) + ")";return cmdtxt;
        }
    }
}

用到的几个函数接口:
types.GetType():获取types当前实例的Type
Type.GetCustomAttributes(false)[0] :获取Type类型参数第一个自定义特性结点,返回为自定义特性结点的特征值,比如名称、类型、长度等
Type.GetCustomAttributes(false) 获取Type类型参数所有自定义特性结点,返回为所有自定义特性结点的特征值(比如名称、类型、长度等)组,示例中将返回的自定义特征值强制转换为自定义特性类
链接:https://msdn.microsoft.com/zh-cn/library/system.type.getcustomattributes.aspx
TableAttribute或FieldAttribute,可以更方便读取其中的自定义附加参数
Type.GetProperties() 返回当前Type的所有公共属性链接:https://technet.microsoft.com/zh-cn/windowsserver/1zkfcy34
PropertyInfo.GetGetMethod() 返回此属性公共get访问器
链接:https://technet.microsoft.com/zh-cn/windowsserver/1zkfcy34Method().Invoke(obj, null);反射执行该类型示例方法,obj为方法所属类型实例http://blog.sina.com.cn/s/blog_976ba8a501010y5k.html

延伸:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]https://blog.csdn.net/honey199396/article/details/51316754

typeof(Animal).IsAssignFrom(typeof(Dog)) 他返回true的条件是 Dog类直接或间接的实现了Animal类;继承也可以

typeof(Dog).IsSubClassOf(typeof(Animal)) 他返回true的条件是Dog类是Animal的子类


 

原文地址:https://www.cnblogs.com/tangtangde12580/p/9497856.html

时间: 2025-02-01 23:45:04

小白详细解析C#反射特性实例的相关文章

【智能算法】粒子群算法(Particle Swarm Optimization)超详细解析+入门代码实例讲解

喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 算法起源 粒子群优化算法(PSO)是一种进化计算技术(evolutionary computation),1995 年由Eberhart 博士和kennedy 博士提出,源于对鸟群捕食的行为研究 .该算法最初是受到飞鸟集群活动的规律性启发,进而利用群体智能建立的一个简化模型.粒子群算法在对动物集群活动行为观察基础上,利用群体中的个体对信息的共享使整个群体的运动在问题求解空间中产生从无序到有序的演化过程,从而获得最优解.

【转】UML中的几种关系详细解析

UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现 类与类图 1) 类(Class)封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性.操作.关系的对象集合的总称. 2) 在系统中,每个类具有一定的职责,职责指的是类所担任的任务,即类要完成什么样的功能,要承担什么样的义务.一个类可以有多种职责,设计得好的类一般只有一种职责,在定义类的时候,将类的职责分解成为类的属性和操作(即方法). 3) 类的属性即类的数据职责,类的操作即类的行为职责 一.依赖关系(Dependence) 依

Java当中的堆与栈详细解析

总结第一句话:Java语言使用内存的时候,栈内存主要保存以下内容:基本数据类型和对象的引用,而堆内存存储对象,栈内存的速度要快于堆内存.总结成一句话就是:引用在栈而对象在堆. Java疯狂讲义的一段对话作为开场白. 一个问题:为什么有栈内存和堆内存之分? 答:当一个方法执行时,每个方法都会简历自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁.因此,所有在方法中创建一个对象时,这个对象将被保存到运行时数据区中,以便利用(因为对象的创建成

Mahout机器学习平台之聚类算法详细剖析(含实例分析)

第一部分: 学习Mahout必须要知道的资料查找技能: 学会查官方帮助文档: 解压用于安装文件(mahout-distribution-0.6.tar.gz),找到如下位置,我将该文件解压到win7的G盘mahout文件夹下,路径如下所示: G:\mahout\mahout-distribution-0.6\docs 学会查源代码的注释文档: 方案一:用maven创建一个mahout的开发环境(我用的是win7,eclipse作为集成开发环境,之后在Maven Dependencies中找到相应

java类生命周期详细解析

(一)详解java类的生命周期 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你“怎样做”,但至于“为什么这样做”却不多说,所以造成大家在基础和原理方面的知识比较匮乏,所以笔者今天就斗胆来讲一下这个问题,权当抛砖引玉,希望对在这个问题上有疑惑的朋友有所帮助,文中有说的不对的地方,也希望各路高手前来指正. 首先来了解一下jvm(java虚拟机)

单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式

单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式 一 表结构如下:  MySQL  5.5.30  5.6.20 版本, 表大概有815万行 CREATE TABLE t_audit_operate_log (  Fid bigint(16) AUTO_INCREMENT,  Fcreate_time int(10) unsigned NOT NULL DEFAULT '0',  Fuser varchar(50) DEFAULT '',  Fip bigint

Android AsyncTask 详细解析

结构 继承关系 public abstract class AsyncTask extends Object java.lang.Object android.os.AsyncTask<Params, Progress, Result> 类概述 AsyncTask能够适当地.简单地用于 UI线程. 这个类不需要操作线程(Thread)就可以完成后台操作将结果返回UI. 异步任务的定义是一个在后台线程上运行,其结果是在 UI线程上发布的计算. 异步任务被定义成三种泛型类型: Params,Pro

JFinal 源码超详细解析之DB+ActiveRecord

我记得以前有人跟我说,"面试的时候要看spring的源码,要看ioc.aop的源码"那为什么要看这些开源框架的源码呢,其实很多人都是"应急式"的去读,就像读一篇文章一下,用最快的速度把文章从头到尾读一遍,那结果就是当你读完它,你也不清楚它讲了一个什么故事,想表达什么. 一个优秀的架构的源码我认为就好像一本名著一样,你的"文学"水平越高,你就越能读出作者设计的精妙之处.一篇源码在你不同水平的时候,能读出不同的东西,因此,我觉得优秀的框架的源码是经久

(干货) Android Volley框架源码详细解析

前言 经常接触Android网络编程的我们,对于Volley肯定不陌生,但我们不禁要问,对于Volley我们真的很了解吗?Volley的内部是怎样实现的?为什么几行代码就能快速搭建好一个网络请求?我们不但要知其然,也要知其所以然,抱着这样的目的,本文主要详细讲述Volley的源码,对内部流程进行详细解析. Part 1.从RequestQueue说起 (1)还记得搭建请求的第一步是什么吗?是新建一个请求队列,比如说这样: RequestQueue queue = Volley.newReques