深入Lazy<T>——.NET Framework 4.0

.NET Framework 4 在一次次跳票中终于发布了,在一次偶然的机会,我看到了 Anytao 的 [你必须知道的.NET]第三十三回,深入.NET 4.0之,Lazy<T>点滴 。

我没有看过在.NET Framework 4.0 beta2 的 关于 Lazy<T> 的实现,也不知道正式版与之前的版本是否有过改进(改变),我只在这里来单纯地谈在.NET Framework 4 中 Lazy<T> 的实现。

1. Lazy<T> 概述

我们也许会遇到这样一种情况,我们有一个大家伙(大对象)需要创建,那么这个对象的创建时需要较长的时间,同时也需要在托管堆上分配较多的空间。

那么在.NET Framework 4 中提供了这样一个很聪明的方式:Lazy<T>(我们可以称之为懒对象)。当然,在之前,很多人也曾对其进行过自己的实现。

那么我们在这里就可以把 Lazy<T> 的作用总结为一句话,按需延迟加载

2. Lazy<T> 的使用

了解了Lazy<T>的作用,让我们就来看下Lazy<T>如何应用。

class Program
{
static void Main(string[] args)
{
Lazy<Large> lazyObject = new Lazy<Large>();
Console.WriteLine(lazyObject.IsValueCreated);
lazyObject.Value.Test();
Console.WriteLine(lazyObject.IsValueCreated);
}
}

[Serializable]
class Large
{
public Large() { }
public void Test()
{
Console.WriteLine("Test");
}
}

运行结果如下:

image

这个例子很简单,也是Lazy<T>最基本,也是最常用的应用方式。

3. 实现自己的Lazy<T>

在.NET Framework 4.0之前,大对象就是存在的,那么对于一个大型系统而言,怎么样对付一个大对象呢。在我看来有两点:延迟加载和即时清理。前者解决创建问题,后者解决回收问题。

那么在来看Lazy<T>的.NET Framework实现之前,我们先来自己实现一个简单的Lazy<T>吧。

class MyLazy<T> where T : new()
{
private T value;
private bool isLoaded;
public MyLazy()
{
isLoaded = false;
}
public T Value
{
get
{
if (!isLoaded)
{
value = new T();
isLoaded = true;
}
return value;
}
}
}

这应该是最简单版本的Lazy<T>了,没有线程安全检测,其实什么都没有,只有着访问时创建真实对象,可是对于我们一般的应用来说也许就已经足够了。

4. Lazy<T>的.NET Framework实现

原本还想解释下代码的,可是太多了,解释不动了…….就写些主要把。

其实.NET Framework和上面的实现大同小异,有两点主要的不同:

A. 引入了Boxed内部类:

[Serializable]
private class Boxed
{
// Fields
internal T m_value;

// Methods
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
internal Boxed(T value)
{
this.m_value = value;
}
}

该内部类取代了我在上面实现中的泛型约束,使之更通用。

但是我们也应该注意到,如果T为结构体,那么由于T很大,所以装箱拆箱反而也许是个更耗费效率的事情,因此,个人建议,对值类型慎用Lazy<T>。

B. 线程安全的控制

在线程安全的控制选项中,.NET Framework为我们提供了这样的枚举选项:

public enum LazyThreadSafetyMode
{
None,
PublicationOnly,
ExecutionAndPublication
}

不做多余解释,关于这三者的具体意思,MSDN中已经说的很清楚了,可参加 这里 。

里面的代码比较麻烦,就不多说了。

5. 完善的大对象解决方案

在 Anytao 文章的回复中,我就提到了一点是:

个人倒觉得Lazy+WeakReference才是实现一个大对象的完整解决之道,一个按需加载,一个不定清理..... 
加到一起才完美。

但是 老赵 说:

又不是所有的大对象都需要自动清理……

那么我就不再重复去总结了,这两句话加到一起,我想应该可以得出一个比较完善的大对象处理方案吧。

如果这样,我们是否能对应地去创建一个单独的实现类:WeakLazy<T>呢。

这样相当于我们有了WeakReference,有了Lazy<T>,还有了WeakLazy<T>,那么我们是不是就可以很完整地根据情况选择应用了呢!

6. 总结

原本想写一些稍微深入点的东西,可是写到最后,发现仍为皮毛而,叹乎…….

### 回答1: Lazy<T> 是一种 .NET 类型,它可以延迟实例化某个类型直到需要使用它时才创建。这对于那些初始化代价较大的类型非常有用,因为它们可以避免浪费资源来实例化未使用的对象。 使用 Lazy<T> 的一种常见方式是在懒加载单例模式中使用。例如,假设有一个 MyClass 类型需要很长时间才能实例化,但是我们希望在第一次访问单例时才初始化它。为了做到这一点,我们可以使用 Lazy<T> 来定义单例: ``` private static readonly Lazy<MyClass> instance = new Lazy<MyClass>(() => new MyClass()); public static MyClass Instance => instance.Value; ``` 这样,当我们首次调用 `MyClass.Instance` 时,Lazy<T> 会调用提供的工厂方法来创建 `MyClass` 的实例,并在后续调用中返回相同的实例。 ### 回答2: Lazy<T>是一种泛型类,用于延迟加载对象。Lazy<T>延迟加载的意思是,只有在第一次访问该对象时才会进行实例化和初始化,之后的访问都直接返回已经创建好的对象。 通常情况下,对象在创建之后会一直存活在内存中,即使在实际使用之前。而使用Lazy<T>可以在需要的时候再进行对象的创建,从而减少了不必要的资源占用和对象的初始化时间。 Lazy<T>可用于创建那些消耗较大的对象,例如数据库连接、网络请求等。通过使用Lazy<T>,我们可以推迟对这些对象的创建和初始化,减少了启动时间和内存的消耗。 在使用Lazy<T>时,我们需要传入一个委托方法(Func<T>),用于在第一次访问该对象时进行实例化。Lazy<T>保证了委托方法的线程安全,并且只执行一次。 Lazy<T>还提供了一些其他的属性和方法,例如Value属性用于获取延迟加载的对象实例,IsValueCreated属性用于判断延迟加载的对象是否已经创建,以及ForceCreate方法用于强制创建延迟加载的对象。 总而言之,Lazy<T>是一种用于实现延迟加载的泛型类,可以在需要的时候再进行对象的创建和初始化,从而提高性能和资源的利用率。 ### 回答3: Lazy<T>是一种类型,它是一个泛型类,用于延迟计算。Lazy<T>表示一个值,该值只有在需要时才会被计算,并且在之后的访问中会缓存计算结果。 Lazy<T>类可以用于解决在某些情况下计算结果代价很高的问题。它的工作原理是,当我们创建Lazy<T>实例时,它并不立即计算结果,而是只在第一次访问Value属性时才计算并返回结果。在之后的所有访问中,Lazy<T>会直接返回缓存的结果,而不再进行计算。 这种延迟计算的方式有助于提高性能,因为在很多情况下,并不是每次访问该值时都需要重新计算。Lazy<T>还提供了线程安全的实现,以便在多线程环境中可以安全地使用。 使用Lazy<T>时,我们可以通过传递一个委托给Lazy<T>的构造函数来延迟计算。这个委托将在第一次访问Value属性时被调用,并且返回的结果会被缓存起来。之后的访问中,Lazy<T>会直接返回这个缓存的结果,而不再调用委托。 总而言之,Lazy<T>是一种用于延迟计算并缓存结果的类型,可以有效提高性能并减少计算代价高的情况下的性能损耗。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值