如何知道代码是否在TransactionScope中?

nig*_*der 28 .net c# transactionscope

知道代码块是否在TransactionScope内的最佳方法是什么?
Transaction.Current是一种可行的方式,还是有任何微妙之处?
是否可以使用反射访问内部ContextData.CurrentData.CurrentScope(在System.Transactions中)?如果有,怎么样?

Mar*_*ell 42

Transaction.Current应该是可靠的; 我刚检查过,在这种情况下,抑制交易的效果也很好:

Console.WriteLine(Transaction.Current != null); // false
using (TransactionScope tran = new TransactionScope())
{
    Console.WriteLine(Transaction.Current != null); // true
    using (TransactionScope tran2 = new TransactionScope(
          TransactionScopeOption.Suppress))
    {
        Console.WriteLine(Transaction.Current != null); // false
    }
    Console.WriteLine(Transaction.Current != null); // true
}
Console.WriteLine(Transaction.Current != null); // false
Run Code Online (Sandbox Code Playgroud)

  • 如果TransactionScope已完成,但仍未处置,则Syste.Transactions.Transaction.Curre会引发异常 (2认同)

nig*_*der 6

这是一种更可靠的方法(正如我所说的,Transaction.Current可以手动设置,并不总是意味着我们确实在TransactionScope中)。也可以通过反射获得此信息,但是发射IL的速度是反射的100倍。

private Func<TransactionScope> _getCurrentScopeDelegate;

bool IsInsideTransactionScope
{
  get
  {
    if (_getCurrentScopeDelegate == null)
    {
      _getCurrentScopeDelegate = CreateGetCurrentScopeDelegate();
    }

    TransactionScope ts = _getCurrentScopeDelegate();
    return ts != null;
  }
}

private Func<TransactionScope> CreateGetCurrentScopeDelegate()
{
  DynamicMethod getCurrentScopeDM = new DynamicMethod(
    "GetCurrentScope",
    typeof(TransactionScope),
    null,
    this.GetType(),
    true);

  Type t = typeof(Transaction).Assembly.GetType("System.Transactions.ContextData");
  MethodInfo getCurrentContextDataMI = t.GetProperty(
    "CurrentData", 
    BindingFlags.NonPublic | BindingFlags.Static)
    .GetGetMethod(true);

  FieldInfo currentScopeFI = t.GetField("CurrentScope", BindingFlags.NonPublic | BindingFlags.Instance);

  ILGenerator gen = getCurrentScopeDM.GetILGenerator();
  gen.Emit(OpCodes.Call, getCurrentContextDataMI);
  gen.Emit(OpCodes.Ldfld, currentScopeFI);
  gen.Emit(OpCodes.Ret);

  return (Func<TransactionScope>)getCurrentScopeDM.CreateDelegate(typeof(Func<TransactionScope>));
}

[Test]
public void IsInsideTransactionScopeTest()
{
  Assert.IsFalse(IsInsideTransactionScope);
  using (new TransactionScope())
  {
    Assert.IsTrue(IsInsideTransactionScope);
  }
  Assert.IsFalse(IsInsideTransactionScope);
}
Run Code Online (Sandbox Code Playgroud)

  • 它出现在.Net 4.5中,“ CurrentData”已重命名为“ TLSCurrentData” (3认同)
  • 我想知道在生产环境中使用这段代码四年后,您是否改变了对“可靠”的定义。 (2认同)