代码改变世界

ASP.NET中使用反射将控件值与实体值相互映射

2008-05-24 16:25  xiaosonl  阅读(2930)  评论(6编辑  收藏  举报

在ASP.NET中, 我们要获取控件的值, 或是给控件赋值, 一般都是Control.Property = Entity.Property, Entity.Property = Control.Property.
如果控件太多,这样写就显的繁琐,而且容易出错.
这种情况下, 使用反射, 把符合控件名和实体属性名相同的值相互映射,只要一行代码就可以完成操作了.

来看主要的两个方法签名:

        /// <summary>
        
/// 将控件的值映射到实体
        
/// </summary>
        
/// <param name="container">映射的控件的容器控件</param>
        
/// <param name="obj">实体</param>
        
/// <param name="isContainChildren">是否遍历子控件</param>
        
/// <param name="controlIDFormat">控件ID的格式, {0}表示值的名称</param>
        
/// <param name="customMaps">自定义的[属性-值]映射规则, Key=控件属性名, Value=属性类型</param>

        public static void ControlsToEntity(Control container, object entity, bool isContainChildren, string controlIDFormat, params KeyValuePair<string, Type>[] customMaps)

        
/// <summary>
        
/// 将实体属性值映射到控件
        
/// </summary>
        
/// <param name="entity">实体</param>
        
/// <param name="container">映射的控件的容器控件</param>
        
/// <param name="isContainChildren">是否遍历子控件</param>
        
/// <param name="idFormat">控件ID的格式, {0}表示值的名称</param>
        
/// <param name="customMaps">自定义的[属性-值]映射规则, Key=控件属性名, Value=属性类型</param>

        public static void EntityToControls(object entity, Control container, bool isContainChildren, string controlIDFormat, params KeyValuePair<string, Type>[] customMaps)


然后是测试用例, 不太容易理解, 见谅:

public class Entity
    
{
        
public bool CheckBoxControl getset; }
        
public string TextBoxControl getset; }
        
public string LabelControl getset; }
        
public object OtherControl getset; }
        
public int DropDownListControl getset; }
        
public int? ListBoxControl getset; }
        
public string CustomControl getset; }
    }


    
public class Custom : Control
    
{
        
public string CustomProperty getset; }
    }


    [TestClass()]
    
public class ControlMappingTest
    
{
        [TestMethod()]
        
public void TestEntityControlsMapping()
        
{
            Entity entity 
= new Entity()
            
{
                CheckBoxControl 
= true,
                ListBoxControl 
= 1,
                DropDownListControl 
= 1,
                LabelControl 
= "LabelValue",
                TextBoxControl 
= "TextBoxValue",
                CustomControl 
= "CustomValue",
            }
;

            
控件

            
bool isContainChildren = true;

            
//实体 -> 控件
            KeyValuePair<string, Type> customMaps = new KeyValuePair<string, Type>("CustomProperty"typeof(string));
            ControlMapping.EntityToControls(entity, container, isContainChildren, 
"_{0}", customMaps);

            Assert.AreEqual(entity.CheckBoxControl, CheckBoxControl.Checked);
            Assert.AreEqual(entity.TextBoxControl, TextBoxControl.Text);
            Assert.AreEqual(entity.LabelControl, LabelControl.Text);
            Assert.AreEqual(entity.DropDownListControl, Converters.ChangeType
<int>(DropDownListControl.SelectedValue));
            Assert.AreEqual(entity.ListBoxControl, Converters.ChangeType
<int>(ListBoxControl.SelectedValue));
            Assert.AreEqual(entity.CustomControl, CustomControl.CustomProperty);

            
//控件 -> 实体
            entity = new Entity();
            ControlMapping.ControlsToEntity(container, entity, isContainChildren, 
"_{0}",  customMaps);

            Assert.AreEqual(entity.CheckBoxControl, CheckBoxControl.Checked);
            Assert.AreEqual(entity.TextBoxControl, TextBoxControl.Text);
            Assert.AreEqual(entity.LabelControl, LabelControl.Text);
            Assert.AreEqual(entity.DropDownListControl, Converters.ChangeType
<int>(DropDownListControl.SelectedValue));
            Assert.AreEqual(entity.ListBoxControl,Converters.ChangeType
<int>( ListBoxControl.SelectedValue));
            Assert.AreEqual(entity.CustomControl, CustomControl.CustomProperty);
        }

     }


之后我又有了新的想法, 就是在中间加入一层Hash值, 这样就可以实现UI层的解藕, 即Control <=> Hash <=> Entity.
暂时只实现了Control <=> Hash :

        /// <summary>
        
/// 将控件值映射到Hash表
        
/// </summary>
        
/// <param name="container">映射控件的容器控件</param>
        
/// <param name="isContainChildren">是否遍历子控件</param>
        
/// <param name="customMaps">自定义的控件属性</param>

        public static Dictionary<stringobject> ControlsToHash(Control container, bool isContainChildren, params string[] customProperties)

        
/// <summary>
        
/// 将Hash表值映射到控件
        
/// </summary>
        
/// <param name="hash">Hash键值对</param>
        
/// <param name="container">映射控件的容器控件</param>
        
/// <param name="isContainChildren">是否遍历子控件</param>

        public static void HashToControls(Dictionary<stringobject> hash, Control container, bool isContainChildren, params string[] customProperties)


测试用例:

        [TestMethod]
        
public void ControlsToHashAndHashToControlsTest()
        
{
            
测试数据准备

            Dictionary
<stringobject> expectedHash = new Dictionary<stringobject>();
            expectedHash.Add(
"c_UserID""1");
            expectedHash.Add(
"c_UserName""Xiaosonl");
            expectedHash.Add(
"c_Age""1");
            expectedHash.Add(
"c_IsUsed""True");
            expectedHash.Add(
"c_RoleID""2");

            ControlMapping.HashToControls(expectedHash, container, 
true);

            Dictionary
<stringobject> hash = ControlMapping.ControlsToHash(container, false);
            Assert.AreEqual(
false, hash.SerializeEqual(expectedHash));
            hash 
= ControlMapping.ControlsToHash(container, true);
            Assert.AreEqual(
true, hash.SerializeEqual(expectedHash));
        }


具体实现代码见FastDev.Web.ControlMapping类.
下载FastDev.Web.rar