C#利用反射为属性赋值

作为一个普通程序员,相信每个人都曾经给某个model编写插入、修改方法时因为这个model的属性太多而吐槽过,当然聪明的使用例如动软代码生成器这样软件的你除外。这个时候我们一般是吐槽归吐槽,报怨归报怨,之后还不是得老老实实地一个属性一个属性的赋值。。

而一个偶然的机会看到dtcms5.0发布,无意间看到它竟然首先(当然是仅在我自己的认知中,这一发现让我对程序世界的博大精深充满了期待与敬畏)使用了一个神奇的功能,让我们程序员彻底解脱了双手,再也不用一边眼花缭乱一边生产代码了。它就是——反射原理。

什么是反射?

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

反射是.Net中获取运行时类型信息的方式,.Net的应用程序由:程序集(Assembly)、模块(Module)、类型(class)组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息。

Assembly类定义和加载程序集,获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。
Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。
Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或 GetConstructor方法来调用特定的构造函数。
MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

反射的作用:

1、可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型
2、应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3、反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。

那么反射如何使用呢,以下是整理的使用反射机制的实例可以作为参考:

反射实例

获取常量属性名及属性值

Type t = typeof(SpiderErrorNoConstant);
FieldInfo[] fis=t.GetFields();  // 注意,这里不能有任何选项,否则将无法获取到const常量
foreach (var fieldInfo in fis) 
{
	Console.WriteLine(fieldInfo.Name  + "=" + fieldInfo.GetRawConstantValue().ToString()); 
}

获取变量属性名及属性值

1.首先要定义一个model类即如下 floor.cs,这个是不可或缺的,也是使用反射机制的要本。

using System;
namespace Model
{
    /// <summary>
    /// floor:实体类(属性说明自动提取数据库字段的描述信息)
    /// </summary>
    [Serializable]
    public partial class floor
    {
        public floor()
        { }
        #region Model
        private int _id;
        private string _title;
        private int? _sort_id;
        private int? _is_lock;
        /// <summary>
        /// 楼层id
        /// </summary>
        public int id
        {
            set { _id = value; }
            get { return _id; }
        }
        /// <summary>
        /// 楼层名称
        /// </summary>
        public string title
        {
            set { _title = value; }
            get { return _title; }
        }
        /// <summary>
        /// 排序
        /// </summary>
        public int? sort_id
        {
            set { _sort_id = value; }
            get { return _sort_id; }
        }
        /// <summary>
        /// 是否开启
        /// </summary>
        public int? is_lock
        {
            set { _is_lock = value; }
            get { return _is_lock; }
        }
        #endregion Model

    }
}

2.在数据访问层中即DAL中就可以使用反射来为属性赋值与取值。如下:

using System;
using System.Data;
using System.Text;
using System.Data.SqlClient;
using HWcms.DBUtility;
using System.Reflection;
using System.Collections.Generic;

namespace HWcms.DAL
{
    /// <summary>
    /// 数据访问类:floor
    /// </summary>
    public partial class floor
    {
        private string databaseprefix; //数据库表名前缀
        public floor(string _databaseprefix)
        {
            databaseprefix = _databaseprefix;
        }
        /// <summary>
        /// 增加一条数据
        /// </summary>
        public int Add(HWcms.Model.floor model)
        {
            StringBuilder strSql = new StringBuilder();
            StringBuilder str1 = new StringBuilder();//数据字段
            StringBuilder str2 = new StringBuilder();//数据参数
            //利用反射获得属性的所有公共属性
            PropertyInfo[] pros = model.GetType().GetProperties();
            List<SqlParameter> paras = new List<SqlParameter>();
            strSql.Append("insert into " + databaseprefix + "floor(");
            foreach(PropertyInfo pi in pros)
            {
	            //如果不是主键则追加sql字符串
                if(!pi.Name.Equals("id"))
                {
	                //判断属性值是否为空
                    if(pi.GetValue(model, null)!=null)
                    {
                        str1.Append(pi.Name + ",");//拼接字段
                        str2.Append("@" + pi.Name + ",");//声明参数
                        paras.Add(new SqlParameter("@" + pi.Name, pi.GetValue(model, null)));//对参数赋值
                    }
                }
            }
            strSql.Append(str1.ToString().Trim(','));
            strSql.Append(") values (");
            strSql.Append(str2.ToString().Trim(','));
            strSql.Append(") ");
            strSql.Append(";select @@IDENTITY;");
            object obj = DbHelperSQL.GetSingle(strSql.ToString(), paras.ToArray());
            if(obj==null)
            {
                return 0;
            }
            else
            {
                return Convert.ToInt32(obj);
            }
        }
        /// <summary>
        /// 更新一条数据
        /// </summary>
        public bool Update(HWcms.Model.floor model)
        {
            StringBuilder strSql = new StringBuilder();
            StringBuilder str1 = new StringBuilder();
            //利用反射获得属性的所有公共属性
            PropertyInfo[] pros = model.GetType().GetProperties();
            List<SqlParameter> paras = new List<SqlParameter>();
            strSql.Append("update " + databaseprefix + "floor set ");
            foreach(PropertyInfo pi in pros)
            {
	            //如果不是主键则追加sql字符串
                if(!pi.Name.Equals("id"))
                {
	                //判断属性值是否为空
                    if(pi.GetValue(model,null)!=null)
                    {
	                    str1.Append(pi.Name + "=@" + pi.Name + ",");
	                    paras.Add(new SqlParameter("@" + pi.Name, pi.GetValue(model, null)));
                    }
                }
            }
            strSql.Append(str1.ToString().Trim(','));
            strSql.Append(" where id=@id");
            paras.Add(new SqlParameter("@id", model.id));
            return DbHelperSQL.ExecuteSql(strSql.ToString(), paras.ToArray()) > 0;
        }
        /// <summary>
        /// 得到一个对象实体
        /// </summary>
        public HWcms.Model.floor GetModel(int id)
        {
            StringBuilder strSql = new StringBuilder();
            StringBuilder str1 = new StringBuilder();
            Model.floor model = new Model.floor();
            PropertyInfo[] pros = model.GetType().GetProperties();
            foreach(PropertyInfo p in pros)
            {
                str1.Append(p.Name + ",");
            }
            strSql.Append("select top 1 " + str1.ToString().Trim(','));
            strSql.Append(" from " + databaseprefix + "floor");
            strSql.Append(" where id=@id");
            SqlParameter[] param = {
                new SqlParameter("@id", SqlDbType.Int, 4)
            };
            param[0].Value = id;
            DataTable dt = DbHelperSQL.Query(strSql.ToString(), param).Tables[0];
            if(dt.Rows.Count>0)
            {
                return DataRowToModel(dt.Rows[0]);
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 将对象转换为实体
        /// </summary>
        public HWcms.Model.floor DataRowToModel(DataRow row)
        {
            HWcms.Model.floor model = new HWcms.Model.floor();
            if (row != null)
            {
	            //利用反射获取属性的所有公共属性
                Type modelType = model.GetType();
                for(int i=0;i<row.Table.Columns.Count;i++)
                {
	                //查找实体是否存在列表相同的公共属性
                    PropertyInfo proInfo = modelType.GetProperty(row.Table.Columns[i].ColumnName);
                    if(proInfo!=null&& row[i]!=DBNull.Value)
                    {
	                    //用索引值设置属性值
                        proInfo.SetValue(model, row[i], null);
                    }
                }
            }
            return model;
        }
    }
}

刚刚使用了反射,感觉这个功能真的很走心,为了更多的了解反射,也去搜索了很多反射很多相关的知识,在一篇文章中看到反射并不是万能的,使用反射反而会降低程序的性能,导航速度非常慢,这一下了解让我意识到任何方法的优劣并不能以偏概全,可以适当的使用了解,但不能太过于依赖。以下是看来的关于反射的性能方面的知识以助了解:

反射的性能:
1、现实应用程序中很少有应用程序需要使用反射类型
2、使用反射动态绑定需要牺牲性能
3、有些元数据信息是不能通过反射获取的

使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:

1、通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。
2、通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。
3、通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些。

这是一篇如何利用委托优化反射的文章:
http://www.cnblogs.com/xinaixia/p/5777886.html

PS:利用反射机制实现添加功能时,一定要记得对那些DateTime类型的字段进行初始化,否则会报错。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值