zoukankan      html  css  js  c++  java
  • C# 用delegate实现AOP事务[C# | AOP | delegate]

    前言

         上一篇 C# 用Attribute实现AOP事务 [C# | AOP | Attribute | ContextAttribute | IContributeObjectSink | IMessageSink ] 是实现或者说达到AOP效果的一种方式,其实最早设计在C#中使用AOP来完成事务的方案是准备用delegate的,但无奈不习惯用这个玩意,也理解不深,后来被Attribute吸引了,这个方案就搁浅了,不过现在我又回来了 : ) 

    正文

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

        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<stringobject> 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<stringobject> dict)
            {
                StringBuilder sql 
    = new StringBuilder();
                sql.Append(
    "INSERT [UserInfo](");
                
                ExecuteNonQuery(sql);
            }
    }

         Main

            static void Main(string[] args)
            {

                Dictionary
    <stringobject> dict = new Dictionary<stringobject>();
                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<stringobject> dict)
            {
                TransactionAction(
    new VOID_DICTIONARY_METHOD(_Add), dict);
            }

            
    private void _Add(Dictionary<stringobject> dict)
            {
                UserInfo uInfo 
    = new UserInfo();
                uInfo.SetPropertyValue(dict);
                Insert(uInfo);
            }
        }
        

              而我们客户端代码又可以切换成普通方式调用了,但实际上他已经处在事务当中了。

    比较与特点

         相比Attribute实现AOP事务,有以下几个特点:

         1.     delegate方式效率肯定要比Attribute方式高,看看他实例化多少个类加上多少次反射就知道了。

         2.     delegate方式我们可以对错误进行Catch处理.

         3.     delegate方式得定义尽可能多的方法形式,这点比较不方便。

    结束

         一天半的时间又没了,但是又多了一种解决方案,我相信没有最好的解决方案,只有更好的解决方案,所以我希望当有人问你一个问题的时候,尤其是学习,你尽可能的给出多个方案并帮助他分析各个方案的利弊。欢迎大家提建议 : )

  • 相关阅读:
    使用PHP获取用户客户端真实IP的解决方案
    PHP中使用mkdir创建多级目录的方法
    javascript中将字符串转换为json格式的三种方法
    Codeigniter处理用户登录验证后URL跳转
    PHP正则表达式匹配URL中的域名
    开源项目列表
    PG JDBC COPY感谢原作者
    if中return的用法
    读数据库查询的 ResultSet时java.sql.SQLException: 流已被关闭
    一篇讲JAVA JDBC的好文章
  • 原文地址:https://www.cnblogs.com/over140/p/1372255.html
Copyright © 2011-2022 走看看