- ThreadStatic ThreadLocal . , . , , :
public class Version {
public Version(int number) {
Number = number;
}
public int Number { get; }
public override string ToString() {
return "Version " + Number;
}
}
VersionScope :
public sealed class VersionScope : IDisposable {
private bool _isCompleted;
private bool _isDisposed;
[ThreadStatic] private static Version _currentVersion;
public static Version CurrentVersion => _currentVersion;
public VersionScope(int version) {
_currentVersion = new Version(version);
}
public void Dispose() {
if (_isCompleted || _isDisposed)
return;
var v = _currentVersion;
if (v != null) {
DeleteVersion(v);
}
_currentVersion = null;
_isDisposed = true;
}
public void Complete() {
if (_isCompleted || _isDisposed)
return;
var v = _currentVersion;
if (v != null) {
PushVersion(v);
}
_currentVersion = null;
_isCompleted = true;
}
private void DeleteVersion(Version version) {
Console.WriteLine($"Version {version} deleted");
}
private void PushVersion(Version version) {
Console.WriteLine($"Version {version} pushed");
}
}
, , , Complete Dispose:
public sealed class VersionScope : IDisposable {
private bool _isCompleted;
private bool _isDisposed;
private static readonly ThreadLocal<VersionChain> _versions = new ThreadLocal<VersionChain>();
public static Version CurrentVersion => _versions.Value?.Current;
public VersionScope(int version) {
var cur = _versions.Value;
_versions.Value = new VersionChain(new Version(version), cur);
}
public void Dispose() {
if (_isCompleted || _isDisposed)
return;
var cur = _versions.Value;
if (cur != null) {
DeleteVersion(cur.Current);
_versions.Value = cur.Previous;
}
_isDisposed = true;
}
public void Complete() {
if (_isCompleted || _isDisposed)
return;
var cur = _versions.Value;
if (cur != null) {
PushVersion(cur.Current);
_versions.Value = cur.Previous;
}
_isCompleted = true;
}
private void DeleteVersion(Version version) {
Console.WriteLine($"Version {version} deleted");
}
private void PushVersion(Version version) {
Console.WriteLine($"Version {version} pushed");
}
private class VersionChain {
public VersionChain(Version current, VersionChain previous) {
Current = current;
Previous = previous;
}
public Version Current { get; }
public VersionChain Previous { get; }
}
}
, . ( , , - ):
static void Main(string[] args) {
PrintCurrentVersion();
using (var s1 = new VersionScope(1)) {
PrintCurrentVersion();
s1.Complete();
PrintCurrentVersion();
using (var s2 = new VersionScope(2)) {
using (var s3 = new VersionScope(3)) {
PrintCurrentVersion();
}
PrintCurrentVersion();
s2.Complete();
}
PrintCurrentVersion();
}
Console.ReadKey();
}
private static void PrintCurrentVersion() {
Console.WriteLine("Current version: " + VersionScope.CurrentVersion);
}
, , ThreadLocal , async . AsyncLocal, . , VersionScope, , . - TransactionScopeAsyncFlowOption, TransactionScope, , .
:
public sealed class VersionScope : IDisposable {
private bool _isCompleted;
private bool _isDisposed;
private readonly bool _asyncFlow;
private static readonly ThreadLocal<VersionChain> _tlVersions = new ThreadLocal<VersionChain>();
private static readonly AsyncLocal<VersionChain> _alVersions = new AsyncLocal<VersionChain>();
public static Version CurrentVersion => _alVersions.Value?.Current ?? _tlVersions.Value?.Current;
private VersionChain CurrentVersionChain => _asyncFlow ? _alVersions.Value : _tlVersions.Value;
public VersionScope(int version, bool asyncFlow = false) {
_asyncFlow = asyncFlow;
var cur = CurrentVersionChain;
if (asyncFlow) {
_alVersions.Value = new VersionChain(new Version(version), cur);
}
else {
_tlVersions.Value = new VersionChain(new Version(version), cur);
}
}
public void Dispose() {
if (_isCompleted || _isDisposed)
return;
var cur = CurrentVersionChain;
if (cur != null) {
DeleteVersion(cur.Current);
if (_asyncFlow) {
_alVersions.Value = cur.Previous;
}
else {
_tlVersions.Value = cur.Previous;
}
}
_isDisposed = true;
}
public void Complete() {
if (_isCompleted || _isDisposed)
return;
var cur = CurrentVersionChain;
if (cur != null) {
PushVersion(cur.Current);
if (_asyncFlow) {
_alVersions.Value = cur.Previous;
}
else {
_tlVersions.Value = cur.Previous;
}
}
_isCompleted = true;
}
private void DeleteVersion(Version version) {
Console.WriteLine($"Version {version} deleted");
}
private void PushVersion(Version version) {
Console.WriteLine($"Version {version} pushed");
}
private class VersionChain {
public VersionChain(Version current, VersionChain previous) {
Current = current;
Previous = previous;
}
public Version Current { get; }
public VersionChain Previous { get; }
}
}
:
static void Main(string[] args) {
Test();
Console.ReadKey();
}
static async void Test() {
PrintCurrentVersion();
using (var s1 = new VersionScope(1, asyncFlow: true)) {
await Task.Delay(100);
PrintCurrentVersion();
await Task.Delay(100);
s1.Complete();
await Task.Delay(100);
PrintCurrentVersion();
using (var s2 = new VersionScope(2, asyncFlow: true)) {
using (var s3 = new VersionScope(3, asyncFlow: true)) {
PrintCurrentVersion();
}
await Task.Delay(100);
PrintCurrentVersion();
s2.Complete();
}
await Task.Delay(100);
PrintCurrentVersion();
}
}
private static void PrintCurrentVersion() {
Console.WriteLine("Current version: " + VersionScope.CurrentVersion);
}