Lazy<T>的应用之类内部字段与C#延迟加载

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lazy<T>的应用之类内部字段与C#延迟加载相关的知识,希望对你有一定的参考价值。

 延迟加载主要应用在以下场景:

数据层 – ADO.NET或Entity Framework等ORM
反射 – 加载assemblies, types, MEF 
缓存对象,领域实体

    下面以领域实体为例, 在实体中我们经常检查某个属性下字段是否为空引用. 如果是空的话,计算或填充这个字段. 像这样:

   1:      /// <summary>
   2:      /// Order
   3:      /// </summary>
   4:      public class Order
   5:      { 
   6:          private Customer _customer;
   7:          /// <summary>
   8:          /// Gets the customer.
   9:          /// </summary>
  10:          public Customer Customer
  11:          {
  12:              get
  13:              {
  14:                  if (_customer == null)
  15:                  {
  16:                      _customer = new Customer();
  17:                  } return _customer;
  18:              }
  19:          }
  20:          /// <summary>
  21:          /// Prints the label.
  22:          /// </summary>
  23:          /// <returns></returns>
  24:          public string PrintLabel()
  25:          {
  26:              return Customer.CompanyName + "\n" + Customer.Address;
  27:          }
  28:      }

如果PrintLabel方法写成这样:

   1:          public string PrintLabel()
   2:          {
   3:              string result = _customer.CompanyName; // probably results in a NullReferenceException    
   4:              return result + "\n" + Customer.Address; // ok to access Customer  
   5:          }

注意上面第4行代码,可能有空引用异常. 下面我们使用Lazy<T>来解决这个问题:

   1:      /// <summary>
   2:      /// Order
   3:      /// </summary>
   4:      public class Order
   5:      {
   6:          /// <summary>
   7:          /// _customerInitializer
   8:          /// </summary>
   9:          private Lazy<Customer> _customerInitializer;
  10:   
  11:          /// <summary>
  12:          /// Initializes a new instance of the <see cref="Order"/> class.
  13:          /// </summary>
  14:          public Order()
  15:          {
  16:              _customerInitializer = new Lazy<Customer>(() => new Customer(),isThreadSafe:true);
  17:          }
  18:   
  19:          /// <summary>
  20:          /// Gets the customer.
  21:          /// </summary>
  22:          public Customer Customer
  23:          {
  24:              get{ return _customerInitializer.Value;}
  25:          }
  26:   
  27:          /// <summary>
  28:          /// Prints the label.
  29:          /// </summary>
  30:          /// <returns></returns>
  31:          public string PrintLabel()
  32:          {
  33:              string result = Customer.CompanyName; // ok to access Customer       
  34:              return result + "\n" + _customerInitializer.Value.Address; // ok to access via .Value  
  35:          }
  36:      }

上面的代码16行,我们延迟初始化对像实例,并且设置线程安全.  Lazy<T>内部是使用Func<T>来实现的,看下面其中构造器的源代码:

   1:  public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode)
   2:  {
   3:      if (valueFactory == null) throw new ArgumentNullException("valueFactory");
   4:      this.m_threadSafeObj = Lazy<T>.GetObjectFromMode(mode);
   5:      this.m_valueFactory = valueFactory;
   6:  }

有兴趣请自行查看.net framework中的源码. 我们还可以扩展一个LazyNotNull<T>

   1:      /// <summary>
   2:      /// LazyNotNull
   3:      /// </summary>
   4:      /// <typeparam name="T">Type</typeparam>
   5:      public class LazyNotNull<T>
   6:      {
   7:          private Lazy<T> _lazyValue = null;
   8:          private Func<T> _valueFactory = null;
   9:   
  10:          /// <summary>
  11:          /// Initializes a new instance of the <see cref="LazyNotNull&lt;T&gt;"/> class.
  12:          /// </summary>
  13:          /// <param name="valueFactory">The value factory.</param>
  14:          public LazyNotNull(Func<T> valueFactory)
  15:          {
  16:              _lazyValue = new Lazy<T>(valueFactory);
  17:              _valueFactory = valueFactory;
  18:          }
  19:   
  20:          /// <summary>
  21:          /// Gets T value.
  22:          /// </summary>
  23:          public T Value
  24:          {
  25:              get
  26:              {
  27:                  var lazyValue = _lazyValue;
  28:                  if (lazyValue.Value != null)
  29:                  {
  30:                      return lazyValue.Value;
  31:                  }
  32:                  _lazyValue = new Lazy<T>(_valueFactory);
  33:                  return default(T);
  34:              }
  35:          }
  36:      }


希望这篇POST对您开发有帮助. 

以上是关于Lazy<T>的应用之类内部字段与C#延迟加载的主要内容,如果未能解决你的问题,请参考以下文章

System.Lazy<T> 如何访问 T 的私有构造函数?

.net 核心依赖注入是不是支持 Lazy<T>

什么时候应该使用 Lazy<T; ?

第23课 可变参数模板_Optional和Lazy类的实现

C# 延迟处理类 Lazy

c# linq update单个字段