CompositeChangeToken
An IChangeToken that represents one or more IChangeToken instances.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Microsoft.Extensions.Primitives
{
[NullableContext(1)]
[Nullable(0)]
[DebuggerDisplay("HasChanged = {HasChanged}")]
public class CompositeChangeToken : IChangeToken
{
private static readonly Action<object> _onChangeDelegate = OnChange;
private readonly object _callbackLock = new object();
private CancellationTokenSource _cancellationTokenSource;
private List<IDisposable> _disposables;
[MemberNotNullWhen(true, "_cancellationTokenSource")]
[MemberNotNullWhen(true, "_disposables")]
private bool RegisteredCallbackProxy {
[MemberNotNullWhen(true, "_cancellationTokenSource")]
[MemberNotNullWhen(true, "_disposables")]
get;
[MemberNotNullWhen(true, "_cancellationTokenSource")]
[MemberNotNullWhen(true, "_disposables")]
set;
}
public IReadOnlyList<IChangeToken> ChangeTokens { get; }
public bool HasChanged {
get {
if (_cancellationTokenSource != null && _cancellationTokenSource.Token.IsCancellationRequested)
return true;
for (int i = 0; i < ChangeTokens.Count; i++) {
if (ChangeTokens[i].HasChanged) {
OnChange(this);
return true;
}
}
return false;
}
}
public bool ActiveChangeCallbacks { get; }
public CompositeChangeToken(IReadOnlyList<IChangeToken> changeTokens)
{
if (changeTokens == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.changeTokens);
ChangeTokens = changeTokens;
int num = 0;
while (true) {
if (num >= ChangeTokens.Count)
return;
if (ChangeTokens[num].ActiveChangeCallbacks)
break;
num++;
}
ActiveChangeCallbacks = true;
}
public IDisposable RegisterChangeCallback([Nullable(new byte[] {
1,
2
})] Action<object> callback, [Nullable(2)] object state)
{
EnsureCallbacksInitialized();
return _cancellationTokenSource.Token.Register(callback, state);
}
[MemberNotNull("_cancellationTokenSource")]
[MemberNotNull("_disposables")]
private void EnsureCallbacksInitialized()
{
if (!RegisteredCallbackProxy) {
lock (_callbackLock) {
if (!RegisteredCallbackProxy) {
_cancellationTokenSource = new CancellationTokenSource();
_disposables = new List<IDisposable>();
for (int i = 0; i < ChangeTokens.Count; i++) {
if (ChangeTokens[i].ActiveChangeCallbacks) {
IDisposable disposable = ChangeTokens[i].RegisterChangeCallback(_onChangeDelegate, this);
if (_cancellationTokenSource.IsCancellationRequested) {
disposable.Dispose();
break;
}
_disposables.Add(disposable);
}
}
RegisteredCallbackProxy = true;
}
}
}
}
private static void OnChange(object state)
{
CompositeChangeToken compositeChangeToken = (CompositeChangeToken)state;
if (compositeChangeToken._cancellationTokenSource != null) {
lock (compositeChangeToken._callbackLock) {
if (compositeChangeToken._cancellationTokenSource.IsCancellationRequested)
return;
try {
compositeChangeToken._cancellationTokenSource.Cancel();
} catch {
}
}
List<IDisposable> disposables = compositeChangeToken._disposables;
for (int i = 0; i < disposables.Count; i++) {
disposables[i].Dispose();
}
}
}
}
}