欢迎访问本站!

首页科技正文

皇冠管理端(www.9cx.net):浅谈C#更改令牌ChangeToken

admin2021-09-0350

欧博代理

欢迎进入欧博代理(www.aLLbetgame.us),欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

,

前言

    在上篇文章浅谈C#作废令牌CancellationTokenSource一文中我们解说了CancellationTokenSource,它的主要功效就是分发一个令牌,当我作废令牌我可以举行一些回调操作或者通过令牌状态得知被作废。在上文的末尾处我们也提到了,默认情形下CancellationTokenSource发生的Token是一次性的,Cancel操作之后就没设施再复用了,只能释放掉了。而微软也很知心的为我们提供了一个解决方案来解决这问题,那就是我们今天要说的更改令牌ChangeToken,它看起来可以让CancellationTokenSource发生的Token多次触发,本文我们就来解说ChangeToken相关。

简朴示例

    要想更好的领会一个新的知识,首先知道它是做啥的,其次要知道它怎么做。以是照样老礼貌,咱们先通过简朴的示例最先,这样更利便领会。ChangeToken自己是一个静态类,它的焦点入口OnChange方式包罗两个参数,一个是转达IChangeToken接口实例来获取令牌,另一个是令牌作废之后举行的回调操作。博主本人知道的关于IChangeToken接口的在CLR中的实现类有两个,划分是CancellationChangeTokenCompositeChangeToken类,接下来咱们就划分先容一下这两个类的简朴使用。

CancellationChangeToken示例

咱们先来演示CancellationChangeToken类的使用方式,这也是默认情形下可以使用ChangeToken的最简朴方式。首先界说一个TestCancellationChangeToken类来包装一下CancellationChangeToken,实现如下

public class TestCancellationChangeToken
{
    private CancellationTokenSource tokenSource;

    /// <summary>
    /// 获取CancellationChangeToken实例方式
    /// </summary>
    public CancellationChangeToken CreatChanageToken()
    {
        tokenSource = new CancellationTokenSource();
        return new CancellationChangeToken(tokenSource.Token);
    }

    /// <summary>
    /// 作废CancellationTokenSource
    /// </summary>
    public void CancelToken()
    {
        tokenSource.Cancel();
    }
}

这个类异常简朴,包罗一个CancellationTokenSource类型的属性,一个确立CancellationChangeToken实例的方式和一个作废CancellationTokenSource的CancelToken方式。注重看实现的CreatChanageToken方式,这个方式每次挪用都需要确立一个新的CancellationTokenSource和CancellationChangeToken实例,确立CancellationChangeToken实例需要转达CancellationToken实例。CancelToken方式里是挪用的CancellationTokenSource的Cancel方式。接下来我们就来看一下若何使用界说的这个类

//声明类的实例
TestCancellationChangeToken cancellationChangeToken = new TestCancellationChangeToken();
ChangeToken.OnChange(() => cancellationChangeToken.CreatChanageToken(), () =>
{
    System.Console.WriteLine($"{DateTime.Now:HH:mm:ss}被触发可一次");
});

//模拟多次挪用CancelToken
for (int i = 0; i < 3; i++)
{
    Thread.Sleep(1000);
    cancellationChangeToken.CancelToken();
}

上面的示例演示了通过ChangeToken类使用我们界说的TestCancellationChangeToken类,ChangeToken的OnChange方式转达了确立新CancellationChangeToken实例的方式委托,第二个参数则是作废令牌的回调操作,这样便可以重复的使用作废操作,为了演示效果在循环里重复挪用CancelToken方式显示的打印效果是

16:40:15被触发可一次
16:40:16被触发可一次
16:40:17被触发可一次

CancellationChangeToken类是通过ChangeToken实现重复作废触发挪用的简质朴现,两者将连系的时刻需要自己包装一下,由于ChangeToken的第一个参数需要每次获取CancellationChangeToken实例的委托,以是需要将它包装到事情类中。

CompositeChangeToken示例

现实开发中许多时刻都需要一些关联的场景,好比我触发了一个作废操作,我想把和这个相关联的其它操作也作废,也就是咱们说的有相关性。CompositeChangeToken正是可以绑定一个相关性的IChangeToken聚集,当这个IChangeToken聚集中有任何一个实例举行作废操作的时刻,当前CompositeChangeToken实例也会执行作废操作,咱们就大致演示一下它的使用方式,首先是界说一个使用类TestCompositeChangeToken来模拟包装CompositeChangeToken实例

public class TestCompositeChangeToken
{
    //声明一个CancellationTokenSource聚集
    private List<CancellationTokenSource> _cancellationTokenSources;

    /// <summary>
    /// 获取CompositeChangeToken实例方式
    /// </summary>
    public CompositeChangeToken CreatChanageToken()
    {
        //初始化三个CancellationTokenSource实例
        var firstCancellationTokenSource = new CancellationTokenSource();
        var secondCancellationTokenSource = new CancellationTokenSource();
        var threeCancellationTokenSource = new CancellationTokenSource();

        //划分注册一个回调操作用于演示
        firstCancellationTokenSource.Token.Register(() => System.Console.WriteLine("firstCancellationTokenSource被作废"));
        secondCancellationTokenSource.Token.Register(() => System.Console.WriteLine("secondCancellationTokenSource被作废"));
        threeCancellationTokenSource.Token.Register(() => System.Console.WriteLine("threeCancellationTokenSource被作废"));

        //加入到聚集还
        _cancellationTokenSources = new List<CancellationTokenSource>
        {
            firstCancellationTokenSource,
            secondCancellationTokenSource,
            threeCancellationTokenSource
        };

        //天生CancellationChangeToken聚集
        var cancellationChangeTokens = _cancellationTokenSources.Select(i => new CancellationChangeToken(i.Token)).ToList();
        //转达给CompositeChangeToken
        var compositeChangeToken = new CompositeChangeToken(cancellationChangeTokens);
        //给CompositeChangeToken实例注册一个作废回调利便演示
        compositeChangeToken.RegisterChangeCallback(state => System.Console.WriteLine("compositeChangeToken被作废"),null);

        return compositeChangeToken;
    }

    /// <summary>
    /// 作废CancellationTokenSource
    /// </summary>
    public void CancelToken()
    {
        //利便演示效果在_cancellationTokenSources聚集随便获取一个作废
        _cancellationTokenSources[new Random().Next(_cancellationTokenSources.Count)].Cancel();
    }
}

这里我界说了一个类,在获取CompositeChangeToken实例的CreatChanageToken方式中确立了三个CancellationTokenSource实例,然后用这三个实例初始化了一个CancellationChangeToken聚集,用这个聚集初始化了一个CompositeChangeToken实例,来模拟聚集中的CancellationChangeToken实例和CompositeChangeToken实例的相关性。CancelToken方式中随机获取了一个CancellationTokenSource实例举行作废操作,来更好的演示相关性。由于CompositeChangeToken类也实现了IChangeToken接口,以是用起来都一样,大致如下

//声明类的实例
TestCompositeChangeToken compositeChangeToken = new TestCompositeChangeToken();
ChangeToken.OnChange(() => compositeChangeToken.CreatChanageToken(), () =>
{
    System.Console.WriteLine($"{DateTime.Now:HH:mm:ss}被触发可一次");
});

//模拟多次挪用CancelToken
for (int i = 0; i < 3; i++)
{
    Thread.Sleep(1000);
    compositeChangeToken.CancelToken();
}

为了演示可以重复触发作废操作,这里依然使用循环的方式模拟多次触发。由于存在相关性,以是打印的执行效果如下

12:05:18被触发可一次
compositeChangeToken被作废
secondCancellationTokenSource被作废

12:05:19被触发可一次
compositeChangeToken被作废
firstCancellationTokenSource被作废

12:05:20被触发可一次
compositeChangeToken被作废
secondCancellationTokenSource被作废

从效果上可以看到任何一个相关联CancellationChangeToken实例的CancellationTokenSource实例被作废的话,与其相关的CompositeChangeToken实例也执行了作废操作,在有些场景下照样对照适用的。

源码探讨

上面我们通过简朴的示例大致领会了ChangeToken是做啥的,以及它怎么使用。通过名字可以得知,它叫更改令牌,说明可以动态发生令牌的值。它涉及到了几个焦点的操作相关划分是IChangeToken接口、CancellationChangeToken、CompositeChangeToken和ChangeToken静态类,通过上面咱们的示例和解说我们大致领会了这几个类型的关系,为了利便阅读和头脑带入咱们就根据利便明白的顺序来挨个解说。

友谊提醒:本文设计到粘贴出来的相关源码,这些源码是省略掉一部门历程的。由于我们主要是领会它的实现,无关紧要的代码可能会影响阅读效果。而且这次的GitHub源码地址我替换为https://hub.fastgit.org而没有使用官方的https://github.com,主要是GitHub近期很不稳固经常打不开。fastgit是github的镜像网站,展示的内容是完全一致的,最主要的是打开很流通。

IChangeToken接口

首先即是IChangeToken接口,它是整个ChangeToken系列的入口操作,ChangeToken的OnChange操作也是通过它的实现类提议的。它的作用就是获取一个可以更改的令牌,也就是可以重复触发的令牌,咱们就先来看一下它的实现[点击查看源码]

public interface IChangeToken
{
    /// <summary>
    /// 用来标识是否发生过更改
    /// </summary>
    bool HasChanged { get; }

    /// <summary>
    /// 指示令牌是否支持回调
    /// </summary>
    bool ActiveChangeCallbacks { get; }

    /// <summary>
    /// 适时牌作废时执行的回调
    /// </summary>
    /// <param name="callback">回调执行委托</param>
    /// <param name="state">回调委托的参数</param>
    /// <returns>An <see cref="IDisposable"/> that is used to unregister the callback.</returns>
    IDisposable RegisterChangeCallback(Action<object> callback, object state);
}

它界说的接口成员异常简朴,总结起来就是两类,一个是判断是否发生过更改相关即作废操作,一个是发生过更改之后的回调操作。它只是界说一个尺度任何实现这个尺度的类都具备被ChangeToken的OnChange方式提供可替换令牌的能力。

CancellationChangeToken实现

上面我们领会了IChageToken接口界说的成员相关,而CancellationChangeToken则是IChageToken接口最常使用默认的实现,领会了它的实现,我们就可以更好的知道ChangeToken的OnChange方式是若何事情的,以是这里我选择了先解说CancellationChangeToken相关的实现,这样会让接下来的阅读变得更容易明白。好了直接看它的实现[点击查看源码]

public class CancellationChangeToken : IChangeToken
{
    /// <summary>
    /// 唯一组织函数通过CancellationChangeToken初始化
    /// </summary>
    public CancellationChangeToken(CancellationToken cancellationToken)
    {
        Token = cancellationToken;
    }

    /// <summary>
    /// 由于它是通过CancellationToken实现具备回调的能力
    /// </summary>
    public bool ActiveChangeCallbacks { get; private set; } = true;

    /// <summary>
    /// 凭证CancellationToken的IsCancellationRequested属性判断令牌是否已作废
    /// </summary>
    public bool HasChanged => Token.IsCancellationRequested;

    /// <summary>
    /// 吸收转达进来的CancellationToken
    /// </summary>
    private CancellationToken Token { get; }

    /// <summary>
    /// 注册回调操作
    /// </summary>
    /// <returns></returns>
    public IDisposable RegisterChangeCallback(Action<object> callback, object state)
    {
        try
        {
            //本质照样通过CancellationToken完成它回调操作的功效
            return Token.UnsafeRegister(callback, state);
        }
        catch (ObjectDisposedException)
        {
            ActiveChangeCallbacks = false;
        }
        return NullDisposable.Instance;
    }

    private class NullDisposable : IDisposable
    {
        public static readonly NullDisposable Instance = new NullDisposable();

        public void Dispose()
        {
        }
    }
}

通过上面的代码我们可以得知,CancellationChangeToken的本质照样CancellationToken的包装类,由于我们看到了CancellationChangeToken类的焦点操作实现都是依赖的CancellationChangeToken类的实现完成的。它的HasChanged属性RegisterChangeCallback方式都是直接挪用的CancellationChangeToken类的实现。

ChangeToken类的实现

上面我们解说了IChangeToken接口的相关实现,也说明晰由于ChangeToken类是依赖IChangeToken接口实现来完成的,以是咱们是从IChangeToken类最先解说的。领会了上面的实现之后,咱们就可以直接来看ChangeToken相关的实现了,而我们使用的就是它的OnChange方式[点击查看源码]

皇冠管理端

www.9cx.net)实时更新发布最新最快最有效的皇冠管理端网址,包括皇冠管理端手机网址,皇冠管理端备用网址,皇冠管理端最新网址,皇冠管理端足球网址,皇冠管理端网址大全。

public static IDisposable OnChange(Func<IChangeToken> changeTokenProducer, Action changeTokenConsumer)
{
    return new ChangeTokenRegistration<Action>(changeTokenProducer, callback => callback(), changeTokenConsumer);
}

public static IDisposable OnChange<TState>(Func<IChangeToken> changeTokenProducer, Action<TState> changeTokenConsumer, TState state)
{
    return new ChangeTokenRegistration<TState>(changeTokenProducer, changeTokenConsumer, state);
}

它的OnChange方式实在是包罗两个重载的,一个是无参委托一个是有参委托。无参委托没啥好说的,通过有参回调我们可以给回调转达参数,这个参数是方式转达每次回调委托获取的值取决于State自己的值是什么。最主要的是它们两个都是返回了ChangeTokenRegistration<T>类的实例,也就是说OnChange方式自己是一个外观用来隐藏ChangeTokenRegistration 这个类的详细信息,由于ChangeTokenRegistration只需要在ChangeToken内部使用。那我们就直接看一下ChangeTokenRegistration内部类的实现[点击查看源码]

private class ChangeTokenRegistration<TState> : IDisposable
{
    //生产IChangeToken实例的委托
    private readonly Func<IChangeToken> _changeTokenProducer;
    //回调委托
    private readonly Action<TState> _changeTokenConsumer;
    //回调参数
    private readonly TState _state;
    public ChangeTokenRegistration(Func<IChangeToken> changeTokenProducer, Action<TState> changeTokenConsumer, TState state)
    {
        _changeTokenProducer = changeTokenProducer;
        _changeTokenConsumer = changeTokenConsumer;
        _state = state;

        //执行changeTokenProducer获得IChangeToken实例
        IChangeToken token = changeTokenProducer();
        //挪用RegisterChangeTokenCallback方式转达IChangeToken实例
        RegisterChangeTokenCallback(token);
    }
}

通过上面我们领会到ChangeTokenRegistration正是实现ChangeToken效果的焦点,而它的组织函数里通过执行转达进来发生IChangeToken新实例的委托获得了新的IChangeToken实例。这里需要注重,每次执行Func<IChangeToken> 都市获得新的IChangeToken实例。然后挪用了RegisterChangeTokenCallback方式,而这个方式只需要转达获得的IChangeToken实例即可。接下来我们只需要看RegisterChangeTokenCallback方式实现即可[点击查看源码]

private void RegisterChangeTokenCallback(IChangeToken token)
{
    //给IChangeToken实例注册回调操作
    //回调操作正是执行当前ChangeTokenRegistration实例的OnChangeTokenFired方式
    IDisposable registraton = token.RegisterChangeCallback(s => ((ChangeTokenRegistration<TState>)s).OnChangeTokenFired(), this);
    SetDisposable(registraton);
}

从这里我们可以看出ChangeTokenRegistration 的RegisterChangeTokenCallback方式本质照样使用了IChangeToken实例的RegisterChangeCallback方式来实现的,不外这里的回调执行的是当前ChangeTokenRegistration 实例的 OnChangeTokenFired方式,也就是说令牌作废的时刻挪用的就是OnChangeTokenFired方式,咱们直接看一下这个方式的实现[点击查看源码]

private void OnChangeTokenFired()
{
    //获取一个新的IChangeToken实例
    IChangeToken token = _changeTokenProducer();
    try
    {
        //执行注册的回调操作
        _changeTokenConsumer(_state);
    }
    finally
    {
        //又挪用了RegisterChangeTokenCallback注册当前IChangeToken实例
        RegisterChangeTokenCallback(token);
    }
}

看上面的代码我第一反映就是豁然爽朗,通过OnChangeTokenFired方式的实现似乎一切都透彻了。首先挪用_changeTokenProducer委托获取新的IChangeToken实例,即我们通过即我们通过ChangeToken的OnChange方式第一个参数转达的委托。然后执行_changeTokenConsumer委托,即我们通过ChangeToken的OnChange方式第二个参数转达的委托。最后转达当前通过_changeTokenProducer委托发生的新IChangeToken实例挪用RegisterChangeTokenCallback方式,即咱们上面的谁人方式,这样就完成了类似一个递归的操作。执行完之后又将这套流程重新注册了一遍,然后形成了这种可以连续触发的操作。
上面的RegisterChangeTokenCallback方式里里挪用了SetDisposable方式,这个方式主要是判断Token有没有被作废。由于我们在使用IChangeToken实例的时刻会涉及到多线程共享的问题,而IChangeToken实例自己设计思量到了线程平安问题,我们可以大致看下SetDisposable的实现[点击查看源码]

private IDisposable _disposable;
private static readonly NoopDisposable _disposedSentinel = new NoopDisposable();
private void SetDisposable(IDisposable disposable)
{
    //读取_disposable实例
    IDisposable current = Volatile.Read(ref _disposable);
    //若是当前_disposable实例即是_disposedSentinel实例则说明当前ChangeTokenRegistration已被释放,
    //则直接释放IChangeToken实例然后返回
    if (current == _disposedSentinel)
    {
        disposable.Dispose();
        return;
    }

    //线程平安交流,若是之前_disposable的值即是_disposedSentinel说明被释放过了
    //则释放IChangeToken实例
    IDisposable previous = Interlocked.CompareExchange(ref _disposable, disposable, current);
    if (previous == _disposedSentinel)
    {
        disposable.Dispose();
    }
    //说明没有被释放过
    else if (previous == current)
    {
    }
    //说明其余线程操作了dispose则直接异常
    else
    {
        throw new InvalidOperationException("Somebody else set the _disposable field");
    }
}

由于ChangeTokenRegistration是实现了IDisposable接口,以是我们可以先看下Dispose方式的实现,这样的话会让人人更好的明白它的这个释放系统[点击查看源码]

public void Dispose()
{
    //由于_disposable初始值是null以是把NoopDisposable实例赋值给_disposable并挪用Dispose方式
    Interlocked.Exchange(ref _disposable, _disposedSentinel).Dispose();
}

由于初始声明_disposable变量的时刻初始值是null,这里把NoopDisposable实例赋值给_disposable并挪用Dispose方式。实在Dispose方式啥也没做就是为了符号一下,由于ChangeTokenRegistration类并未涉及到非托管资源相关的操作。

通过SetDisposable方式连系Dispose方式,我们可以明白在触回调操作的时刻会调SetDisposable方式举行判断ChangeTokenRegistration有没有被释放过,若是已经被释放则直接释放掉转达的IChangToken实例。由于ChangeToken的OnChange方式返回的就是ChangeTokenRegistration实例,若是这个被释放则意味了OnChange转达的IChangeToken实例也必须要释放。

通过上面解说了ChangeTokenRegistration<TState>类的实现我们领会到了ChangeToken类事情的本质,实在异常简朴,为了怕人人没看明了在这里咱们简朴的总结一下ChangeToken的整体事情历程。

  • ChangeToken静态类只包装了OnChange方式,这个方式转达的焦点参数是发生IChangeToken实例的委托和CancellationTokenSource实例作废后的回调操作。这里的IChangeToken实例和ChangeToken静态类没啥关系,就是名字长得像。
  • ChangeToken静态类的OnChange方式本质是包装一个ChangeTokenRegistration<TState>实例。ChangeTokenRegistration是ChangeToken类事情的焦点,它的事情方式是,初始化的时刻天生IChangeToken实例然后挪用RegisterChangeTokenCallback方式,在RegisterChangeTokenCallback方式方式中给IChangeToken实例的RegisterChangeCallback方式注册了回调操作。
  • RegisterChangeCallback回调操作注册一个挪用OnChangeTokenFired方式的操作,通过上面的源码我们知道RegisterChangeCallback本质是给CancellationToken注册回调,以是当CancellationTokenSource挪用Cancel的时刻回执行OnChangeTokenFired方式。
  • OnChangeTokenFired方式是焦点操作,它首先是获取一个新的IChangeToken实例,然后执行注册的回调操作。然后又挪用了RegisterChangeTokenCallback转达了最新获取的IChangeToken实例,这样的话就形成了一个类似递归的操作,而这个递归的终止条件就是ChangeTokenRegistration 有没有被释放。以是才气实现动态更改令牌的效果。

一句话总结一下就是,RegisterChangeCallback中给CancellationChangeToken的回调注册了挪用OnChangeTokenFired方式的操作,OnChangeTokenFired方式中有挪用了RegisterChangeCallback方式给它转达了天生的IChangeToken实例,而回调操作都是统一个,只是不停被新的IChangeToken实例挪用。

CompositeChangeToken实现

上面我们说过之以是最厥后说CompositeChangeToken的实现,完全是由于它属于增强的操作。若是人人明白了简朴的事情方式的流程,然后再去实验领会庞大的操作可能会更容易明白。以是咱们先说了CancellationChangeToken这个IChangeToken最简朴的实现,然后说了ChangeToken静态类,让人人对整体的事情机制有领会,最后咱们再来解说CompositeChangeToken,这样的话人人会很容易就明白这个操作方式的。咱们照样先从入口的组织函数入手吧[点击查看源码]

public class CompositeChangeToken : IChangeToken
{
      public IReadOnlyList<IChangeToken> ChangeTokens { get; }
      public bool ActiveChangeCallbacks { get; }
      public CompositeChangeToken(IReadOnlyList<IChangeToken> changeTokens)
      {
          ChangeTokens = changeTokens ?? throw new ArgumentNullException(nameof(changeTokens));
          //遍历传入的IChangeToken聚集
          for (int i = 0; i < ChangeTokens.Count; i++)
          {
              /**
               * 若是聚集中存在任何一个IChangeToken实例ActiveChangeCallbacks为true
               * 则CompositeChangeToken的ActiveChangeCallbacks也为true
               * 由于CompositeChangeToken可以关联IChangeToken聚集中的任何一个有用实例
               */
              if (ChangeTokens[i].ActiveChangeCallbacks)
              {
                  ActiveChangeCallbacks = true;
                  break;
              }
          }
      }
}

从上面的组织函数可以看出IChangeToken聚集中存在可用的实例即可,由于CompositeChangeToken只需要知道聚集中存在可用的即可,而不是要求所有的IChangeToken都可以用。通过ChangeToken静态类的源码我们可以知道,CancellationTokenSource的Cancel方式执行后挪用的是IChangeToken的RegisterChangeCallback方式,也就是说回调触发的操作就是这个方式,我们来看一下这个方式的实现[点击查看源码]

private CancellationTokenSource _cancellationTokenSource;
public IDisposable RegisterChangeCallback(Action<object> callback, object state)
{
    //焦点方式
    EnsureCallbacksInitialized();
   //这里的CancellationTokenSource注册CompositeChangeToken的回调操作
    return _cancellationTokenSource.Token.Register(callback, state);
}

private static readonly Action<object> _onChangeDelegate = OnChange;
private bool _registeredCallbackProxy;
private List<IDisposable> _disposables;
private readonly object _callbackLock = new object();
private void EnsureCallbacksInitialized()
{
   //判断是否已使用RegisterChangeCallback注册过回调操作,若是不是第一次则直接返回
    if (_registeredCallbackProxy)
    {
        return;
    }

   //加锁 意味着这个操作要线程平安
    lock (_callbackLock)
    {
        if (_registeredCallbackProxy)
        {
            return;
        }
        //实例化CancellationTokenSource,由于RegisterChangeCallback方式里再用
        _cancellationTokenSource = new CancellationTokenSource();
        _disposables = new List<IDisposable>();
        //循环要关联的IChangeToken聚集
        for (int i = 0; i < ChangeTokens.Count; i++)
        {
            //判断注册进来的IChangeToken实例是否支持回调操作
            if (ChangeTokens[i].ActiveChangeCallbacks)
            {
                //给IChangeToken实例注册回调操作执行_onChangeDelegate委托
                IDisposable disposable = ChangeTokens[i].RegisterChangeCallback(_onChangeDelegate, this);
                //返回值加入IDisposable聚集
                _disposables.Add(disposable);
            }
        }
       //标识注册过了,防止重复注册引发的多次触发
        _registeredCallbackProxy = true;
    }
}

上面的代码我们看到了焦点的关联回调操作是执行了_onChangeDelegate委托,它是被OnChange方式初始化的。这一步操作实在就是把关联的IChangeToken实例注册_onChangeDelegate委托操作,咱们来看下CompositeChangeToken的OnChange方式实现[点击查看源码]

private static void OnChange(object state)
{
    //获取转达的CompositeChangeToken实例
    var compositeChangeTokenState = (CompositeChangeToken)state;
    //判断CancellationTokenSource是否被初始化过
    if (compositeChangeTokenState._cancellationTokenSource == null)
    {
        return;
    }

    //加锁 说明这一步是线程平安操作
    lock (compositeChangeTokenState._callbackLock)
    {
        try
        {
            /**
             * 作废当前实例的CancellationTokenSource
             * 这样才气执行CompositeChangeToken注册的回调操作
             */
            compositeChangeTokenState._cancellationTokenSource.Cancel();
        }
        catch
        {
        }
    }
    //获取EnsureCallbacksInitialized方式中注册的聚集,即IChangeToken聚集的回调返回值聚集
    List<IDisposable> disposables = compositeChangeTokenState._disposables;
    //不为null则通过循环的方式挨个释放掉
    Debug.Assert(disposables != null);
    for (int i = 0; i < disposables.Count; i++)
    {
        disposables[i].Dispose();
    }
}

通过上面的OnChange方式我们得知,它主要是实现了在注册进来的随便IChangeToken实例若是发生了作废操作则当前的CompositeChangeToken实例RegisterChangeCallback进来的回调操作也要执行,而且这一步要释放掉所有注册IChangeToken实例,由于只要有一个IChangeToken实例执行了作废操作,则CompositeChangeToken实例和其它注册进来相关联的IChangeToken实例都要作废。
IChangeToken另有一个HasChange属性来标识当前IChangeToken是否被作废,咱们来看下CompositeChangeToken是若何实现这个属性的[点击查看源码]

public bool HasChanged
{
    get
    {
        //若是当前实例的CancellationTokenSource被作废过则说明当前CompositeChangeToken已被作废
        if (_cancellationTokenSource != null && _cancellationTokenSource.Token.IsCancellationRequested)
        {
            return true;
        }

        //循环注册进来的关联的IChangeToken聚集
        for (int i = 0; i < ChangeTokens.Count; i++)
        {
            //若是存在关联的IChangeToken实例有被作废的那么也以为当前CompositeChangeToken已被作废
            if (ChangeTokens[i].HasChanged)
            {
                //挪用OnChange是否关联的IChangeToken实例
                OnChange(this);
                return true;
            }
        }
        //否则则没被作废过
        return false;
    }
}

通过上面的代码可以看到HasChanged属性的设计思绪相符它整体的设计思绪。判断是否作废的标识有两个,若是当前实例的CancellationTokenSource被作废过则说明当前CompositeChangeToken已被作废,另有就是若是存在关联的IChangeToken实例有被作废的那么也以为当前CompositeChangeToken也被作废。好了通过上面这一部门整体的源码,我们可以总结一下CompositeChangeToken的整体实现思绪。

  • CompositeChangeToken的作废回调操作分为两部门,一个是基于转达的IChangeToken聚集中激活更改回调即ActiveChangeCallbacks为true的实例,另一个则是它自身维护通过RegisterChangeCallback注册进来的委托,这个委托是它内部维护的CancellationTokenSource实现的。
  • 由于CompositeChangeToken的RegisterChangeCallback方式中给注册进来的IChangeToken聚集中的每一个ActiveChangeCallbacks的实例注册了作废回调操作,以是当ChangeToken静态类触发RegisterChangeCallback回调操作的时刻回挪用CompositeChangeToken的OnChange方式。
  • CompositeChangeToken的OnChange方式中会作废CompositeChangeToken内部维护的CancellationTokenSource,也就是触发CompositeChangeToken类自己的回调,而且释放注册进来的其他相关联的IChangeToken实例,从而实现了关联作废的操作。

    通过源码探讨部门,我们划分展示了关于IChangeToken接口,以及它最简朴的实现类CancellationChangeToken类的实现,然后凭证CancellationChangeToken类的实现解说了ChangeToken静态类是若何实现动态令牌更改的,最后又探讨了IChangeToken接口的另一个高级的可以关联更改令牌操作的CompositeChangeToken的用法,通过这样一个流程,博主本人以为是更容易明白的。

自界说IChangeToken实现

上面我们看到了CancellationChangeToken的使用方式异常简朴,然则也存在一定的限制,那就是需要外部转达CancellationTokenSource的实例。实在许多时刻我们只需要知道你是IChangeToken实例就好了能知足被ChangeToken静态类使用就好了,至于转达CancellationTokenSource啥的不需要外部体贴,能响应的操作就行了,好比在.Net Core的Configuration系统中的ConfigurationReloadToken,它是用来实现设置发生转变通知ConfigurationProvider重新加载数据完成自动刷新操作,我们来看一下它的实现方式[点击查看源码]

public class ConfigurationReloadToken : IChangeToken
{
    //内部界说了CancellationTokenSource实例
    private CancellationTokenSource _cts = new CancellationTokenSource();

    public bool ActiveChangeCallbacks => true;

    public bool HasChanged => _cts.IsCancellationRequested;

    /// <summary>
    /// 给当前的CancellationTokenSource实例注册操作
    public IDisposable RegisterChangeCallback(Action<object> callback, object state) => _cts.Token.Register(callback, state);

    /// <summary>
    /// 添加OnReload方式,供外部作废使用
    /// </summary>
    public void OnReload() => _cts.Cancel();
}

它在ConfigurationReloadToken类的内部声明晰CancellationTokenSource类型的属性,然后提供了可以作废CancellationTokenSource实例的方式OnReload,这样的话逻辑可以在内部消化,而不像在外部转达。当重新获取它的实例的时刻分外提供一个可获取ConfigurationReloadToken新实例的方式即可[点击查看源码]

private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();
private void RaiseChanged()
{
    //直接交流一个新的ConfigurationReloadToken实例
    ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
    //作废上一个ConfigurationReloadToken实例实现更改通知操作
    previousToken.OnReload();
}

这样的话获取Token的实现就异常简朴了,直接返回ConfigurationReloadToken的属性即可不再需要一堆分外的操作,这样就可以保证每次通过GetReloadToken方式获取的IChangeToken实例都是未失效的。

public IChangeToken GetReloadToken() => _changeToken;

总结

    本文我们解说了ChangeToken相关的系统,设计到了IChangeToken接口的几个实现类和ChangeToken静态类是若何实现通过作废令牌重复触发的,实在本质也就是它的名字,可以动态去更改令牌,实现的大致思绪就是类似递归的操作,在回调通知里获取新的换取令牌实例,重新注册当前回调操作形成递归。由于IChangeToken实例都是引用类型,而我们转达的CancellationTokenSource实例也是引用类型,以是我们在使用的时刻没感受有什么转变,但实在若是你每次打印它的实例都是纷歧样的,由于内部已经替换了新的实例。好了我们大致总结一下

  • IChangeToken接口是知足ChangeToken静态类的必须操作,默认提供的CancellationChangeToken类则是IChangeToken接口最简朴的实现,它是依赖CancellationTokenSource实现注册和作废通知相关操作的。
  • ChangeToken静态类的事情依赖它的OnChange方式注册的参数,一个是获取IChangeToken实例的委托,一个是令牌作废执行的操作。实在现的本质是在CancellationChangeToken的Register方式里注册重新注册的操作。也就是通过ChangeToken静态类的OnChange方式第一个参数委托,执行这个委托获取新的IChangeToken实例,固然它包罗的CancellationChangeToken实例也是最新的。然后ChangeToken静态类的OnChange方式第二个参数,即回调操作重新注册给这个新的实例,这个更改操作对外部都是无感知的,但实在内部早已经替换了新的实例。
  • CompositeChangeToken实现关联作废更改操作的本质是,给一堆IChangeToken实例注册相同的OnChange操作,若是有一个IChangeToken实例执行了作废则通过OnChange方式作废当前CompositeChangeToken实例和相关联的IChangeToken实例,防止统一个CompositeChangeToken实例重复被触发。

这个系列我们解说了作废令牌相关,其焦点都是对CancellationTokenSource的包装,由于默认的CancellationTokenSource的实例默认只能被作废一次,然则许多场景需要能多次甚至无限次触发这种通知,好比.Net Core的Configuration系统,每次设置发生换取都需要执行响应的刷新操作。因此衍生出来了IChangeToken相关,连系辅助的ChangeToken来实现重复更改令牌的操作,实现无限次的触发通知。虽然博主能力和文笔都十分有限,但依然希望同砚们能从中获取收获,这也是作为写作人最大的动力。

迎接扫码关注我的民众号

网友评论