ChangeToken
Propagates notifications that a change has occurred.
using System;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Microsoft.Extensions.Primitives
{
[NullableContext(1)]
[Nullable(0)]
public static class ChangeToken
{
private sealed class ChangeTokenRegistration<TState> : IDisposable
{
private sealed class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
private readonly Func<IChangeToken> _changeTokenProducer;
private readonly Action<TState> _changeTokenConsumer;
private readonly TState _state;
private IDisposable _disposable;
private static readonly NoopDisposable _disposedSentinel = new NoopDisposable();
public ChangeTokenRegistration(Func<IChangeToken> changeTokenProducer, Action<TState> changeTokenConsumer, TState state)
{
_changeTokenProducer = changeTokenProducer;
_changeTokenConsumer = changeTokenConsumer;
_state = state;
IChangeToken token = changeTokenProducer();
RegisterChangeTokenCallback(token);
}
private void OnChangeTokenFired()
{
IChangeToken token = _changeTokenProducer();
try {
_changeTokenConsumer(_state);
} finally {
RegisterChangeTokenCallback(token);
}
}
private void RegisterChangeTokenCallback(IChangeToken token)
{
if (token != null) {
IDisposable disposable = token.RegisterChangeCallback(delegate(object s) {
((ChangeTokenRegistration<TState>)s).OnChangeTokenFired();
}, this);
if (token.HasChanged && token.ActiveChangeCallbacks)
disposable?.Dispose();
else
SetDisposable(disposable);
}
}
private void SetDisposable(IDisposable disposable)
{
IDisposable disposable2 = Volatile.Read<IDisposable>(ref _disposable);
if (disposable2 == _disposedSentinel)
disposable.Dispose();
else {
IDisposable disposable3 = Interlocked.CompareExchange<IDisposable>(ref _disposable, disposable, disposable2);
if (disposable3 == _disposedSentinel)
disposable.Dispose();
else if (disposable3 != disposable2) {
throw new InvalidOperationException("Somebody else set the _disposable field");
}
}
}
public void Dispose()
{
Interlocked.Exchange<IDisposable>(ref _disposable, (IDisposable)_disposedSentinel)?.Dispose();
}
}
public static IDisposable OnChange([Nullable(new byte[] {
1,
2
})] Func<IChangeToken> changeTokenProducer, Action changeTokenConsumer)
{
if (changeTokenProducer == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.changeTokenProducer);
if (changeTokenConsumer == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.changeTokenConsumer);
return new ChangeTokenRegistration<Action>(changeTokenProducer, delegate(Action callback) {
callback();
}, changeTokenConsumer);
}
public static IDisposable OnChange<[Nullable(2)] TState>([Nullable(new byte[] {
1,
2
})] Func<IChangeToken> changeTokenProducer, Action<TState> changeTokenConsumer, TState state)
{
if (changeTokenProducer == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.changeTokenProducer);
if (changeTokenConsumer == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.changeTokenConsumer);
return new ChangeTokenRegistration<TState>(changeTokenProducer, changeTokenConsumer, state);
}
}
}