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

 

结束

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

posted @ 2009-01-09 10:55  农民伯伯  阅读(5761)  评论(3编辑  收藏  举报