知道代码块是否在TransactionScope内的最佳方法是什么? Transaction.Current是一种可行的方式,还是有任何细微之处? 是否可以使用反射访问内部ContextData.CurrentData.CurrentScope(在System.Transactions中)?如果是,怎么样?
答案 0 :(得分:39)
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
答案 1 :(得分:5)
这是更可靠的方式(正如我所说,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);
}
答案 2 :(得分:0)
有使用表达式的更新版本,不需要System.Transactions
引用。
internal static class TransactionScopeHelper
{
static Func<object?> _getCurrentScopeDelegate = GetTransactionScopeFunc();
public static bool IsInsideTransactionScope
{
get
{
var ts = _getCurrentScopeDelegate();
return ts != null;
}
}
static Func<object?> GetTransactionScopeFunc()
{
var assembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.GetName().Name == "System.Transactions");
if (assembly != null)
{
var t = assembly.GetType("System.Transactions.ContextData");
var currentDataProperty = t.GetProperty("TLSCurrentData", BindingFlags.NonPublic | BindingFlags.Static);
if (currentDataProperty != null)
{
var body = Expression.MakeMemberAccess(null, currentDataProperty);
var lambda = Expression.Lambda<Func<object?>>(body);
return lambda.Compile;
}
}
return () => null;
}
}