C# 如何知道代码是否在 TransactionScope 内?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/980337/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:46:14  来源:igfitidea点击:

How to know if the code is inside TransactionScope?

c#.nettransactionscope

提问by nightcoder

What is the best way to know if the code block is inside TransactionScope?
Is Transaction.Current a realiable way to do it or there are any subtleties?
Is it possible to access internal ContextData.CurrentData.CurrentScope (in System.Transactions) with reflection? If yes, how?

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

采纳答案by nightcoder

Here is more reliable way (as I said, Transaction.Current can be set manually and it doesn't always mean we are really in TransactionScope). It's also possible to get this information with reflection, but emiting IL works 100 times faster than reflection.

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

回答by Marc Gravell

Transaction.Currentshould be reliable; I've just checked, at this works fine with suppressed transactions, too:

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