代码之家  ›  专栏  ›  技术社区  ›  nightcoder

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

  •  26
  • nightcoder  · 技术社区  · 15 年前

    了解代码块是否在TransactionScope中的最佳方法是什么?
    当前交易是一种可实现的方式还是有任何微妙之处?
    是否可以通过反射访问内部ContextData.CurrentData.CurrentScope(在System.Transactions中)?如果是,怎么办?

    2 回复  |  直到 15 年前
        1
  •  39
  •   Thomas Levesque    15 年前

    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
    
        2
  •  4
  •   nightcoder    15 年前

    这里有更可靠的方法(如我前面所说的,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);
    }