首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 利用反射减少if等重复代码,听听大家的意见 [已结贴,结贴人:sunchaohuang]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 10:30:06 楼主
    [code=C#]在项目开发中难免存在大量的判断语句,特别是在频繁使用ajax与服务器交互的项目中,if,switch等判断语句的使用量是相当大的,为了在项目开发过程减少这类代码的使用量,我使用了反射。

    该页面是Ajax回发处理的公共页面Process.aspx,由此可见这样重复写代码是十分令人厌恶的:
    switch (Request["action"].ToString())
            {
                case "city":
                    InitCity(iType);
                    break;
                case "city1":
                    InitCity1(iType);
                    break;
                case "city2":
                    InitCity2(iType);
                    break;
                case "ChangeEnter":
                    ChangeEnter();
                    break;
                case "UpdateTime":

                    UpdateTime();
                    break;
                case "FeedbackList":
                    FeedbackList();
                    break;
                case "MessageBoardList":
                    MessageBoardList();
                    break;
                case "WantsList":
                    WantsList();
                    break;
                case "iStateChange":
                    iStateChange();
                    break;
                case "seliWorkType":
                    seliWorkType();
                    break;
                case "Del":
                    Del();
                    break;
                case "jobwill":
                    SaveJobWill();
                    break;
                case "callmode":
                    SaveCallMode();
                    break;
                case "goodskill":
                    SaveGoodSkill();
                    break;
                case "state":
                    SaveState();
                    break;
                case "wantwork":
                    WantWork();
                    break;
                case "Resumes":
                    Resumes();
                    break;
            }
    为了减少大家在开发过程中重复写类似的代码,这里使用了反射。
    下面提供一个例子,全国省份的二级联动菜单:


    1.首先创建一个专门处理Ajax回发事件的类库
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Data;
    using System.Data.SqlClient;
    using DBUtility;

    namespace Re_Demo.AjaxProcess
    {
        public class City
        {
            StringBuilder strHtml = new StringBuilder();

            #region测试
            public string Test()
            {
                return "hello world!";

            }
            #endregion

            #region测试
            public string Test_111(int a,string b)
            {
                return a.ToString() + b;

            }
            #endregion

            #region测试asdasdasd
            public string Test_111r3r43()
            {
                return "hello world!aaabbfredbdrfa";

            }
            #endregion
           
            #region根据省份填充市
            /// <summary>
            ///填充市
            /// </summary>
            /// <param name="iParent">省份ID </param>
            /// <returns> </returns>
            public string InitCity(int iParent)
            {
                using (SqlDataReader rdr = SqlHelp.ExecuteReader(SqlHelp.ConnectionStringLocalTransaction, CommandType.Text, "select AutoCode,sName from S_City where iParentID=" + iParent, null))
                {
                    strHtml.Append("城市: <select id='ddlCity'>");
                    strHtml.Append(" <option value='0'>---请选择--- </option>");

                    while (rdr.Read())
                    {
                        strHtml.Append(" <option value='" + rdr["AutoCode"].ToString() + "'>" + rdr["sName"].ToString() + " </option>");
                    }
                }
                strHtml.Append(" </select>");
                return strHtml.ToString();
            }

            #endregion

           
        }
    }

    2.数据访问类:
    namespace DBUtility
    {
        public abstract class SqlHelp
        {
            public static readonly string ConnectionStringLocalTransaction = ConfigurationManager.ConnectionStrings["SQLDemo"].ConnectionString;
            public static SqlDataReader ExecuteReader(string connectionString, CommandType cmdType, string cmdText,
                params SqlParameter[] cmmandParameters)
            {
                SqlCommand cmd = new SqlCommand();
                SqlConnection con = new SqlConnection(connectionString);
                try
                {
                    PrepareCommand(cmd, con, null, cmdType, cmdText, cmmandParameters);
                    SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                    cmd.Parameters.Clear();
                    return rdr;
                }
                catch
                {
                    con.Close();
                    throw;
                }
            }


            private static void PrepareCommand(SqlCommand cmd, SqlConnection con, SqlTransaction trans, CommandType cmdtype, string
                cmdText, SqlParameter[] cmdparms)
            {
                if (con.State != ConnectionState.Open)
                    con.Open();
                cmd.Connection = con;
                cmd.CommandText = cmdText;

                if (trans != null)
                    cmd.Transaction = trans;
                cmd.CommandType = cmdtype;

                if (cmdparms != null)
                    foreach (SqlParameter parm in cmdparms)
                        cmd.Parameters.Add(parm);
            }
        }
    }

    3.前台AjaxProcess.aspx页面
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="AjaxProcess.aspx.cs" Inherits="AjaxProcess" %>
    .CS页面
    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Reflection;
    using System.Text;

    public partial class AjaxProcess : System.Web.UI.Page
    {
        string action;
        string itype;
        string classname;
        string iParent;
        int index;
        object[] obj_parameters;
        ParameterInfo[] paramterinfo;
       
        readonly string path = ConfigurationManager.AppSettings["AjaxProcess"];

        protected void Page_Load(object sender, EventArgs e)
        {
         
            //获取查询参数
            action = Request["action"] != null ? Request["action"] : null;
            itype = Request["itype"] != null ? Request["itype"] : null;
            iParent = Request["iParent"] != null ? Request["iParent"] : null;

            //动态调用方法
            classname = path + "." + action;
            object obj = Assembly.Load(path).CreateInstance(classname);
            Type mytype = obj.GetType();     
            MethodInfo m = mytype.GetMethod(itype);       
            if (m.GetParameters().Length > 0)
            {
                paramterinfo = m.GetParameters();
                obj_parameters = new object[m.GetParameters().Length];
                string[] parameters = new string[] { };
                if (iParent.IndexOf(" ¦") != -1)
                {
                    parameters = iParent.Split(' ¦');
                    for (int i = 0; i < paramterinfo.Length; i++)
                    {
                        Get_Type(parameters[i], paramterinfo[i]);
                    }             
                }
                else
                {

                    Get_Type(iParent, paramterinfo[0]);
                }
                Response.Write(m.Invoke(obj, obj_parameters));
            }
            else
                Response.Write(m.Invoke(obj, null));       
           
        }


        private void Get_Type(string par, ParameterInfo paramterinfo)
        {

            switch (paramterinfo.ParameterType.ToString())
            {
                case "System.String":
                    obj_parameters[index] = par;
                    break;
                case "System.Int32":
                    obj_parameters[index] = int.Parse(par);
                    break;
            }
            index++;                 
        }
    }


    100  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 10:30:391楼 得分:0
    C# code
    3.前台Demo页面. <%@ Page Language="C#" AutoEventWireup="true" CodeFile="DEMO.aspx.cs" Inherits="DEMO" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>无标题页</title> <script type="text/javascript" language="javascript"> var xmlHttp; function $(a){ return document.getElementById?document.getElementById(a):null; } function CreateXmlHttp() { try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { try { xmlHttp = new XMLHttpRequest(); } catch (e) { xmlHttp = false; }}} } function AjaxProcess(url,id) { CreateXmlHttp(); xmlHttp.open("POST",url); xmlHttp.onreadystatechange=function() { if(xmlHttp.readyState==4) { $(id).innerHTML=xmlHttp.responseText; } } xmlHttp.send(null); } function ChangeProvince() { // + $("ddProvince").value var id=$("divCity"); var url="AjaxProcess.aspx?action=City&iParent=3232|vfdvdf" + "&itype=Test_111"; AjaxProcess(url,"divCity"); } </script> </head> <body> <form id="form1" runat="server"> 省份:<asp:DropDownList ID="ddProvince" runat="server" onchange="ChangeProvince();"></asp:DropDownList><br /><br /> <span id="divCity"></span> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:TP_ZDConnectionString %>" SelectCommand="SELECT AutoCode, sName FROM S_Province"></asp:SqlDataSource> </form> </body> </html> 后台.cs页面: using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Data.SqlClient; using System.Collections.Generic; using System.Drawing; using System.Reflection; public partial class DEMO : System.Web.UI.Page { protected DataRow EnterDR; protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { ProCity(); } } public void ProCity() { ddProvince.DataSource = SqlDataSource1; ddProvince.DataTextField = "sName"; ddProvince.DataValueField = "AutoCode"; ddProvince.DataBind(); ListItem item = new ListItem("---请选择---", ""); ddProvince.Items.Insert(0, item); } } 上面写的不清楚,也许会纯在些遗漏,下面提供一个demo下载有需要的可以下载来看,里面还有个省份-市区数据库: http://download.csdn.net/user/sunchaohuang
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 10:30:431楼 得分:0
    头晕。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 10:58:532楼 得分:0
    very good!I often do like this~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 11:04:403楼 得分:0
    强烈建议用ref,和out传方法.不要用反射
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jzywh
    • 等级:
    发表于:2008-06-25 11:11:094楼 得分:0
    不一定要用反射阿,一点小小的改进就可以了阿

    public abstract Processor
    {
      public abstract void Process();
    }

    public class ChangeEnter : Processor
    {
      public overwrite void Process()
      {
        //Your execution code
      }
    }

    public class UpdateTime : Processor
    {
    ....
    }

    .............


    Dictionary <string, Processor> dictProcessor = new Dictionary <string, Processor>();
    dictProcessor["changeenter"] = new ChangeEnter();
    ......


    然后再处理的时候

    Processor proc;
    if(dictProcessor.TryGetValue(Request["action"].ToString().ToLower(), out proc))
    {
      proc.Process();
    }

    为了获取请求上下文你可以定义

    public abstract Processor
    {
      public abstract void Process(HttpContext context);
    }


    这样只需proc.Process(Context);就可以把上下文信息传禁区了


    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 14:21:025楼 得分:0
    昵称:江大鱼(.NET职业抢分)

    的方法很好但需要手动的添加类名称并且将其实例化,并且没法使代码的分类更加的细化如:
    var url="AjaxProcess.aspx?action=City&iParent=3232 ¦vfdvdf"  + "&itype=Test_111";
    中action(类名),itype(方法名)


    Dictionary <string, Processor> dictProcessor = new Dictionary <string, Processor>();
    dictProcessor["changeenter"] = new ChangeEnter();
    ...........


    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jinjazz
    • 等级:
    发表于:2008-06-25 14:24:166楼 得分:0
    用case不是蛮好的么,把里面的字符串改为enum就更好了,用反射得不偿失
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 14:39:127楼 得分:0
    请教楼主:
    object obj = Assembly.Load(path).CreateInstance(classname);
    这个path是在readonly string path = ConfigurationManager.AppSettings["AjaxProcess"];
    即配置文件得到的~
    我想知道Web.Config中的AjaxProcess里面的.dll是如何获得的,是全路径,还是文件名就好
    我在Asp.net中生成bin目录中.dll有好多个。
    谢谢!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 14:40:228楼 得分:0
    感觉都一样。。。。。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 14:48:079楼 得分:0
    请教楼主:
    object obj = Assembly.Load(path).CreateInstance(classname);
    这个path是在readonly string path = ConfigurationManager.AppSettings["AjaxProcess"];
    即配置文件得到的~
    我想知道Web.Config中的AjaxProcess里面的.dll是如何获得的,是全路径,还是文件名就好
    我在Asp.net中生成bin目录中.dll有好多个。
    谢谢!
    C# code
    <appSettings> <add key="AjaxProcess" value="Re_Demo.AjaxProcess"/> </appSettings>



    。。。。。case多的时候很麻烦, 写一个方法还要添一个case,要是出现N个人一起添加方法那找起来就麻烦了,都不知道
    在哪个类里添加了方法!  虽然在性能上有所不足,但使开发过程变得简便 

    个人认为可以尝试。。。。。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jzywh
    • 等级:
    发表于:2008-06-25 14:55:3410楼 得分:0
    引用 5 楼 sunchaohuang 的回复:
    昵称:江大鱼(.NET职业抢分)

    的方法很好但需要手动的添加类名称并且将其实例化,并且没法使代码的分类更加的细化如:
    var url="AjaxProcess.aspx?action=City&iParent=3232 ¦vfdvdf"  + "&itype=Test_111";
    中action(类名),itype(方法名)


    Dictionary <string, Processor> dictProcessor = new Dictionary <string, Processor>();
    dictProcessor["changeenter"] = new ChangeEnter();
    ...........


    1.手动的添加类名称??
    这里就可以用反射了, 第一次load的时候通过反射把这个类实例加到dictionary里面去。


    2.没法使代码的分类更加的细化
    既然 Context都传进去了, 当然可以根据 Request的参数来决定执行哪些代码啦。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 14:55:5811楼 得分:0
    请问sunchaohuang :
    我就是不知Re_Demo.AjaxProcess这个值是如何得到的~~ 谢谢!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 15:07:2312楼 得分:0
    引用 10 楼 jzywh 的回复:
    引用 5 楼 sunchaohuang 的回复:
    昵称:江大鱼(.NET职业抢分)

    的方法很好但需要手动的添加类名称并且将其实例化,并且没法使代码的分类更加的细化如:
    var url="AjaxProcess.aspx?action=City&iParent=3232 ¦vfdvdf"  + "&itype=Test_111";
    中action(类名),itype(方法名)


    Dictionary <string, Processor> dictProcessor = new Dictionary <string, Processor>();
    dictProcessor["changeenter"] = new Chan…



    那还是需要使用到放射啊,我以为不要用就可以了

    readonly string path = ConfigurationManager.AppSettings["AjaxProcess"];
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 15:17:0713楼 得分:0
    楼主可以看下这篇文章:

    使用工厂方法和State模式替换冗余的 switch-case 语句
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 15:23:0514楼 得分:0
    我的意思是,下面代码中Value中的Re_Demo.AjaxProcess是不是指程序集的名称,是从哪里得来的,是编译后的.Dll吗?

    <appSettings>                
                    <add   key= "AjaxProcess "   value= "Re_Demo.AjaxProcess "/>
            </appSettings>
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jzywh
    • 等级:
    发表于:2008-06-25 15:28:5615楼 得分:0
    引用 12 楼 sunchaohuang 的回复:
    引用 10 楼 jzywh 的回复:
    引用 5 楼 sunchaohuang 的回复:
    昵称:江大鱼(.NET职业抢分)

    的方法很好但需要手动的添加类名称并且将其实例化,并且没法使代码的分类更加的细化如:
    var url="AjaxProcess.aspx?action=City&iParent=3232 ¦vfdvdf"  + "&itype=Test_111";
    中action(类名),itype(方法名)


    Dictionary <string, Processor> dictProcessor = new Dictionary <string, Processor>();
    dictProcesso…


    初始化的时候反射一下几乎不影响性能,既然不影响性能又能使程序变得跟灵活,反射这么好的东东为啥不用呢?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 15:34:4716楼 得分:0
    用反射的performance比较差,各有各的好处,上上楼说的工厂方法和策略模式是可行的,但是前提条件是你操作的对象可以抽象出来共同的接口,从而你能够运用多态来实现策略和工厂,但是实际中往往业务对象要比这个复杂很多,抽象出一个base的接口是很难得,
    btw 用反射的话,一定要在合适的地方运用cache的机制将一些metadata缓存起来,这样在一定程度上可以提高performance
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • ysn1314
    • 等级:
    发表于:2008-06-25 15:34:5717楼 得分:0
    收藏,有空再look~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 15:35:0318楼 得分:0
    反射不会优化性能。实在很复杂的能用反射解决的才用反射解决。不过非常希望的项目是需要你用到反射的。
    看过博客园一篇文章。反射的性能与非反射性能对比相差百倍。不知道真的还是假的。初始化的反射几乎不会影响性能,是真的还是假的。能说详细些吗?还是你有对比测试过
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 15:49:0919楼 得分:0
    我也觉得有不得己的情况下才用反射
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jzywh
    • 等级:
    发表于:2008-06-25 15:56:0220楼 得分:0
    引用 18 楼 tiancaolin 的回复:
    初始化的反射几乎不会影响性能,是真的还是假的。能说详细些吗?


    在整个应用程序的生命周期内反射只执行一次,你说会不会影响呢?程序第一次运行编译的过程所花的时间更多。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jzywh
    • 等级:
    发表于:2008-06-25 15:57:2521楼 得分:0
    引用 16 楼 youlxsbobo 的回复:
    用反射的performance比较差,各有各的好处,上上楼说的工厂方法和策略模式是可行的,但是前提条件是你操作的对象可以抽象出来共同的接口,从而你能够运用多态来实现策略和工厂,但是实际中往往业务对象要比这个复杂很多,抽象出一个base的接口是很难得,
    btw 用反射的话,一定要在合适的地方运用cache的机制将一些metadata缓存起来,这样在一定程度上可以提高performance


    对的, Dictionary <string, Processor> dictProcessor = new Dictionary <string, Processor>();  其实就是起cache的作用
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 15:59:0122楼 得分:5
    up 学习
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 16:01:1323楼 得分:5
    慎用反射, 效率比较低哈
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天