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);
}
}

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

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();

BooleanDisposable

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

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

由于不能控制该对象的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);

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();

这个类在释放共享资源的时候非常有用,例如我们做视频点播的时候,当有多个客户端点播视频时,每个客户端都需要维护引用计数,当所有客户端都退出的时候,会自动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"));

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();

这个对象用于释放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();

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");

输出结果为:

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");

输出结果为:

#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();

输出结果为:

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

RX库中的IDisposable对象的更多相关文章

  1. 在EL表达式或者Struts标签库中格式化日期对象,即将Date转换为yyyy-MM-dd格式

    一.EL表达式 首先,在jsp页面引入<fmt> tags,<%@ taglib prefix="fmt" uri="http://java.sun.c ...

  2. vuex中怎么把‘库’中的状态对象赋值给内部对象(三种方法)

    一.通过computed的计算属性直接赋值 import store from '@/store/store' export default{ name: 'count', data(){ retur ...

  3. 在PHP中使用SPL库中的对象方法进行XML与数组的转换

    虽说现在很多的服务提供商都会提供 JSON 接口供我们使用,但是,还是有不少的服务依然必须使用 XML 作为接口格式,这就需要我们来对 XML 格式的数据进行解析转换.而 PHP 中并没有像 json ...

  4. 第一个lucene程序,把一个信息写入到索引库中、根据关键词把对象从索引库中提取出来、lucene读写过程分析

    新建一个Java Project :LuceneTest 准备lucene的jar包,要加入的jar包至少有: 1)lucene-core-3.1.0.jar     (核心包) 2) lucene- ...

  5. SharePoint 2013 文档库中PPT转换PDF

    通过使用 PowerPoint Automation Services,可以从 PowerPoint 二进制文件格式 (.ppt) 和 PowerPoint Open XML 文件格式 (.pptx) ...

  6. C#中对IDisposable接口的理解

    http://blog.sina.com.cn/s/blog_8abeac5b01019u19.html C#中对IDisposable接口的理解 本人最近接触一个项目,在这个项目里面看到很多类实现了 ...

  7. C++模板中的函数对象

    在C++模板类map中一个参数为Compare类型,该类型为一个比较函数,其完整定义如下: template< class Key, class T, class Compare = std:: ...

  8. iOS开发系列--扩展--播放音乐库中的音乐

    众所周知音乐是iOS的重要组成播放,无论是iPod.iTouch.iPhone还是iPad都可以在iTunes购买音乐或添加本地音乐到音乐 库中同步到你的iOS设备.在MediaPlayer.fram ...

  9. [百度空间] [转] 在 Visual C++ 中控制全局对象的初始化顺序

    from: http://blog.csdn.net/classfactory/archive/2004/08/07/68202.aspx 在 C++ 中,同一个翻译单位(.cpp文件)里的全局对象的 ...

随机推荐

  1. 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树

    [题目]BZOJ 1095 [题意]给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\). [算法]括号序 ...

  2. C++笔试易错题集(持续更新)

    1.如下代码输出结果是什么? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include<stdio.h> char *myString() {     ...

  3. %08lx

    u-boot中代码如下: debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr); 对应设备上的打印消息如下: N ...

  4. js如何判断一个对象是不是Array?

    在开发中,我们经常需要判断某个对象是否为数组类型,在Js中检测对象类型的常见方法都有哪些呢? typeof 操作符 对于Function, String, Number ,Undefined 等几种类 ...

  5. react-native 报错

    报错信息: java.lang.RuntimeException: Unable to load script from assets 'index.android.bundle'. Make sur ...

  6. dede列表页调用

    {dede:list pagesize ='16'} <li class="item pull-left"> <a class="item-wrap&q ...

  7. IntelliJ Idea中创建package的问题

    在idea中创建package时,会一直往后面累加 想在com.huayang下面再新建一个service,普通的做法是选中了huayang.dao--->然后右键--->新建了一个pac ...

  8. nginx log 错误502 upstream sent too big header while reading response header from upstream

    cookies的值超出了范围我是说 看看了一下日志 错误502 upstream sent too big header while reading response header from upst ...

  9. Java第三阶段学习(十一、Servlet基础、servlet中的方法、servlet的配置、ServletContext对象)

    一.Servlet简介  1.什么是servlet: sun公司提供的一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是java代码,通过java的API动态的向 ...

  10. 023 Hadoop的生态系统

    1.数据来源 RDBM:sqoop 日志文件:flume 2.zookeeper 多台机器保持同步数据. 3.hive sql语句的查询 HQL转换成mapreduce SQL On Hadoop 4 ...