天天看點

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,如需轉載請自行聯系原作者