/* the previous value is stored in order to avoid the overhead of an stack or linked list */ public ThreadVariableValueScope(ThreadVariable <T> key, T value, ThreadVariableValueScope previous) { threadId = Thread.CurrentThread.ManagedThreadId; this.key = key; this.value = value; this.previous = previous; }
/// <summary> /// Returns a scope for the <paramref name="value"/>. The value is held in the /// current thread, until the scope is disposed. /// </summary> /// <remarks> /// Within the scope, the value will be available via <see cref="Current"/> and /// <see cref="CurrentOrDefault"/>, <see cref="HasCurrent"/> will always /// be <value>true</value>. /// </remarks> public IDisposable Use(T value) { ThreadVariableValueScope old; var v = EnsuredValues; v.TryGetValue(this, out old); return(v[this] = new ThreadVariableValueScope(this, value, old)); }
/// <summary> /// Disposes the scope <paramref name="scopeToDispose"/> and it's other /// nested scopes. /// </summary> private void DisposeScope(ThreadVariableValueScope scopeToDispose) { // 1) The programmer simply did an error if he tried to dispose a scope on a different thread // 2) If the garbage collection takes care of disposal, it will get an error and ignore it if (Thread.CurrentThread.ManagedThreadId != scopeToDispose.threadId) { throw new InvalidOperationException("The thread variable value scope " + "has to be disposed on the same thread it was created on!"); } /* Let's say we have three scopes: outer, middle and inner. * * When disposing 'inner', usually the value is * recovered to 'middle'. * But if 'middle' is disposed before 'inner', * 'inner' should be disposed automatically, too. * * Else, disposing 'inner' afterwards, would end in * setting the current value to 'middle' - which * already is disposed */ /* start on the current scope wich is always scopeToDispose * or one of its inner scopes - actually the inner most one */ var v = EnsuredValues; ThreadVariableValueScope innerMost; v.TryGetValue(this, out innerMost); // dispose all inner scopes while (innerMost != scopeToDispose) { innerMost.MarkAsDisposed(); innerMost = innerMost.previous; } // mark current one as disposed scopeToDispose.MarkAsDisposed(); // remove, or recover previous value if (scopeToDispose.previous == null) { v.Remove(this); } else { v[this] = scopeToDispose.previous; } }