ASP.NET 中采用 Reflection 机制把页面控件元素和对象联系起来。

类别:Asp 点击:0 评论:0 推荐:

最近在做一个项目,涉及到的实体很多,每个实体都需要做一个用户界面接受用户输入,这样在把实体对象展开到界面控件和从界面控件收集实体属性要写的代码就相当的多,但是这些代码都是简单的get和set操作。
于是我写了一个简单的赋值类:

using System;
using System.Reflection;

/**
 * 文件名:Web\Assigner.cs
 * Copyright(c):http://www.hakatasoft.com
 * 创建人:周树群
 * 日期:2004-10-16 18:45
 * 修改人:
 * 日期:
 * 描述:
 * 版本:1.0
 */
namespace Sce.Common.Web {
 /// <summary>
 /// Assigner 采用 reflection 机制简化了从 Web 页面中的表单中构成对象
 /// 一般情况下:
 /// System.Web.UI.WebControls.TextBox txtMyField1;
 /// System.Web.UI.WebControls.TextBox txtMyField2;
 /// MyObject myObj = new MyObject();
 /// myObj.SetMyField1(txtMyField1.Text);
 /// myObj.SetMyField2(txtMyField2.Text);
 /// 采用 Assigner 来赋值
 /// System.Web.UI.WebControls.TextBox txtMyField1;
 /// System.Web.UI.WebControls.TextBox txtMyField2;
 /// MyObject myObj = new MyObject();
 /// Assigner.Assign(Page.Controls(), "txt", null, myObj, "Set", null);
 /// </summary>
 public class Assigner {

  private static readonly bool DEBUG = false;

  private Assigner() {
  }

  
  #region 支持的类型
  /// <summary>
  /// 一些已知能处理的类型
  /// </summary>
  private static Type[] KnownTypes =
   new Type[]{
         typeof(object),
         typeof(string),
         typeof(double),
         typeof(float),
         typeof(long),
         typeof(int),
         typeof(short),
         typeof(char),
         typeof(byte),
         typeof(bool)
        };

  #endregion

  #region
  /// <summary>
  /// 仅作调试
  /// </summary>
  /// <param name="s"></param>
  private static void log(string s) {
   if (DEBUG) {
    System.IO.StreamWriter sw = new System.IO.StreamWriter("C:\\tmp\\debug.log", true);
    sw.WriteLine(s);
    sw.Close();
   }
  }

  private static void SetParam(object[] var, int index, object theValue, Type type) {
   if (type.Equals(typeof(object))) {
    var[index] = theValue;
   }
   else if(type.Equals(typeof(string))) {
    var[index] = theValue.ToString();
   }
   else if(type.Equals(typeof(double))) {
    var[index] = double.Parse(theValue.ToString().Trim());
   }
   else if(type.Equals(typeof(float))) {
    var[index] = float.Parse(theValue.ToString().Trim());
   }
   else if(type.Equals(typeof(long))) {
    var[index] = long.Parse(theValue.ToString().Trim());
   }
   else if(type.Equals(typeof(int))) {
    var[index] = int.Parse(theValue.ToString().Trim());
   }
   else if(type.Equals(typeof(short))) {
    var[index] = short.Parse(theValue.ToString().Trim());
   }
   else if(type.Equals(typeof(char))) {
    var[index] = char.Parse(theValue.ToString().Trim());
   }
   else if(type.Equals(typeof(byte))) {
    var[index] = byte.Parse(theValue.ToString().Trim());
   }
   else if(type.Equals(typeof(bool))) {
    var[index] = bool.Parse(theValue.ToString().Trim());
   }
   else {
    throw new System.ApplicationException("不支持的数据类型。");
   }
  }

  /// <summary>
  /// 得到具有该名称的最合适的方法
  /// </summary>
  /// <param name="obj"></param>
  /// <param name="methodName"></param>
  /// <param name="onlyType">用来标识参数类型,传入一个null即可</param>
  /// <returns></returns>
  private static System.Reflection.MethodInfo GetOnlyMethodByName(object obj, string methodName, ref Type onlyType) {
   MethodInfo method = null;
   Type objType = obj.GetType();
   Type[] types = new Type[1];
   for (int i = 0; i < KnownTypes.Length; i++) {
    types.SetValue(KnownTypes[i], 0);
    method = objType.GetMethod(methodName, types);
    if (method != null) {
     break;
    }
   }
   onlyType = types[0];
   return method;
  }


  #endregion

 


  #region 把Web控件中的值赋给对象
  /// <summary>
  /// 把Web控件中的值赋值给对象
  /// 遍历给定的控件集合中的控件(包括子控件,跳过不具有指定前缀与后缀的 ID 的控件。),
  /// 并将其值(TextBox.Text, DropDownList.SelectedValue)赋给指定的对象。
  /// 例子:比如我们要把控件txtUsernameTextBox的值赋给user的Username
  /// (obj拥有一个SetUsername(string username)方法),则使用:
  /// Assign(Page.Controls, "txt", "TextBox", user, "Set", null);
  /// 如果user的Username是采用类似下面的写法的:
  /// public string Username {
  ///   get {
  ///     return m_Username;
  ///   }
  ///   set {
  ///    m_Username = value;
  ///  }
  /// }
  /// 那么采用这样的写法:
  /// Sce.Common.Web.Assigner.Assign(Page.Controls, "txt", null, user, "set_", null);
  /// 因为这种getter,setter写法就类似与添加了set_XXX, get_XXX这样的方法。
  /// </summary>
  /// <param name="controls">Web控件集合。</param>
  /// <param name="prefix">控件前缀,没有后缀用null或者""传入。</param>
  /// <param name="suffix">控件后缀,没有后缀用null或者""传入。</param>
  /// <param name="obj">需要赋值的对象。</param>
  /// <param name="setterPrefix">赋值方法前缀,没有后缀用null或者""传入。</param>
  /// <param name="setterSuffix">赋值方法后缀,没有后缀用null或者""传入。</param>
  public static void Assign(System.Web.UI.ControlCollection controls, string prefix, string suffix, System.Object obj, string setterPrefix, string setterSuffix) {
   if (null == prefix) {
    prefix = "";
   }
   if (null == suffix) {
    suffix = "";
   }
   if (null == setterPrefix) {
    setterPrefix = "";
   }
   if (null == setterSuffix) {
    setterSuffix = "";
   }
   System.Collections.IEnumerator myEnum = controls.GetEnumerator();
   string ctrlId, field, methodName;
   object theValue;
   System.Web.UI.Control ctrl;
   Type type = obj.GetType();
   System.Reflection.MethodInfo method = null;
   object[] parameters; // 参数值
   Type[] types; // 参数类型
   while (myEnum.MoveNext()) {
    ctrl = (System.Web.UI.Control) myEnum.Current;
    ctrlId = ctrl.ID;

    if (ctrl.HasControls()) {
     Assign(ctrl.Controls, prefix, suffix, obj, setterPrefix, setterSuffix);
    }
    if(
     ctrlId != null
     &&
     (ctrlId.StartsWith(prefix) || prefix.Length == 0)
     &&
     (ctrlId.EndsWith(suffix) || suffix.Length == 0)
     ) {
     // field
     field = ctrlId.Substring(prefix.Length, ctrlId.Length - prefix.Length - suffix.Length);
     methodName = setterPrefix + field + setterSuffix;
     // types
     types = new Type[1];
     // try to find the only method
     /*
     for (int i = 0; i < KnownTypes.Length; i++) {
      types.SetValue(KnownTypes[i], 0);
      method = type.GetMethod(methodName, types);
      if (method != null) {
       break;
      }
     }
     */
     Type onlyType = null;
     method = GetOnlyMethodByName(obj, methodName, ref onlyType);
     // assign value
     if (method != null) {
      //log(method.ToString());
      // value
      if (ctrl is System.Web.UI.WebControls.TextBox) {
       theValue = ((System.Web.UI.WebControls.TextBox)ctrl).Text;
      }
      else if(ctrl is System.Web.UI.WebControls.DropDownList) {
       theValue = ((System.Web.UI.WebControls.DropDownList)ctrl).SelectedValue;
      }
      else if(ctrl is System.Web.UI.WebControls.CheckBox) {
       theValue = ((System.Web.UI.WebControls.CheckBox)ctrl).Checked;
      }
      else if(ctrl is System.Web.UI.WebControls.CheckBoxList) {
       theValue = ((System.Web.UI.WebControls.CheckBoxList)ctrl).SelectedValue;
      }
      else {
       theValue = "";
      }

      // parameters
      parameters = new object[1];

      if (theValue != null && theValue.ToString().Length != 0) {
       SetParam(parameters, 0, theValue, onlyType);
       method.Invoke(obj, parameters);
      }
     }
    }
   }
  }

  #endregion

  #region 把对象的值赋给Web控件
  /// <summary>
  /// 把对象的值赋值给Web控件
  /// 遍历控件集合中的控件(包括控件的字控件,跳过不具有指定前缀与后缀的控件),把对象的值赋值给控件。
  /// </summary>
  /// <param name="obj">提供值的对象</param>
  /// <param name="getterPrefix">getter前缀</param>
  /// <param name="getterSuffix">getter后缀</param>
  /// <param name="controls">Web控件集合</param>
  /// <param name="prefix">控件ID前缀</param>
  /// <param name="suffix">控件ID后缀</param>
  public static void Assign(System.Object obj, string getterPrefix, string getterSuffix, System.Web.UI.ControlCollection controls, string prefix, string suffix) {
   if (null == prefix) {
    prefix = "";
   }
   if (null == suffix) {
    suffix = "";
   }
   if (null == getterPrefix) {
    getterPrefix = "";
   }
   if (null == getterSuffix) {
    getterSuffix = "";
   }
   System.Collections.IEnumerator myEnum = controls.GetEnumerator();
   Type type = obj.GetType();
   System.Web.UI.Control ctrl;
   System.Reflection.MethodInfo method = null;
   System.Web.UI.WebControls.DropDownList dropDownList;
   System.Web.UI.WebControls.CheckBoxList checkBoxList;
   object retObj;
   string ret, ctrlId, field, methodName;
   while (myEnum.MoveNext()) {
    ctrl = (System.Web.UI.Control) myEnum.Current;
    ctrlId = ctrl.ID;
    if (ctrl.HasControls()) {
     Assign(obj, getterPrefix, getterSuffix,ctrl.Controls, prefix, suffix);
    }
    if(
     ctrlId != null
     &&
     (ctrlId.StartsWith(prefix) || prefix.Length == 0)
     &&
     (ctrlId.EndsWith(suffix) || suffix.Length == 0)
     ) {
     // field
     field = ctrlId.Substring(prefix.Length, ctrlId.Length - prefix.Length - suffix.Length);
     methodName = getterPrefix + field + getterSuffix;
     // try to find the only method
     method = type.GetMethod(methodName);
     if (method != null) {
      retObj = method.Invoke(obj, new object[0]);
      ret = (retObj == null ? "" : retObj.ToString());
      if (ctrl is System.Web.UI.WebControls.TextBox) {
       ((System.Web.UI.WebControls.TextBox)ctrl).Text = ret.ToString();
      }
      else if(ctrl is System.Web.UI.WebControls.CheckBox) {
       ((System.Web.UI.WebControls.CheckBox)ctrl).Checked = bool.Parse(ret);
      }
      else if(ctrl is System.Web.UI.WebControls.DropDownList) {
       dropDownList = (System.Web.UI.WebControls.DropDownList)ctrl;
       if (dropDownList.Items.FindByValue(ret) != null) {
        dropDownList.SelectedValue = ret;
       }
      }
      else if(ctrl is System.Web.UI.WebControls.CheckBoxList) {
       checkBoxList = (System.Web.UI.WebControls.CheckBoxList)ctrl;
       if (checkBoxList.Items.FindByValue(ret) != null) {
        checkBoxList.SelectedValue = ret;
       }
      }
      //ctrl.DataBind();
     }
    }
   }
  }

  #endregion

 }
}

对于其中的类型处理我觉得不是很好,因为我对C#还不是很熟悉,我参与使用ASP.NET开发的项目还是第一次,所以一些肯定还有相当大的改进的余地。
另外这种思想当然也可以用在其他的语言上,不一定是基于C#的ASP.NET。

本文地址:http://com.8s8s.com/it/it8304.htm