我们先来看一段代码雏形:
class TestClass { public void Test() { Console.WriteLine( " Test " ); } public void DelegateTest(DelegateMethod dm) { Console.WriteLine( " DelegateMethod Start " ); dm.Invoke(); Console.WriteLine( " DelegateMethod End " ); } } class Program { static void Main( string [] args) { TestClass tc = new TestClass(); tc.Test(); Console.WriteLine( " ------------------------------- " ); tc.DelegateTest( new DelegateMethod(mc.Test)); Console.Read(); } } 输出结果
Test
-------------------------------
DelegateMethod Start...
Test
DelegateMethod End...
我认为这也是一种AOP的方式,只是和传统的不太一样,如果把调用方和被调用方看成客户端和服务器的话,那么传统的AOP是施加在服务器端的,并在服务器端控制的,而现在我把这个权利交出来,交给客户端来控制,也就是由调用者来决定是不是要使用事务,也就是调用者自己决定用事务或非事务的方式来执行方法。请注意:如果到这里你不能接受我的想法请不必往下看了 : )
接下来我会把代码贴全,注意代码我都测试通过了的: )
SqlDAL.cs 把上篇文章拿过来拷贝过来改把改把贴上来
#region // 事务 private SqlTransaction _SqlTrans; // 数据库连接类 private SqlConnectionStringBuilder _ConnectionString = null ; #endregion #region delegate /// <summary> /// 用于执行带Dictionary参数无返回值的函数 /// </summary> /// <param name="dict"></param> public delegate void VOID_DICTIONARY_METHOD(Dictionary < string , object > dict); #endregion #region Method #region ExecuteNonQuery public int ExecuteNonQuery( string cmdText) { if (SqlTrans == null ) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, CommandType.Text, cmdText); else return SqlHelper.ExecuteNonQuery(SqlTrans, CommandType.Text, cmdText); } public int ExecuteNonQuery( string cmdText, CommandType type) { if (SqlTrans == null ) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText); else return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText); } public int ExecuteNonQuery( string cmdText, CommandType type, params SqlParameter[] cmdParameters) { if (SqlTrans == null ) return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText, cmdParameters); else return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText, cmdParameters); } #endregion /// <summary> /// 在事务中执行 /// </summary> /// <param name="action"></param> /// <param name="args"></param> public void TransactionAction(Delegate delegateMethod, params object [] args) { SqlConnection SqlConnect = new SqlConnection(ConnectionString.ConnectionString); SqlConnect.Open(); _SqlTrans = SqlConnect.BeginTransaction(); try { // 数据库操作 delegateMethod.DynamicInvoke(args); // 提交事务 _SqlTrans.Commit(); } catch (SqlException) { _SqlTrans.Rollback(); // 日志 } finally { if (SqlTrans != null ) { _SqlTrans.Dispose(); _SqlTrans = null ; } if (SqlConnect != null ) SqlConnect.Close(); } } #endregion #region Properties /// <summary> /// 仅支持有事务时操作 /// </summary> public SqlTransaction SqlTrans { get { return _SqlTrans; } set { _SqlTrans = value; } } /// <summary> /// 字符串连接 /// </summary> public virtual SqlConnectionStringBuilder ConnectionString { get { if (_ConnectionString == null || string .IsNullOrEmpty(_ConnectionString.ConnectionString)) { _ConnectionString = new SqlConnectionStringBuilder(Configurations.SQLSERVER_CONNECTION_STRING); } return _ConnectionString; } set { _ConnectionString = value; } } #endregion 代码说明:
1. 讲Delegate作为参数,我们可以传任何一个delegate进来,不必使用实际的如VOID_DICTIONARY_METHOD作为参数传递,这对于通用是一个很好的办法。
2. TransactionAction方法第二个参数是你要传递的参数,即委托的参数。MSDN:作为参数传递给当前委托所表示的方法的对象数组。- 或 - 如果当前委托所表示的方法不需要参数,则为null。
UserInfoAction.cs 不变
public class UserInfoAction:SqlDAL { public void Add(Dictionary < string , object > dict) { StringBuilder sql = new StringBuilder(); sql.Append( " INSERT [UserInfo]( " ); ExecuteNonQuery(sql); } } Main
static void Main( string [] args) { Dictionary < string , object > dict = new Dictionary < string , object > (); UserInfoAction uiAction = new UserInfoAction(); dict.Add( " Username " , " abc " ); dict.Add( " Password " , " abc " ); dict.Add( " Email " , " over140@gmail.com " ); // 普通方式执行 // uiAction.Add(dict); // 事务方式执行 uiAction.TransactionAction( new UserInfoAction.VOID_DICTIONARY_METHOD(uiAction.Add), dict); } 代码说明
1. 可以看到普通方式和事务方式执行方式不同,但是我们不用改UserInfoAction的代码!!我们在写代码尤其是维护的时候就是这样的原则,或者是增量式开发也是比较好的,尽量不去改是比较好的。
2. 请注意:你的delegate必须符合Method,否则编译时会出错的,虽然解决了统一调用的问题,但是这个delegate目前我还没想到办法解决,也就是你有一个不同参数、返回值方法就得对应一个delegate,方法名称不限制,所以一开始我们就得定义可能好几十个委托,这也是利弊所在不,不然还是很完美的。
3. 有朋友可能觉得这个决定权不应该交给客户端来决定,必须事务,那这也好办,请看代码:
public class UserInfoAction:SqlDAL { public void Add(Dictionary < string , object > dict) { TransactionAction( new VOID_DICTIONARY_METHOD(_Add), dict); } private void _Add(Dictionary < string , object > dict) { UserInfo uInfo = new UserInfo(); uInfo.SetPropertyValue(dict); Insert(uInfo); } } 而我们客户端代码又可以切换成普通方式调用了,但实际上他已经处在事务当中了。
比较与特点
相比Attribute实现AOP事务,有以下几个特点:
1. delegate方式效率肯定要比Attribute方式高,看看他实例化多少个类加上多少次反射就知道了。
2. delegate方式我们可以对错误进行Catch处理.
3. delegate方式得定义尽可能多的方法形式,这点比较不方便。
本文转自博客园农民伯伯的博客,原文链接:,如需转载请自行联系原博主。