zoukankan      html  css  js  c++  java
  • RX库中的IDisposable对象

    IDisposable是.net中的主动资源释放接口,它是在编程过程中经常使用到的一个接口,本文介绍一下微软在Rx.NET中提供的一系列常用的Disposable类,通过它们可以简化我们的程序代码,提高代码质量。

    IDisposable:

    一个简单的IDisposable接口实现如下

    class DisposableObject : IDisposable
    {
        private readonly string name = null;
     
        public DisposableObject(string name)
        {
            this.name = name;
        }
     
        public void Dispose()
        {
            Console.WriteLine("{0} - Disposed", this.name);
        }
    }
    View Code

    注: 这个例子并不是合适的实现,主要是为了后面的代码演示使用。

    ICancelable

    RX框架在Disposable接口上扩展了一下,增加了一个查看是否被释放的状态,定义了一个ICancelable接口

      public interface ICancelable : IDisposable
      {
        bool IsDisposed { get; }
      }

    除了Disposable.Empty外,RX框架提供的都是ICancelable接口对象。

     

    Disposable.Empty

    Disposable.Empty返回的是一个没有任何功能的IDisposable对象,是一个IDisposable的NullObject模式的实现。

    它的Dispose函数可以使用,但没有任何行为。

     

    Disposable.Create

    Disposable.Create可以快速构建一个IDisposable对象,它接受一个委托,当Dispose函数调用时,执行该委托。

    var d = Disposable.Create(() =>
    {
        Console.WriteLine("Disposed");
    });
    d.Dispose();
    View Code

    BooleanDisposable

    BooleanDisposable是一个简单的ICancelable的实现,它的Dispose操作也没有任何行为,但可以查看该函数是否执行过。

    var d = new BooleanDisposable();
    Console.WriteLine(d.IsDisposed);
    
    d.Dispose(); 
    Console.WriteLine(d.IsDisposed);
    View Code

    由于不能控制该对象的Dispose行为,这个对象用得到不是很多,往往用来作为一个开关变量使用。

    CancellationDisposable

    CancellationDisposable可将一个CancellationTokenSource对象封装为Disposable对象

    • 当Dispose函数调用时,调用Cancel函数。
    • 查看IsPosed状态时,返回IsCancellationRequested状态

    简单的示例如下:

    var source = new CancellationTokenSource();
    source.Token.Register(() => Console.WriteLine("Cancelled"));
    var d = new CancellationDisposable(source);
    Console.WriteLine(d.IsDisposed);
    Console.WriteLine(source.IsCancellationRequested);
    View Code

    RefCountDisposable

    RefCountDisposable也是一个封装型的Disposable对象,不过它是一个引用计数型的封装。

    • 新建RefCountDisposable对象后,引用计数为1
    • 调用GetDisposable可以生成一个新的引用Disposable封装,引用技术加1
    • 调用RefCountDisposable对象和GetDisposable生成的Disposable对象时,引用计数都减1
    • 引用计数为0时,释放封装的Disposable对象

    这里需要注意的时,当调用RefCountDisposable. Dispose函数时,可能引用计数还不为0,此时还是可以继续调用GetDisposable函数增加引用计数的。

    简单的示例如下:

    var d    = new RefCountDisposable(new DisposableObject("#1"));
    var ref1 = d.GetDisposable();
    var ref2 = d.GetDisposable();
    Console.WriteLine("ref2 - Dispose");
    ref2.Dispose();
    Console.WriteLine("ref1 - Dispose");
    ref1.Dispose();
    Console.WriteLine("Dispose");
    d.Dispose();
    View Code

    这个类在释放共享资源的时候非常有用,例如我们做视频点播的时候,当有多个客户端点播视频时,每个客户端都需要维护引用计数,当所有客户端都退出的时候,会自动Dispose,注销视频源。

    CompositeDisposable

    CompositeDisposable用于聚合多个disposable对象,形成一个新的disposable对象,它主要有Add,Clear,Dispose三个函数。

    • Add函数将子Disposable对象添加到集合
    • Clear函数删除集合类所有的Disposable对象,同时调用子Disposable对象的Dispose函数
    • Dispose函数释放CompositeDisposable对象:释放所有子Disposable对象。
    • 如果CompositeDisposable对象已经释放,再次调用Add函数时,不会添加到集合,而是直接调用其子对象的Dispose函数。

    简单的示例如下:

    var d = new CompositeDisposable();
    d.Add(new DisposableObject("#1"));
    d.Add(new DisposableObject("#2"));
    d.Add(new DisposableObject("#3"));
    d.Clear();
    Console.WriteLine("----------");
    d.Add(new DisposableObject("#4"));
    d.Add(new DisposableObject("#5"));
    d.Add(new DisposableObject("#6"));
    d.Dispose();
    Console.WriteLine("----------");
    d.Add(new DisposableObject("#7"));
    View Code

    ContextDisposable

    ContextDisposable对象也是一个复合Disposable对象

    • 它主要用于封装一个Disposable对象,将其与一个SynchronizationContext上下文关联,
    • 封装后生成的ContextDisposable对象的Disposable函数会Post到上下文线程中执行。

    简单的示例如下:

    var context = SynchronizationContext.Current;
    var obj     = new DisposableObject("#1");
    var d       = new ContextDisposable(context, obj);
    d.Dispose(); 
    View Code

    这个对象用于释放UI对象非常方便,另外,也可以实现用于将一些Dispose函数推送到指定的队列中串行执行,从而避免一些并发问题。

    ScheduledDisposable

    ScheduledDisposable和ContextDisposable类似,也是用于封装一个Disposable对象,不过它是将其Dispose函数推送到指定的IScheduler中执行。

    var scheduler = ThreadPoolScheduler.Instance;
    var obj       = new DisposableObject("#1");
    var d         = new ScheduledDisposable(scheduler, obj);
    d.Dispose();
    View Code

    SingleAssignmentDisposable

    SingleAssignmentDisposable是一个关联型的Disposable对象

    • 可以通过它的Disposable属性关联到子Dispose对象。
    • 当执行Dispose函数时,执行的是子Dispose对象的Dispose函数,如果没有关联子Dispose对象,则不执行任何操作。
    • 已经执行Dispose函数后,再次使用Disposable属性关联后无法关联,直接会调用子对象的Dispose函数。

    SingleAssignmentDisposable的关联有一个Single特点,它主要体现为:

    • 如果已经通过Disposable属性关联后,再次调用Disposable属性关联时会抛异常

    简单的示例如下:

    var d = new SingleAssignmentDisposable();
    d.Disposable = new DisposableObject("#1");
    try
    {
        d.Disposable = new DisposableObject("#2"); //--- 例外発生
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine(ex.Message);
    }
    d.Dispose();
    d.Disposable = new DisposableObject("#3");
    View Code

    输出结果为:

    Disposable has already been assigned.
    #1 – Disposed
    #3 - Disposed

     

    MultipleAssignmentDisposable

    MultipleAssignmentDisposable和SingleAssignmentDisposable类似,区别是其关联的multi特性,它的特点是:

    • 如果已经通过Disposable属性关联后,再次调用Disposable属性是会覆盖关联

    简单的示例如下:

    var d = new MultipleAssignmentDisposable();
    d.Disposable = new DisposableObject("#1");
    d.Disposable = new DisposableObject("#2");
    d.Dispose();
    d.Disposable = new DisposableObject("#3");
    View Code

    输出结果为:

    #2 – Disposed
    #3 - Disposed

     

    SerialDisposable

    SerialDisposable和SingleAssignmentDisposable也类似,不过它的Disposable属性再次关联的策略是:

    • 覆盖关联,同时先释放上一个Disposable对象。

    简单的示例如下:

    var d = new SerialDisposable();
    Console.WriteLine("#1 - Set");
    d.Disposable = new DisposableObject("#1");
    Console.WriteLine("#2 - Set");
    d.Disposable = new DisposableObject("#2");
    Console.WriteLine("Dispose");
    d.Dispose();
    View Code

    输出结果为:

    #1 – Set
    #2 – Set
    #1 – Disposed
    Dispose
    #2 – Disposed
    #3 – Set
    #3 - Disposed

     

     

  • 相关阅读:
    codeforces 765 F Souvenirs 线段树+set
    codeforces 768 E 变形NIM博弈/手写sg函数
    BZOJ 1001 狼抓兔子(网络流)
    BZOJ 2957 楼房重建 (分块)
    CodeForces
    CodeForces
    HYSBZ
    SPOJ
    Codeforces-963 D Frequency of String
    中石油2019寒假集训第一场(新生场)(补题)
  • 原文地址:https://www.cnblogs.com/TianFang/p/9096001.html
Copyright © 2011-2022 走看看