使用反射简化日常操作
做了这么长时间的开发,书写的代码最无趣,最无聊,而又没有什么价值,却不能不做的是什么?应该就如棉棉讲的,为对象或控件进行赋值的部分了。如:
ddlRecoMember.Text = bean.fd_Key_RecoMemberID.ToString();
txtRecoSort.Text = bean.fd_Key_RecoSort.ToString();
txtRecoStartTime.Text = bean.fd_Key_RecoStartTime.ToString("yyyy-MM-dd");
txtRecoEndTime.Text = bean.fd_Key_RecoEndTime.ToString("yyyy-MM-dd");
txtRecoLink.Text = bean.fd_Key_RecoLink;
这里重复进行着无价值的劳动,使你不能专心的从事更有价值和核心的工作,那么我们可以不可以避免或减少这类型代码的编写?
其实可以的。
如果进行总结,我们可以发现,虽然强大的ASP.NET架构为我们提供了一大堆完美的控件,但,在做编辑功能时,如果没有特殊需求,我们总是在重复使用特定的一小部分,像:TextBox、DropDownList、ListBox、CheckBox、CheckBoxList、RadioButton、RadioButtonList和TextBox。而实体类属性的数据类型就更简单了,像String,DateTime,Boolean和Int32等。
运用强大的反射功能,我们可以做到把这种代码书写的次数减至最少。
反射是.NET提供的一种用在运行时刻动态获得程序集的元数据、类信息等资源,可以获得对象接口,动态创建对象,执行相关代码的机制。
现在准备使用它来完成这些重复劳动。为了从对象中获取或设置属性的值,我们需要运用下面的代码得到属性列表:
Type t = obj.GetType();//obj是Object类型可为任意类型 PropertyInfo[] props = t.GetProperties();
下面我们定义一个根据属性推断出控件的ID:
public virtual string GetControlID(PropertyInfo prop)
{
string shortName = (prop.Name.Length > 0 && (prop.Name.ToLower().StartsWith("fd") || prop.Name.ToLower().StartsWith("fa"))) ? prop.Name.Substring(6) : prop.Name;
string startChar = "txt";
if (prop.PropertyType == typeof(bool))
{
startChar = "chb";
}
return startChar + shortName;
}
下面的方法是,从一个控件集合中填充对象:
public virtual void FillByControl(Object obj, Control ctrl)//ctrl是包含有需要赋值的控件
{
if (obj == null) return;
String key = null;
Object val = null;
Control findCtrl = null;
PropertyInfo[] props = GetProperties(obj);
foreach (PropertyInfo info in props)
{
key = GetControlID(info);
findCtrl = ctrl.FindControl(key);
if (findCtrl != null)
{
val = GetValue(findCtrl);
if (info.PropertyType.Name == "Nullable`1")//如果是Nullable类型
{
Type baseType = Nullable.GetUnderlyingType(info.PropertyType);
if (!String.IsNullOrEmpty(string.Format("{0}", val)))
{
info.SetValue(obj, Convert.ChangeType(val, baseType), null);
}
}
else
{
if (!info.PropertyType.IsValueType || !String.IsNullOrEmpty(string.Format("{0}", val)))
{
info.SetValue(obj, Convert.ChangeType(val, info.PropertyType), null);
}
}
}
}
}
下面的方法与上面的相反,是从对象中取值来初始化控件
public virtual void Fill2Control(Object obj, Control ctrl)
{
Object val = null;
String ctrlId = null;
Control findCtrl = null;
PropertyInfo[] props = GetProperties(obj);
foreach (PropertyInfo prop in props)
{
val = prop.GetValue(obj, null);
if (val != null)//如果不为空
{
ctrlId = GetControlID(prop);
findCtrl = ctrl.FindControl(ctrlId);
if (findCtrl != null)
{
SetValue(findCtrl, val);
}
}
}
}
运用上面的代码片段,就可以帮助我们完成对从对象取值赋值控件和从控件取值赋值对象的绝大部分代码了。从上面的代码片断中,我写出了对象与控件间的赋值操作。如果想实现从查询变量中初始化对象也是可以按类似思路实现的。下面是这个类的完整代码:
using System;
using System.Text;
using System.Web.UI;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Reflection;
using System.Collections.Specialized;
namespace Guaik.Web
{
///
/// 用于对象的填充,由Guaik.com提供
///
public class Porter
{
#region 默认值
///
/// 默认的日期
///
public readonly static DateTime DefaultDateTime = new DateTime(1900, 1, 1);
///
/// 从QueryString中读取Boolean类型为true的值
///
public readonly static String BooleanValue = "on";
#endregion
#region 数据缓存
private static Hashtable htProperties = new Hashtable();
///
/// 得到对象的属性列表
///
///
///
public static PropertyInfo[] GetProperties(Object obj)
{
if( obj == null ) return null;
Type t = obj.GetType();
if (!htProperties.ContainsKey(t.FullName))
{
htProperties[t.FullName] = t.GetProperties();
}
return (PropertyInfo[])htProperties[t.FullName];
}
#endregion
#region 得到键
///
/// 得到查询字符串的键
///
///
///
public virtual string GetQueryStringKey(PropertyInfo prop)
{
if (prop.Name.Length > 6 && prop.Name.ToLower().StartsWith("fd"))
{
return prop.Name.Substring(6);
}
else
{
return prop.Name;
}
}
///
/// 得到控件的ID
///
///
///
public virtual string GetControlID(PropertyInfo prop)
{
string shortName = (prop.Name.Length > 0 && (prop.Name.ToLower().StartsWith("fd") || prop.Name.ToLower().StartsWith("fa"))) ? prop.Name.Substring(6) : prop.Name;
string startChar = "txt";
if (prop.PropertyType == typeof(bool))
{
startChar = "chb";
}
return startChar + shortName;
}
#endregion
#region 数据填充
///
/// 将过滤条件填充到控件下
///
///
public virtual void Fill2Control(Object obj, Control ctrl)
{
Object val = null;
String ctrlId = null;
Control findCtrl = null;
PropertyInfo[] props = GetProperties(obj);
foreach (PropertyInfo prop in props)
{
val = prop.GetValue(obj, null);
if (val != null)//如果不为空
{
ctrlId = GetControlID(prop);
findCtrl = ctrl.FindControl(ctrlId);
if (findCtrl != null)
{
SetValue(findCtrl, val);
}
}
}
}
///
/// 从QueryString集合中填充
///
public virtual void FillByNameValueCollection(Object obj, NameValueCollection valueCollection)
{
if (valueCollection == null) return;
String key = null;
PropertyInfo[] props = GetProperties(obj);
foreach (PropertyInfo info in props)
{
key = GetQueryStringKey(info);
if (!String.IsNullOrEmpty(valueCollection[key]))
{
if (info.PropertyType == typeof(bool) && valueCollection[key] == BooleanValue)
{
info.SetValue(obj, (valueCollection[key] == BooleanValue ? true : false), null);
}
else
{
if (info.PropertyType.Name == "Nullable`1")
{
Type baseType = Nullable.GetUnderlyingType(info.PropertyType);
info.SetValue(obj, Convert.ChangeType(valueCollection[key], baseType), null);
}
else
{
info.SetValue(obj, Convert.ChangeType(valueCollection[key], info.PropertyType), null);
}
}
}
}
}
///
/// 设置控件的值
///
///
///
public virtual void SetValue(Control ctrl, Object val)
{
if (ctrl is ITextControl)//TextBox, DropDownList, ListBox...
{
((ITextControl)ctrl).Text = val.ToString();
}
else if (ctrl is ICheckBoxControl)//CheckBox
{
((ICheckBoxControl)ctrl).Checked = (bool)val;
}
}
///
/// 得到控件的值
///
///
///
public virtual Object GetValue(Control ctrl)
{
object val = null;
if (ctrl is ITextControl)//TextBox, DropDownList, ListBox...
{
val = ((ITextControl)ctrl).Text;
}
else if (ctrl is ICheckBoxControl)//CheckBox
{
val = ((ICheckBoxControl)ctrl).Checked;
}
return val;
}
public virtual void FillByControl(Object obj, Control ctrl)
{
if (obj == null) return;
String key = null;
Object val = null;
Control findCtrl = null;
PropertyInfo[] props = GetProperties(obj);
foreach (PropertyInfo info in props)
{
key = GetControlID(info);
findCtrl = ctrl.FindControl(key);
if (findCtrl != null)
{
val = GetValue(findCtrl);
if (info.PropertyType.Name == "Nullable`1")//如果是Nullable类型
{
Type baseType = Nullable.GetUnderlyingType(info.PropertyType);
if (!String.IsNullOrEmpty(string.Format("{0}", val)))
{
info.SetValue(obj, Convert.ChangeType(val, baseType), null);
}
}
else
{
if (!info.PropertyType.IsValueType || !String.IsNullOrEmpty(string.Format("{0}", val)))
{
info.SetValue(obj, Convert.ChangeType(val, info.PropertyType), null);
}
}
}
}
}
#endregion
}
}
运用这个代码的示例也非常简单,假设有类User,需要为divMain下的控件赋值,可以这样做:
User bean = new User(); Porter porter = new Porter(); porter.FillByControl(bean, divMain);//从divMain下的控件初始化bean对象。 //porter.File2Control(bean, divMain);//把bean对象的值赋值给divMain下的控件
在这里烦人的赋值语句变得简单了。
如何让上面的代码支持更多新控件?实现很简单,将新控件继承自ITextControl就可以了。
对于那些不能支持的控件,只有针对它写一个赋值语句就可以。
相关文章:
使用双向绑定动态编辑任意对象内容(一)
使用双向绑定动态编辑任意对象内容(二)
- 1. 使用反射简化日常操作2009-06-25





