您的位置:首页 > 编程语言 > C#

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

2009-01-09 10:55 260 查看
前言

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

结束

一天半的时间又没了,但是又多了一种解决方案,我相信没有最好的解决方案,只有更好的解决方案,所以我希望当有人问你一个问题的时候,尤其是学习,你尽可能的给出多个方案并帮助他分析各个方案的利弊。欢迎大家提建议 : )
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: