Welcome

首页 / 软件开发 / .NET编程技术 / 领先技术 - 别着急,人懒没问题

领先技术 - 别着急,人懒没问题2010-12-24 MSDN Dino Esposito在软件中,术语延迟指的是尽可能久地推迟特定的高开销活动的空闲时 间。软件延迟过程中其实也在进行操作,但意味着任何操作仅当需要完成某一 特定任务时才会发生。就这一点而言,延迟是软件开发中的一种重要模式,可 以成功地应用于包括设计与实施在内的各种情景中。

例如,极限编程方法中的一种基本编码实践就被简单地概括为“您不会需要 它”,那就是一种明确的延迟要求 - 当且仅当您需要这些功能时,才需要在基 本代码中包含它。

从另一个角度来看,在实施类的过程中,当要从难以访问的源中加载数据时 ,您也可能需要延迟。事实上,延迟加载模式解释了这种普遍接受的解决方案 ,即定义一个类成员,但使其保持为空,直到其他某些客户端代码实际需要其内 容时为止。延迟加载完全适合在对象关系映射 (ORM) 工具(如实体框架和 NHibernate)环境中使用。ORM 工具用于映射面向对象的环境与关系数据库之 间的数据结构。例如,在这种环境中,延迟加载指的就是仅当某些代码尝试读 取 Customer 类上公开的 Orders 集合属性时,
框架才能加载 Customer 的 Orders。

但是,延迟加载并不限于特定的实施方案(如 ORM 编程)。而且,延迟加 载指的就是在某些数据实际可用之前不获取该数据的实例。换言之,延迟加载 就是要有特殊工厂逻辑,即跟踪必须要创建的内容,最后在实际请求该内容时以 静默方式创建该内容。

在 Microsoft .NET Framework 中,开发人员早就在我们的类中手动实施了 所有延迟行为。在 .NET Framework 4 问世之前,从未有过内置的机制来帮助 完成此任务。在 .NET Framework 4 中,我们可以开始
使用全新的 Lazy<T> 类。

了解 Lazy<T> 类

Lazy<T> 是一个特殊的工厂,您可以用来包装给定 T 类型的对象。Lazy<T> 包装代表一个尚不存在的类实例的实时代理。使用 Lazy 包装 的理由有很多,其中最重要的莫过于可以提高性能。延迟初始化对象可以避免 所有不必要的计算,从而减少内存消耗。如果加以合理利用,延迟初始化对象 也可以成为一种加快应用程序启动的强大工具。以下代码说明了以延迟方式初 始化对象的方法:

var container = new Lazy<DataContainer>();

在本例中,DataContainer 类表示的是一个引用了其他对象数组的纯数据容 器对象。在刚刚对 Lazy<T> 实例调用完 new 运算符之后,返回的只是 一个实时的 Lazy<T> 类实例;无论如何都不会得到指定类型 T 的实例。如果您需要向其他类的成员传递一个 DataContainer 实例,则必须更改这些成 员的签名才能使用 Lazy<DataContainer>,如下所示:

void ProcessData(Lazy<DataContainer> container);

何时创建 DataContainer 的实际实例,以便程序可以处理其所需的数据? 让我们来看看 Lazy<T> 类的公共编程接口。该公共接口非常小,因为它 只包含两个属性:Value 和 IsValueCreated。如果存在与 Lazy 类型关联的实 例,则属性 Value 就会返回该实例的当前值。该属性的定义如下:

public T Value
{
get { ... }
}

属性 IsValueCreated 可以返回一个 Boolean 值,表示 Lazy 类型是否已经 过实例化。以下是该属性的源代码中的一段摘录:

public bool IsValueCreated
{
get
{
return ((m_boxed != null) && (m_boxed is Boxed<T>));
}
}

如果 Lazy<T> 类包含 T 类型的实际实例(如果有),则 m_boxed 成 员就是该类的一个内部私有的不稳定成员。因此,IsValueCreated 只需检查是 否存在 T 的实时实例,然后返回一个 Boolean 答案。如前文所述,m_boxed 成员是私有的并且不稳定(如以下代码段所示):

private volatile object m_boxed;