欢迎光临
我们一直在努力

用 System.Reflection.Emit 来自动生成调用储存过程的实现-ASP教程,脚本编码

建站超值云服务器,限时71元/月

/****************************************************************\

*

* 用 system.reflection.emit 来自动生成调用储存过程的实现!

*

* by http://lostinet.com

*

* copyrights : not-reversed

*

\****************************************************************/

//使用的例子

namespace lostinet.sample

{

using system;

using system.data;

using system.data.sqlclient;

using system.windows.forms;

//定义一个接口,用于定义存储过程

interface inorthwindstoredprocedures

{

//定义存储过程对应的方法

dataset custorderhist(string customerid);

//如果储存过程名字和方法名字不同,应该用sqlaccessattribute来进行说明

[sqlaccess("employee sales by country")]

datatable employeesalesbycountry(datetime beginning_date,datetime ending_date);

//…more…

//more ideas..

//直接执行sql语句?

//[sqlaccess(sqlaccesstype.sqlquery,"select * from employees where employeeid=@empid")]

//datatable selectemployee(int empid);

}

class consoleapplication

{

[stathread]

static void main(string[] args)

{

using(sqlconnection conn=new sqlconnection("server=(local);trusted_connection=true;database=northwind"))

{

//一句话就把实现创建了!

//需要传如 sqlconnection 和 sqltransaction

//sqltransaction可以为null

//这个好就好在,只要能得到sqlconnection/sqltransaction就能用这个方法了,所以兼容 lostinet.data.sqlscope

inorthwindstoredprocedures nsp=(inorthwindstoredprocedures)

storedprocedure.createstoredprocedureinterface(typeof(inorthwindstoredprocedures),conn,null);

//调用储存过程并且显示

showdata("custorderhist alfki",nsp.custorderhist("alfki"));

showdata("employee sales by country",nsp.employeesalesbycountry(new datetime(1998,1,1),new datetime(1999,1,1)));

}

}

static void showdata(string title,object data)

{

form f=new form();

f.width=600;

f.height=480;

f.text=title;

datagrid grid=new datagrid();

grid.dock=dockstyle.fill;

grid.datasource=data;

f.controls.add(grid);

f.showdialog();

}

}

}

#region //实现方法(不完整)

namespace lostinet.sample

{

using system;

using system.collections;

using system.reflection;

using system.reflection.emit;

using system.data;

using system.data.sqlclient;

//这个类作为实现的基类,

//目的是提供储存 sqlconnection/sqltransaction 和公用的一些方法

//这个类必须为public,否则无法继承

//但开发者不会显式访问这个类

public class spinterfacebase : idisposable

{

public spinterfacebase()

{

}

public void dispose()

{

}

//createstoredprocedureinterface会把相关的值sqlconnection/sqltransaction存到这里

public sqlconnection connection;

public sqltransaction transaction;

//创建一个sqlcommand

public sqlcommand createcommand(string spname)

{

sqlcommand cmd=new sqlcommand(spname,connection,transaction);

cmd.commandtype=commandtype.storedprocedure;

//todo:

//cmd.parameters.add("@returnvalue",…

return cmd;

}

//由 type 推算出 sqldbtype , 未完成

sqldbtype getsqldbtype(type type)

{

//todo:switch(type)…

return sqldbtype.nvarchar;

}

//定义参数

public void defineparameter(sqlcommand cmd,string name,type type,parameterdirection direction)

{

sqlparameter param=new sqlparameter("@"+name,getsqldbtype(type));

param.direction=direction;

cmd.parameters.add(param);

}

//在sqlcommand执行前设置参数值

public void setparameter(sqlcommand cmd,string name,object value)

{

cmd.parameters["@"+name].value=(value==null?dbnull.value:value);

}

//在sqlcommand执行后取得参数值

public object getparameter(sqlcommand cmd,string name)

{

return cmd.parameters["@"+name].value;

}

//根据不同的返回值执行不同的操作

public sqldatareader executedatareader(sqlcommand cmd)

{

return cmd.executereader();

}

public object executescalar(sqlcommand cmd)

{

return cmd.executescalar();

}

public void executenonquery(sqlcommand cmd)

{

cmd.executenonquery();

}

public dataset executedataset(sqlcommand cmd)

{

dataset ds=new dataset();

using(sqldataadapter sda=new sqldataadapter(cmd))

{

sda.fill(ds);

}

return ds;

}

public datatable executedatatable(sqlcommand cmd)

{

datatable table=new datatable();

using(sqldataadapter sda=new sqldataadapter(cmd))

{

sda.fill(table);

}

return table;

}

public datarow executedatarow(sqlcommand cmd)

{

datatable table=executedatatable(cmd);

if(table.rows.count==0)

return null;

return table.rows[0];

}

}

public class storedprocedure

{

static public object createstoredprocedureinterface(type interfacetype,sqlconnection connection,sqltransaction transaction)

{

//检查参数

if(interfacetype==null)throw(new argumentnullexception("interfacetype"));

if(!interfacetype.isinterface)

throw(new argumentexception("argument is not interface","interfacetype"));

if(connection==null)throw(new argumentnullexception("connection"));

if(transaction!=null)

{

if(transaction.connection!=connection)

throw(new argumentexception("transaction.connection!=connection","transaction"));

}

//创建storedprocedure

storedprocedure spemit=new storedprocedure();

spemit.interfacetype=interfacetype;

spemit.connection=connection;

spemit.transaction=transaction;

//创建

return spemit.createinstance();

}

//用于储存已创建的类型

static hashtable emittedtypes=new hashtable();

type interfacetype;

sqlconnection connection;

sqltransaction transaction;

private storedprocedure()

{

}

object createinstance()

{

lock(interfacetype)

{

//如果没有创建具体的实现,则创建它

if(emittedtype==null)

{

emittedtype=(type)emittedtypes[interfacetype];

if(emittedtype==null)

{

createtype();

//储存已创建类型

emittedtypes[interfacetype]=emittedtype;

}

}

}

//创建具体的实例

spinterfacebase spi=(spinterfacebase)activator.createinstance(emittedtype);

//设置sqlconnection/sqltransaction

spi.connection=connection;

spi.transaction=transaction;

return spi;

}

type emittedtype;

typebuilder typebuilder;

//创建类型

void createtype()

{

//创建 assembly

//assemblybuilderaccess.run-表示只用于运行,不在磁盘上保存

assemblyname an=new assemblyname();

an.name="assembly."+interfacetype.fullname+".implementation";

assemblybuilder asmbuilder=appdomain.currentdomain.definedynamicassembly(an,assemblybuilderaccess.run);

//创建module

modulebuilder mdlbuilder=asmbuilder.definedynamicmodule("module."+interfacetype.fullname+".implementation");

//创建type,该类型继承 spinterfacebase

typebuilder=mdlbuilder.definetype(interfacetype.fullname+".implementation",typeattributes.class,typeof(spinterfacebase));

//实现所有的接口方法

emitinterface(interfacetype);

//如果interfacetype是基于其他接口的

foreach(type subinterface in interfacetype.getinterfaces())

{

//idisposable不需要实现,由spinterfacebase实现了

if(subinterface==typeof(idisposable))

continue;

emitinterface(subinterface);

}

emittedtype=typebuilder.createtype();

}

void emitinterface(type type)

{

//实现接口

typebuilder.addinterfaceimplementation(type);

//列出接口的成员

foreach(memberinfo member in type.getmembers(bindingflags.instance|bindingflags.public))

{

//约定-成员必须是方法,不能有属性啊,事件之类的

if(member.membertype!=membertypes.method)

throw(new exception("could not emit "+member.membertype+" automatically!"));

//取得接口中定义的方法

methodinfo method=(methodinfo)member;

//计算新方法的属性,在原来方法的属性上复制过来,并且不是public/abstract,加上private

methodattributes methodattrs=method.attributes;

methodattrs&=~(methodattributes.public|methodattributes.abstract);

methodattrs|=methodattributes.private;

parameterinfo[] paraminfos=method.getparameters();

int paramlength=paraminfos.length;

//取得参数的类型数组

type[] paramtypes=new type[paramlength];

for(int i=0;i<paramlength;i++)

{

paramtypes[i]=paraminfos[i].parametertype;

}

//在typebuilder上建立新方法,参数类型与返回类型都与接口上的方法一致

methodbuilder mthbuilder=typebuilder.definemethod(method.name,methodattrs,method.callingconvention,method.returntype,paramtypes);

//复制新方法上的参数的名字和属性

for(int i=0;i<paramlength;i++)

{

parameterinfo pi=paraminfos[i];

//对于instance,参数position由1开始

mthbuilder.defineparameter(i+1,pi.attributes,pi.name);

}

//指定新方法是实现接口的方法的。

typebuilder.definemethodoverride(mthbuilder,method);

//在类型上定义一个字段,这个字段用于储存被方法使用的sqlcommand

fieldbuilder field_cmd=typebuilder.definefield("_cmd_"+method.name,typeof(sqlcommand),fieldattributes.private);

//ilgenerator 是用于生成实现代码的对象

ilgenerator ilg=mthbuilder.getilgenerator();

//定义临时变量

localbuilder local_res=ilg.declarelocal(typeof(object));

//定义一个用于跳转的label

label label_cmd_ready=ilg.definelabel();

//this._cmd_methodname

ilg.emit(opcodes.ldarg_0); //this

ilg.emit(opcodes.ldfld,field_cmd);//._cmd_methodname

//if(this._cmd_methodname!=null) 跳到 label_cmd_ready

ilg.emit(opcodes.brtrue,label_cmd_ready);

//如果this._cmd_methodname为null,则运行下面代码来创建sqlcommand

//this._cmd_methodname=this.createcommand("methodname");

ilg.emit(opcodes.ldarg_0);

//this.createcommand

ilg.emit(opcodes.ldarg_0);//参数0

ilg.emit(opcodes.ldstr,sqlaccessattribute.getspname(method));//参数1

//调用

ilg.emit(opcodes.callvirt,typeof(spinterfacebase).getmethod("createcommand",bindingflags.instance|bindingflags.public));

ilg.emit(opcodes.stfld,field_cmd);// ._cmd_methodname=

//this.defineparameter(…)

if(paramlength!=0)

{

//取得defineparameter的引用

methodinfo method_defineparameter=typeof(spinterfacebase).getmethod("defineparameter",bindingflags.instance|bindingflags.public);

for(int i=0;i<paramlength;i++)

{

//取得各参数

parameterinfo pi=paraminfos[i];

//this.defineparameter(this._cmd_methodname,"parametername",typeof(parametertype),parameterdirection.xxx);

//参数0 – this

ilg.emit(opcodes.ldarg_0);

//参数1 – this._cmd_methodname

ilg.emit(opcodes.ldarg_0);

ilg.emit(opcodes.ldfld,field_cmd);

//参数2 – "parametername"

ilg.emit(opcodes.ldstr,pi.name);

//参数3 – typeof(parametertype)

ilg.emit(opcodes.ldtoken,pi.parametertype);

//参数4 – parameterdirection.xxx

if(pi.parametertype.isbyref)

{

ilg.emit(opcodes.ldc_i4,(int)parameterdirection.inputoutput);

}

else if(pi.isout)

{

ilg.emit(opcodes.ldc_i4,(int)parameterdirection.output);

}

else

{

ilg.emit(opcodes.ldc_i4,(int)parameterdirection.input);

}

//调用defineparameter

ilg.emit(opcodes.callvirt,method_defineparameter);

}

}

//到这里 _cmd_commandname 已经 ok 了。

//设置label_cmd_ready就指这里

ilg.marklabel(label_cmd_ready);

//cmd!=null now.

if(paramlength!=0)

{

//现在要把方法的参数的值设置到sqlparameter上

methodinfo method_setparameter=typeof(spinterfacebase).getmethod("setparameter",bindingflags.instance|bindingflags.public);

for(int i=0;i<paramlength;i++)

{

parameterinfo pi=paraminfos[i];

//如果参数是 out 的,则不需要设置

if(!pi.parametertype.isbyref&&pi.isout)

continue;

//this.setparameter(this._cmd_methodname,"parametername",parametername);

ilg.emit(opcodes.ldarg_0);

ilg.emit(opcodes.ldarg_0);

ilg.emit(opcodes.ldfld,field_cmd);

ilg.emit(opcodes.ldstr,pi.name);

//取得参数值,如果参数为valuetype,则box到object

ilg.emit(opcodes.ldarg,i+1);

if(pi.parametertype.isvaluetype)

ilg.emit(opcodes.box,pi.parametertype);

ilg.emit(opcodes.callvirt,method_setparameter);

}

}

//现在要执行储存过程(执行sqlcommand)了

//这里根据返回值类型判断怎样执行sqlcommand

type returntype=method.returntype;

//如果是 void 的,则不需要返回值

bool nores=returntype==typeof(void);

methodinfo method_execute=null;

if(nores)

{

//不需要返回值

method_execute=typeof(spinterfacebase).getmethod("executenonquery",bindingflags.instance|bindingflags.public);

}

else if(returntype==typeof(object))

{

//返回object

method_execute=typeof(spinterfacebase).getmethod("executescalar",bindingflags.instance|bindingflags.public);

}

else if(returntype==typeof(dataset))

{

//返回dataset

method_execute=typeof(spinterfacebase).getmethod("executedataset",bindingflags.instance|bindingflags.public);

}

else if(returntype==typeof(datatable))

{

//返回datatable

method_execute=typeof(spinterfacebase).getmethod("executedatatable",bindingflags.instance|bindingflags.public);

}

else if(returntype==typeof(datarow))

{

//返回datarow

method_execute=typeof(spinterfacebase).getmethod("executedatarow",bindingflags.instance|bindingflags.public);

}

else

{

//返回其他类型

foreach(type retinterface in returntype.getinterfaces())

{

//如果是返回idatareader

if(retinterface==typeof(idatareader))

{

//只支持sqldatareader

if(!returntype.isassignablefrom(typeof(sqldatareader)))

throw(new exception("sqldatareader could not convert to "+returntype.fullname));

method_execute=typeof(spinterfacebase).getmethod("executedatareader",bindingflags.instance|bindingflags.public);

break;

}

}

}

//如果找不到适合的策略,

if(method_execute==null)

{

//todo:当然,这里应该有返回int32,string,…的,不过懒得再写了。

//抛出异常,提示不支持该返回类型,要作者改改:)

throw(new notsupportedexception("notsupport returntype:"+returntype.fullname));

}

//this.executexxx(this._cmd_methodname)

ilg.emit(opcodes.ldarg_0);

ilg.emit(opcodes.ldarg_0);

ilg.emit(opcodes.ldfld,field_cmd);

ilg.emit(opcodes.callvirt,method_execute);

//如果有返回值的,则是

//local_res=this.executexxx(this._cmd_methodname)

if(!nores)

{

if(returntype.isvaluetype)

ilg.emit(opcodes.box,returntype);

ilg.emit(opcodes.stloc,local_res);

}

if(paramlength!=0)

{

//这里处理ref/out的参数

methodinfo method_getparameter=typeof(spinterfacebase).getmethod("getparameter",bindingflags.instance|bindingflags.public);

for(int i=0;i<paramlength;i++)

{

parameterinfo pi=paraminfos[i];

//如果不是ref/out则跳过

if(!pi.parametertype.isbyref&&!pi.isout)

continue;

//parametername=this.getparameter(this._cmd_methodname,"parametername")

ilg.emit(opcodes.ldarg_0);

ilg.emit(opcodes.ldarg_0);

ilg.emit(opcodes.ldfld,field_cmd);

ilg.emit(opcodes.ldstr,pi.name);

ilg.emit(opcodes.callvirt,method_getparameter);

//如果类型是值类型,则需要 unbox

if(pi.parametertype.isvaluetype)

ilg.emit(opcodes.unbox,pi.parametertype);

ilg.emit(opcodes.starg,i+1);

}

}

//如果是 void , 则直接 return;

//否者是 return local_res , 如果返回值类型是valuetype,则需要unbox

if(!nores)

{

ilg.emit(opcodes.ldloc,local_res);

if(returntype.isvaluetype)

ilg.emit(opcodes.unbox,returntype);

}

ilg.emit(opcodes.ret);

// //throw(new notimplementedexception());

// ilg.emit(opcodes.newobj,typeof(notimplementedexception).getconstructor(new type[0]));

// ilg.emit(opcodes.throw);

}

}

}

public enum sqlaccesstype

{

storedprocedure

//todo:

//,sqlquery

}

[attributeusage(attributetargets.method)]

public class sqlaccessattribute : attribute

{

string _sp;

public sqlaccessattribute(string spname)

{

_sp=spname;

}

public string storeprocedure

{

get

{

return _sp;

}

}

static public string getspname(methodinfo method)

{

if(method==null)throw(new argumentnullexception("method"));

object[] attrs=method.getcustomattributes(typeof(sqlaccessattribute),false);

if(attrs==null||attrs.length==0)

return method.name;

return ((sqlaccessattribute)attrs[0]).storeprocedure;

}

//todo:

// public sqlaccessattribute(sqlaccesstype type,string text)

// {

//

// }

}

}

#endregion

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 用 System.Reflection.Emit 来自动生成调用储存过程的实现-ASP教程,脚本编码
分享到: 更多 (0)

相关推荐

  • 暂无文章