我现在正面临同样的问题,对我来说似乎有两种解决方案:
- 别解决问题。
- 为现有类创建遵循相同模式但可模拟/可存根的抽象。
Edit:我现在为此创建了一个 CodePlex 项目:http://legendtransactions.codeplex.com/ http://legendtransactions.codeplex.com/
我倾向于创建一组用于处理事务的接口和委托给 System.Transaction-implementations 的默认实现,例如:
public interface ITransactionManager
{
ITransaction CurrentTransaction { get; }
ITransactionScope CreateScope(TransactionScopeOption options);
}
public interface ITransactionScope : IDisposable
{
void Complete();
}
public interface ITransaction
{
void EnlistVolatile(IEnlistmentNotification enlistmentNotification);
}
public interface IEnlistment
{
void Done();
}
public interface IPreparingEnlistment
{
void Prepared();
}
public interface IEnlistable // The same as IEnlistmentNotification but it has
// to be redefined since the Enlistment-class
// has no public constructor so it's not mockable.
{
void Commit(IEnlistment enlistment);
void Rollback(IEnlistment enlistment);
void Prepare(IPreparingEnlistment enlistment);
void InDoubt(IEnlistment enlistment);
}
这看起来工作量很大,但另一方面它是可重用的,并且使得一切都非常容易测试。
请注意,这并不是接口的完整定义,仅足以让您了解全局。
Edit:我只是做了一些快速而肮脏的实现作为概念证明,我认为这是我将采取的方向,这是我到目前为止所想出的。我想也许我应该为此创建一个 CodePlex 项目,这样问题就可以一劳永逸地解决。这不是我第一次遇到这种情况。
public interface ITransactionManager
{
ITransaction CurrentTransaction { get; }
ITransactionScope CreateScope(TransactionScopeOption options);
}
public class TransactionManager : ITransactionManager
{
public ITransaction CurrentTransaction
{
get { return new DefaultTransaction(Transaction.Current); }
}
public ITransactionScope CreateScope(TransactionScopeOption options)
{
return new DefaultTransactionScope(new TransactionScope());
}
}
public interface ITransactionScope : IDisposable
{
void Complete();
}
public class DefaultTransactionScope : ITransactionScope
{
private TransactionScope scope;
public DefaultTransactionScope(TransactionScope scope)
{
this.scope = scope;
}
public void Complete()
{
this.scope.Complete();
}
public void Dispose()
{
this.scope.Dispose();
}
}
public interface ITransaction
{
void EnlistVolatile(Enlistable enlistmentNotification, EnlistmentOptions enlistmentOptions);
}
public class DefaultTransaction : ITransaction
{
private Transaction transaction;
public DefaultTransaction(Transaction transaction)
{
this.transaction = transaction;
}
public void EnlistVolatile(Enlistable enlistmentNotification, EnlistmentOptions enlistmentOptions)
{
this.transaction.EnlistVolatile(enlistmentNotification, enlistmentOptions);
}
}
public interface IEnlistment
{
void Done();
}
public interface IPreparingEnlistment
{
void Prepared();
}
public abstract class Enlistable : IEnlistmentNotification
{
public abstract void Commit(IEnlistment enlistment);
public abstract void Rollback(IEnlistment enlistment);
public abstract void Prepare(IPreparingEnlistment enlistment);
public abstract void InDoubt(IEnlistment enlistment);
void IEnlistmentNotification.Commit(Enlistment enlistment)
{
this.Commit(new DefaultEnlistment(enlistment));
}
void IEnlistmentNotification.InDoubt(Enlistment enlistment)
{
this.InDoubt(new DefaultEnlistment(enlistment));
}
void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
{
this.Prepare(new DefaultPreparingEnlistment(preparingEnlistment));
}
void IEnlistmentNotification.Rollback(Enlistment enlistment)
{
this.Rollback(new DefaultEnlistment(enlistment));
}
private class DefaultEnlistment : IEnlistment
{
private Enlistment enlistment;
public DefaultEnlistment(Enlistment enlistment)
{
this.enlistment = enlistment;
}
public void Done()
{
this.enlistment.Done();
}
}
private class DefaultPreparingEnlistment : DefaultEnlistment, IPreparingEnlistment
{
private PreparingEnlistment enlistment;
public DefaultPreparingEnlistment(PreparingEnlistment enlistment) : base(enlistment)
{
this.enlistment = enlistment;
}
public void Prepared()
{
this.enlistment.Prepared();
}
}
}
下面是一个依赖 ITransactionManager 来处理其事务工作的类的示例:
public class Foo
{
private ITransactionManager transactionManager;
public Foo(ITransactionManager transactionManager)
{
this.transactionManager = transactionManager;
}
public void DoSomethingTransactional()
{
var command = new TransactionalCommand();
using (var scope = this.transactionManager.CreateScope(TransactionScopeOption.Required))
{
this.transactionManager.CurrentTransaction.EnlistVolatile(command, EnlistmentOptions.None);
command.Execute();
scope.Complete();
}
}
private class TransactionalCommand : Enlistable
{
public void Execute()
{
// Do some work here...
}
public override void Commit(IEnlistment enlistment)
{
enlistment.Done();
}
public override void Rollback(IEnlistment enlistment)
{
// Do rollback work...
enlistment.Done();
}
public override void Prepare(IPreparingEnlistment enlistment)
{
enlistment.Prepared();
}
public override void InDoubt(IEnlistment enlistment)
{
enlistment.Done();
}
}
}