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

转载于:https://www.cnblogs.com/TianFang/p/9096001.html

RX库中的IDisposable对象相关推荐

  1. python requests库 response_Pytest 如何模拟 requests库中的Response对象?

    请问如何在 Pytest 框架中模拟requests库中的Response对象? 涉及到的主体代码如下: def get_address(phone): url = 'http://www.ip138 ...

  2. ACE库中ACE_Msg_Log日志对象浅论

    引言 ACE库提供了ACE_Msg_Log类实现较为全面的日志功能.对于该类的基本使用已经有不少文章谈论过.本文对其中几点需要注意的地方进行说明,帮助大家更好地使用该类. 1. 线程安全性       ...

  3. Express 工具库中的 Application 对象

    var express = require('express') var app = express()app.get('/', function (req, res) {res.send('hell ...

  4. C++11 中STL库中新增内容

    C++ 11一个比较显著的变化是以前boost库中的一些函数被正式标准化合入到STL中了,本文就简单的介绍一下. 引用包装器(Reference Wrapper) 当模板函数参数为泛型类型的时候,无法 ...

  5. C++语言标准库functional中的函数对象,绝对是装B神器~

    C++语言标准库<functional>中的函数对象,绝对是装B神器~用一下,感慨万千~~~ 基本上是C++ Primer上的,show一下代码: #include <iostrea ...

  6. AutoRunner如何在对象库中添加新的对象而不改变脚本

    在录制一些对象时,有的对象属性比较固定,在录制脚本的时候我们只是录制到了有限个对象.在对脚本进行加强过后执行脚本就会报"找不到对象"这种错误. 出现这种错误的时候我们就需要对对象库 ...

  7. Python爬虫高级库之一的lxml库中,ET.parse()是一个非常重要的方法。它可以将任意XML或HTML格式的文档解析成一个ElementTree对象,...

    Python爬虫高级库之一的lxml库中,ET.parse()是一个非常重要的方法.它可以将任意XML或HTML格式的文档解析成一个ElementTree对象,方便我们对结构化的数据进行处理和分析.在 ...

  8. php 不喜欢用对象,为什么PHP不在其默认库中使用对象?

    我已经用 PHP编写了半年多的时间,虽然我还远没有成为一名专家,但我可以很容易地解决问题,并根据我的需要编写脚本.我来自面向对象的背景,这似乎是PHP在其默认库中使用的很少(如果有的话). 我使用或创 ...

  9. CImg库中CImg,CImgList,CImgDisplay三个类的介绍

    转自:http://www.cppprog.com/2009/0426/108.html 本文简单介绍了CImg库中的三个大类:CImg,CImgList,CImgDisplay.然后给出了让CImg ...

最新文章

  1. linux添加域名证书,在Linux服务器上手动安装免费的Let's Encrypt域名证书 - 乐道主机...
  2. C++虚继承下的内存模型(一)
  3. Fiddler抓包使用教程-基本功能介绍
  4. android popupwindow 调用方法,Android PopUpWindow使用详解
  5. MySQL 引擎特性 · InnoDB Buffer Pool
  6. Python正则表达式初识(九)
  7. win7计算机双击空白,win7系统控制面板“打开或关闭Windows 功能”空白没有任何选项的解决方法...
  8. 流程控制: jQ Deferred 与 ES6 Promise 使用新手向入坑!
  9. centos7 安装vsftpd和配置以及虚拟用户权限分配
  10. Ashmem、MemoryFile、Binder的共享内存(jni可用)
  11. linux上设置jar包加载顺序,SpringBoot配置加载顺序
  12. 超强扒站神器:SiteSucker Pro for Mac(4.1.3多语言)
  13. 应用随机过程笔记(二):泊松过程
  14. 城市智能交通项目实施方案
  15. [转]库存那些事儿_4_收货
  16. 下载阿里云OSS上的文件及文件夹
  17. 洛克菲勒:世界上只有两种人头脑聪明...
  18. matlab 端点检测 能零比法_端点检测方法
  19. 模拟网上手机抽奖界面(供大家BS......)
  20. 好人品的八个标准,你有几个?

热门文章

  1. 优化element ui中的弹框样式
  2. 【java笔记】序列化和反序列化
  3. 【PYTHON笔记】:文件打开和关闭
  4. LeetCode 48 旋转图像
  5. FFMPEG 实现 YUV,RGB各种图像原始数据之间的转换(swscale)
  6. abaqus dat文件 matlab_基于MPCCI的FLUENT与ABAQUS流固耦合分析步骤
  7. java jquery easyui_java中用jquery-easyui插件做可编辑datagird列表
  8. php获取图片所有颜色代码,php 获取一张图片所有点的颜色值
  9. IDEA启动项目报错:非法字符: ‘\ufeff‘
  10. android span的用法,android – 如何使用TextAppearanceSpan