简介
阅读 Abp 源码的过程中,自己也学习到了一些之前没有接触过的知识。在这里,我在这儿针对研究学习 Abp 框架中,遇到的一些值得分享的知识写几篇文章。如果有什么疑问或者问题,欢迎大家评论指正。
在本篇主要是 Scoped 范围与 using 语句块的使用。using 语句块大家一定都不陌生,都是与非托管对象一起存在的,它有一个特性就是在 using 语句块结束的时候会调用对象的 IDispose.Dispose() 方法。一般我们会在非托管类型的 Dispose() 方法内部进行资源的释放,类似于 C 语言的 free() 操作。
例如下面的代码:
public void TestMethod()
{
using(var waitDisposeObj = new TestClass())
{
// 执行其他操作 xxx
}
// 出了语句块之后就,自动调用 waitDisposeObj 的 Dispose() 方法。
}
可以看到上面的例子,using 语句块包裹的就是一个范围 (Scoped)。其实这里可以延伸到依赖注入的概念,在依赖注入的生命周期当中有一个 Scoped 的生命周期。(PS: 需要了解的可以去阅读我的 这篇文章)
一个 Scoped 其实就可以看作是一个 using 语句块包裹的范围,所有解析出来的对象在离开 using 语句块的时候都应该被释放。
例如下面的代码:
public void TestMethod()
{
using(var scopedResolver = new ScopedResolver())
{
var a = scopedResolver.Resolve
();
var b = scopedResolver.Reslove();
}
// 出了语句块之后 a b 对象自动释放
}
其实这里也是利用了 using 语句块的特性,在 ScopedResolver 类型的定义当中,也实现了 IDisopse 接口。所以在 using 语句块结束的时候,会自动调用 ScopedResovler 的 Dispose() 方法,在这个方法内部则对已经解析出来的对象调用其 Dispose() 进行释放。
二、分析
2.0 释放委托
也是不知道叫什么标题了,这玩意儿是 Abp 封装的一个类型,它的作用就是在 using 语句块结束的时候,执行你传入的委托。
使用方法如下:
var completedTask = new DisposeAction(()=>Console.WriteLine("using 语句块结束了。"));
using(completedTask)
{
// 其他操作
}
// 执行完成之后会调用 completedTask 传入的委托。
根据上述用法,你也应该猜出来这个 DisposeAction 类型的定义了。该类型继承了 IDispose 接口,并且在内部有一个 Action 字段,用于存储构造函数传入的委托。在执行 Dispose() 方法的时候,执行传入的委托。
public class DisposeAction : IDisposable
{
public static readonly DisposeAction Empty = new DisposeAction(null);
private Action _action;
public DisposeAction([CanBeNull] Action action)
{
_action = action;
}
public void Dispose()
{
// 防止在多线程环境下,多次调用 action
var action = Interlocked.Exchange(ref _action, null);
action?.Invoke();
}
}
2.1 统一对象释放
统一对象释放是 Abp 当中的另一种用法,其实按照 Abp 框架的定义,叫做 ScopedResolver(范围解析器)。顾名思义,通过 ScopedResolver 解析出来的对象,都会在 using 语句块结束之后统一进行销毁。
IScopedIocResolver 接口继承自 IIocResolver 和 IDisposable 接口,它的本质就是作为 Ioc 解析器的一种特殊实现,所以它拥有所有 Ioc 解析器的方法,这里就不再赘述。
它的实现也比较简单,在其内部有一个集合维护每一次通过 IIocResolver 解析出来的对象。在 Dispose() 方法执行的时候,遍历这个集合,调用 Ioc 解析器的 Release() 方法释放对象并从集合中删除对象。下面就是实现的简化版:
public class ScopedIocResolver : IScopedIocResolver
{
private readonly IIocResolver _iocResolver;
private readonly List