用于多个方法调用的Func委托

时间:2012-02-17 00:31:48

标签: c# delegates

我曾经问过这个问题 Converting using SqlConnection to Func delegate

如何使用以下委托使用同一事务进行多次调用? 更复杂的是,我希望返回一个值的一个调用。

我有以下委托功能定义

protected TResult UsingSqlTransaction<TResult>(Func<SqlTransaction, TResult> myFunction)
{
    using (SqlConnection sqlConn = new SqlConnection(ConnectionString))
    {
        sqlConn.Open();
        using (SqlTransaction sqlTrans = sqlConn.BeginTransaction())
        {
            var result = myFunction(sqlTrans);
            sqlTrans.Commit();

            return result;
        }

    }
}

当前用法

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans => data.InsertUpdate(sqlTrans, entity));
}

解决方案 - 查看接受的答案

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans =>
    {
        var token = data.InsertUpdate(sqlTrans, entity);
        data.DoSomethingElse(sqlTrans, entity);
        return token;
    });
}

//-- The above UsingSqlTransaction remains unchanged

3 个答案:

答案 0 :(得分:2)

你可以使用'block'lambda。而不是:

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans => data.InsertUpdate(sqlTrans, entity));
}

你可以使用(注意大括号和分号):

public List<Guid?> InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans =>
    {
        var result = new List<Guid?>();
        result.Add(data.InsertUpdate(sqlTrans, entity));
        result.Add(data.DoSomethingElse(sqlTrans, entity));
        return result;
    });
}

回复:你的更新。我会这样写(请注意,您可以存储token并将其返回到lambda的末尾,就像通常的方法一样):

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans =>
    {
        var token = data.InsertUpdate(sqlTrans, entity);
        data.DoSomethingElse(sqlTrans, entity);
        return token;
    });
}

答案 1 :(得分:0)

我的程序中有相同的方法,但它是这样的:

void RunTransaction(Action<IDbCommand> action)
{
using(var cnn=GetConnection)
cnn.Open();
using(var trans=cnn.BeginTransaction())
{
var command=cnn.CreateCommand();
action(command);
trans.Commit();
}
}

这个方法只负责管理一个事务而不管其他任何事情。我们不在乎我们是在查询数据库还是在插入一个值。调用者有责任去处理这些事情,并且封闭之美很容易做到:)

这就是我的想法:不要试图对所有内容进行抽象,因为很快您的程序员就会变得太复杂而无法扩展和维护。只需要一些基本的抽象,然后就可以在这些简单的构建上构建应用程序了。

答案 2 :(得分:0)

这是我成功使用过几次的模式:

拥有一个“事务管理器”对象,在内部跟踪当前连接和事务。对于单线程应用程序,它可以是一个简单的静态,或者使用线程本地存储甚至是WCF操作上下文来做有趣的事情。我们的想法是,它为您提供了一个单独的位置来创建与调用数据库的代码分开的连接和事务。

事务管理器公开一个名为BeginTransaction的公共方法,该方法返回实现IDisposable的事务对象。每次调用BeginTransaction时,都会获得一个新的事务范围实例。

事务范围对象还提供了获取数据库连接的方法和在处置之前必须调用的Commit方法。如果未调用Commit,则事务将在Dispose上回滚。

void M1() 
{
    using( var scope = TransactionManager.BeginTransaction() )
    {
      // Do stuff with the database.
      M2(); // M2 and M3 each create their own scopes that share the transaction
      M3(); // created by M1.

      // An exception before the commit will cause the transaction to roll back.
      scope.Commit();
    }
}

重要的是,TransactionManager将允许您创建嵌套作用域 - “对数据库执行操作”行可以调用一堆其他方法,每个方法创建自己的共享事务的作用域。必须提交所有范围或一切都将回滚。

这看起来与System.Transactions命名空间中的内容非常相似,我建议你也看看它。

然后你的实用程序用于简化代码,如果你仍然想要它们,看起来像这样:

public static void Execute(Action<ITransactionScope> action)
{
  using( var scope = TransactionManager.BeginTransaction() )
  {
    action(scope);
    scope.Commit();
  }
}

public static TResult Execute<TResult>(Func<ITransactionScope, TResult> func)
{
  using( var scope = TransactionManager.BeginTransaction() )
  {
    var result = func(scope);
    scope.Commit();
    return result;
  }
}