天天看点

C# 用delegate实现AOP事务[C# | AOP | delegate]

正文

     我们先来看一段代码雏形:

    class TestClass

    {

        public void Test()

        {

            Console.WriteLine("Test");

        }

        public void DelegateTest(DelegateMethod dm)

            Console.WriteLine("DelegateMethod Start

C# 用delegate实现AOP事务[C# | AOP | delegate]

");

            dm.Invoke();

            Console.WriteLine("DelegateMethod End

C# 用delegate实现AOP事务[C# | AOP | delegate]

    }

    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...

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);

        #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)

                return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText);

                return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText);

        public int ExecuteNonQuery(string cmdText, CommandType type, params SqlParameter[] cmdParameters)

                return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText, cmdParameters);

                return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText, cmdParameters);

        /// 在事务中执行

        /// <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();

        #region Properties

        /// 仅支持有事务时操作

        public SqlTransaction SqlTrans

            get { return _SqlTrans; }

            set { _SqlTrans = value; }

        /// 字符串连接

        public virtual SqlConnectionStringBuilder ConnectionString

            get

                if (_ConnectionString == null || string.IsNullOrEmpty(_ConnectionString.ConnectionString))

                    _ConnectionString = new SqlConnectionStringBuilder(Configurations.SQLSERVER_CONNECTION_STRING);

                return _ConnectionString;

            set { _ConnectionString = value; }

     代码说明:

          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](");

C# 用delegate实现AOP事务[C# | AOP | delegate]
C# 用delegate实现AOP事务[C# | AOP | delegate]

            ExecuteNonQuery(sql);

}

     Main

            Dictionary<string, object> dict = new Dictionary<string, object>();

            UserInfoAction uiAction = new UserInfoAction();

            dict.Add("Username", "abc");

            dict.Add("Password", "abc");

            dict.Add("Email", "[email protected]");

            //普通方式执行

            //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

            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方式得定义尽可能多的方法形式,这点比较不方便。

本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/586461,如需转载请自行联系原作者