最近有病呆在家里,不是次就是睡,不只日夜颠倒了,还胖了不少。
不过空余的时间总不能浪费掉,所以开始了一个新的跨数据库访问组件。
不过那个组件要写比较长时间了,所以一时不会做得完。
不过今天用其中的技术做了个有用的例子,发到这里给大家参考一下。
这个例子的大概意思是,程序员参考存储的定义,写出一个接口出来,并且不需要写具体的实现代码,就能调用该接口了!
也就是说,程序员不需要写以下类似的代码了:
SqlCommand cmd=new SqlCommand("UpdateTopic",conn);
cmd.CommandType=CommandType.StoredProcedure;

SqlParameter pTitle=new SqlParameter("@title",SqlDbType.NVarChar,80);
pTitle.Value=title;
cmd.Parameters.Add(pTitle);

//
.
程序的例子如下

/**//****************************************************************\
*
* 用 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)
![]()