Lazy<T>解决什么问题?

1、大对象加载

  考虑下面的需求,有个对象很大,创建耗时,并且要在托管堆上分配一大块空间。我们当然希望,用到它的时候再去创建。也就是延迟加载,等到真正需要它的时候,才去加载。

  显然,这里需要加一个中间层,将大对象封装起来,暴露接口,开始并不创建大对象,等到用户真正访问对象的时候,再去创建。另外,这个中间层应该可以封装不同类型的大对象,因此需要类模版。Lazy<T>就是为了解决这个问题。

  典型的使用

public Lazy<AccountService> AccountServ = new Lazy<AccountService>();
public Lazy<ProductService> ProductService = new Lazy<ProductService>();

2、将委托或者方法对象保存,并在需要的时候调用。

private readonly Lazy<IDbConnection> _connectionLazy;
public CallHistoryRepository(ConnectionFactory connectionFactory)
{
    _connectionLazy = new Lazy<IDbConnection>(()=>connectionFactory.Connection);
}

一旦使用.Vale,那么对应的变量就会被实例化,IsValueCreated属性也就变成了true。

实现自己的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>了,没有线程安全检测,只有着访问时创建真实对象,可是对于我们一般的应用来说也许就已经足够了。

.NET Lazy<T> 实现

.NET Core和我们的实现,有两点主要的不同:

1、 引入了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>

2、 线程安全的控制

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

public enum LazyThreadSafetyMode
{
    None,
    PublicationOnly,
    ExecutionAndPublication
}

默认值为ExecutionAndPublication

枚举选项MSDN介绍如下

http://msdn.microsoft.com/en-us/library/system.threading.lazythreadsafetymode%28VS.100%29.aspx

isThreadSafe则应用于多线程环境下,如果isThreadSafe为false,那么延迟加载对象则一次只能创建于一个线程。

Lazy<T>源码

System.Runtime命名空间下

由于core中的lazy源码我只找到了下图这个,再往下lazy的实现并没找

Core源码(三) Lazy<T>

所以我使用.Net 4.5的lazy源码

 Core源码(三) Lazy<T>

一、最常使用的属性Value

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public T Value
{
    get
    {
        Boxed boxed = null;
        if (m_boxed != null )
        {
            // Do a quick check up front for the fast path.
            boxed = m_boxed as Boxed;
            if (boxed != null)
            {
                return boxed.m_value;
            }
            LazyInternalExceptionHolder exc = m_boxed as LazyInternalExceptionHolder;
            Contract.Assert(m_boxed != null);
            exc.m_edi.Throw();
        }
        return LazyInitValue();
    }
}
//null --> value is not created
//m_value is Boxed --> the value is created, and m_value holds the value
//m_value is LazyExceptionHolder --> it holds an exception
private object m_boxed;
View Code

相关文章:

  • 2021-06-09
  • 2021-06-08
  • 2021-08-06
  • 2021-09-20
  • 2021-12-04
  • 2021-09-15
  • 2021-08-27
猜你喜欢
  • 2021-10-12
  • 2021-06-14
  • 2022-01-06
  • 2022-12-23
  • 2021-11-25
  • 2021-08-11
相关资源
相似解决方案