利用反射减少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++;
}
}


...全文
381 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
jzywh 2008-06-25
  • 打赏
  • 举报
回复
不一定要用反射阿,一点小小的改进就可以了阿

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);就可以把上下文信息传禁区了


lihongdian 2008-06-25
  • 打赏
  • 举报
回复
强烈建议用ref,和out传方法.不要用反射
bookshop 2008-06-25
  • 打赏
  • 举报
回复
very good!I often do like this~
wfcfan 2008-06-25
  • 打赏
  • 举报
回复
头晕。
sunchaohuang 2008-06-25
  • 打赏
  • 举报
回复
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
sunchaohuang 2008-06-25
  • 打赏
  • 举报
回复
要下班了 :)

多谢各位的参与,结贴拉

关于今天的问题从.net框架设计一书中找到了相关资料发给大家:

动态定位个构造类型,我们应该遵循以下几点原则:

1.让类型继承自一个编译时已经确定的基类型。然后在运行时构造一个该类型的实例,并将其引用存放在一个声明类型为基
类型的变量中(如果大家选择的语言要求的话,可以适当的转型),最后调用基类型中的方法。 -- 江大鱼(.NET职业抢分)

2.让类型实现一个编译时已经确定的接口类型。然后在运行时构造一个该类型的实例,并将其引用存放在一个声明类型为其接口
类型的变量中(如果大家选择的语言要求的话,可以适当的转型),最后调用接口类型中定义的方法。相对于上面使用基类型的做法,我个人更喜欢使用接口方式,因为我们选择的基类型并不是在所有的情况下都能工作的更好。

3.让类型实现的方法的名称和原型匹配一个编译时已经确定的委托类型。然后在运行时构造一个该类型的实例,并用该实例对象和方法的名称构造一个委托类型的实例,最后通过委托对象来调用期望的方法,这种技巧在三种技巧中需要的工作量最多,尤其在我们需要对一个类型的多个方法进行调用的时,工作最会急剧上升。另外注意,通过委托来调用一个方法比直接调用一个类型或接口的方法要慢一些。


「已注销」 2008-06-25
  • 打赏
  • 举报
回复
收藏
ld_thinking 2008-06-25
  • 打赏
  • 举报
回复
利用反射类型Invoke方法的消耗远高于Load对象
  • 打赏
  • 举报
回复
应该说,像出现“m.Invoke(obj, obj_parameters)”这样的代码,在这里有点反射过头。Processor接口才是好的策略。

实际上,只有当你作为一个非常非常高级的框架设计师,你的软件必须用来取悦于许多“已经成熟、知名”的命令解析程序,并且付出一点性能代价可以得到非常巨大的系统整体功能和性能优势,才应该连方法也反射。否则,如果你就是一个应用的先行者,你就应该用接口来约束方法扩展,而不反射来纵容方法随意书写。

但是,从很谨慎地考虑出发,这里使用反射是非常好的。
  • 打赏
  • 举报
回复
如果程序不得不设计得如此细颗粒和扩展性,那么 Dictionary <string, Processor> dictProcessor 是很好的策略。在应用程序启动时一次性得到dictProcessor,或者在页面解析url参数时一边查询一边(当查询key在dictProcessor中找不到时)添加,都是即快有好的策略,效率很高。

在开发中,如果真的是大型框架,那么命令解析是要有灵活的扩展接口的。反之,需要对需求做一些简化。

谈效率,首先要在同样的功能需求条件下。如果功能根本达不到,举出这种情况下的任何所谓“高效”代码来反对“低效”实现方法都是无积极意义的。举出完成同样的设计要求的代码来,然后再提高效率,比较有积极意义。
jzywh 2008-06-25
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 ld_thinking 的回复:]
慎用反射, 效率比较低哈
[/Quote]

对, 慎用,不是不用!
ld_thinking 2008-06-25
  • 打赏
  • 举报
回复
慎用反射, 效率比较低哈
szh3210 2008-06-25
  • 打赏
  • 举报
回复
up 学习
jzywh 2008-06-25
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 youlxsbobo 的回复:]
用反射的performance比较差,各有各的好处,上上楼说的工厂方法和策略模式是可行的,但是前提条件是你操作的对象可以抽象出来共同的接口,从而你能够运用多态来实现策略和工厂,但是实际中往往业务对象要比这个复杂很多,抽象出一个base的接口是很难得,
btw 用反射的话,一定要在合适的地方运用cache的机制将一些metadata缓存起来,这样在一定程度上可以提高performance
[/Quote]

对的, Dictionary <string, Processor> dictProcessor = new Dictionary <string, Processor>(); 其实就是起cache的作用
jzywh 2008-06-25
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 tiancaolin 的回复:]
初始化的反射几乎不会影响性能,是真的还是假的。能说详细些吗?
[/Quote]

在整个应用程序的生命周期内反射只执行一次,你说会不会影响呢?程序第一次运行编译的过程所花的时间更多。
tinalucky 2008-06-25
  • 打赏
  • 举报
回复
我也觉得有不得己的情况下才用反射
datahandler2 2008-06-25
  • 打赏
  • 举报
回复
反射不会优化性能。实在很复杂的能用反射解决的才用反射解决。不过非常希望的项目是需要你用到反射的。
看过博客园一篇文章。反射的性能与非反射性能对比相差百倍。不知道真的还是假的。初始化的反射几乎不会影响性能,是真的还是假的。能说详细些吗?还是你有对比测试过
闲游四疯 2008-06-25
  • 打赏
  • 举报
回复
收藏,有空再look~
youlxsbobo 2008-06-25
  • 打赏
  • 举报
回复
用反射的performance比较差,各有各的好处,上上楼说的工厂方法和策略模式是可行的,但是前提条件是你操作的对象可以抽象出来共同的接口,从而你能够运用多态来实现策略和工厂,但是实际中往往业务对象要比这个复杂很多,抽象出一个base的接口是很难得,
btw 用反射的话,一定要在合适的地方运用cache的机制将一些metadata缓存起来,这样在一定程度上可以提高performance
jzywh 2008-06-25
  • 打赏
  • 举报
回复
[Quote=引用 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…
[/Quote]

初始化的时候反射一下几乎不影响性能,既然不影响性能又能使程序变得跟灵活,反射这么好的东东为啥不用呢?
加载更多回复(10)

62,074

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧