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对您开发有帮助.

时间: 2024-10-13 00:54:43

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

javascript获取wx.config内部字段解决微信分享

转自:http://www.jb51.net/article/80679.htm 专题推荐:js微信开发_脚本之家 http://www.jb51.net/Special/879.htm 背景在微信分享开发的时候我们通常的流程是 <?php require_once "jssdk.php"; $jssdk = new JSSDK("yourAppID", "yourAppSecret"); $signPackage = $jssdk->

.NET泛型04,使用Lazy&lt;T&gt;实现延迟加载

对于一些"大对象"的创建,我们常常希望延迟加载,即在需要的时候再创建对象实例.现在Lazy<T>很好地支持了这一特点.主要包括: 没有Lazy<T>之前 Lazy<T>实例 延迟加载的本质 没有Lazy<T>之前 在没有Lazy<T>之前,我们通过如下方式实现延迟加载. public class LazySinleton { private LazySingleton() {}   public static LazySing

如何使用 awk 输出文本中的字段和列

首先我们要知道,awk 能够自动将输入的行,分隔为若干字段.每一个字段就是一组字符,它们和其他的字段由一个内部字段分隔符分隔开来. 如果你熟悉 Unix/Linux 或者懂得 bash shell 编程,那么你应该知道什么是内部字段分隔符(IFS)变量.awk 中默认的 IFS 是制表符和空格. awk 中的字段分隔符的工作原理如下:当读到一行输入时,将它按照指定的 IFS 分割为不同字段,第一组字符就是字段一,可以通过 $1 来访问,第二组字符就是字段二,可以通过 $2 来访问,第三组字符就是

C#属性与字段

一.字段: 字段是储存类要满足其设计所需要的数据,是与类相关的变量. 二.属性: 1.在C#中可以自由的.毫无限制的访问公有字段,但在一些场合中,我们需要只能给字段赋于某个范围的值.或是要求字段只能读或只能写,或是在改变字段时能改变对象的其他一些状态,这些单靠字段是无法做到的,于是就有了属性. 2.属性有两个方法:get和set. get访问器返回与声明的属性相同的数据类型,表示的意思是调用时可以得到内部字段的值或引用: set访问器没有显示设置参数,但它有一个隐式参数,用关键字value表示,

01-05-01-1【Nhibernate (版本3.3.1.4000) 出入江湖】延迟加载及其class和集合(set、bag等)的Lazy属性配置组合对Get和Load方法的影响

这篇文章 http://ayende.com/blog/3988/nhibernate-the-difference-between-get-load-and-querying-by-id One of the more common mistakes that I see people doing with NHibernate is related to how they are loading entities by the primary key. This is because the

[.net 面向对象编程基础] (9) 类的成员(字段、属性、方法)

[.net 面向对象编程基础] (9) 类的成员(字段.属性.方法) 前面定义的Person的类,里面的成员包括:字段.属性.方法.事件等,此外,前面说的嵌套类也是类的成员. a.类的成员为分:静态成员(static)和非静态成员 b.静态成员用static标识,不标识则默认为非静态成员 c.静态成员属于类所有,动态成员则属于实例所有,即对象 d.静态成员为类所有实例共享,无论类有多少实例或副本,静态成员只占用存中一块区域.非静态成员则在类的每个实例,都创建一个内存域. 下面主要说明一下类的主要

C#---属性和字段

C#中的变量 内存:用户存储正在运行的程序数据RAM(随机存储器)断电后里面的数据丢失 变量代表这一块内存空间,我们可以通过变量名称向内存存/取数据.有变量就不需要我们记忆复杂的内存地址了. 先向计算机申请一块内存空间,考虑往内存方的数据类型,向内存申请一块内存空间的语法: int number;//申请开辟一块内存空间 number=1000;//把1000放到number中 Console.WriteLine(number); Console.ReadKey(); 变量可以类中,方法中声明.

SharePoint 2013 中代码创建列表查阅项字段

1.首先,打开VS创建两个List Definition,分别是Address和City,如下图: 2.City列表里修改Title为City Name,其实内部名称还是Title,注意一下: 3.给City的列表实例,添加几个值,用来测试使用,如下: 4.在Address列表里添加几个字段,分别是CityName(LookUp类型)和HomeAddress(Single Line of Text),如下: 5.查看Address列表的Schema.Xml,尤其是Fields节点,也就是字段,如

1.16字段分隔符和迭代器

内部字段分隔符(Internal Field Separator,IFS)是shell脚本编程的一个重要概念.下面将讨论把单个数据流划分成不同数据元素的定界符(delimiter),内部字段分隔符是用于特定用途的定界符.IFS是存储定界符的环境变量.它是当前shell环境默认使用的默认定界字符串. 1.考虑一种情形,我们需要迭代一个字符串或逗号分隔型数值(Comma Separated Value,CSV)中的单词.如果是前一种,则使用IFS=".";如果是后一种,则使用IFS=&qu