C#中的Lazy如何使用详解
作者:码农读书 发布时间:2023-10-25 12:56:34
前言
延迟初始化 是一种将对象的创建延迟到第一次需要用时的技术,换句话说,对象的初始化是发生在真正需要的时候才执行,值得注意的是,术语 延迟初始化 和 延迟实例化 的意思是相同的——可以互换使用,通过使用 延迟初始化 技术,可以避免应用程序不必要的计算和内存消耗,这篇文章我们将会讨论如何在 C# 中使用 延迟初始化。
有些朋友听完这些可能会懵逼,接下来用一个简单的例子来了解下 延迟加载 的场景,考虑下面两个类, Customer 和 Order , Customer 类包含了一个 Orders 属性,一个人肯定会有很多的订单,也就意味着它可能包含了很多的数据,甚至还需要连接数据库去获取 Orders 记录,在这种场景下,没必要给 customer 集合中的所有人都带上完整的 orders,这个初始化开销是巨大的,优化点就是不加载 Orders,直到某些 customer 真的需要 Orders 时才按需灌入。
使用 Lazy<T>
你可以自己写一段逻辑来实现 延迟初始化 ,在 .Net Framework 4.0 之后就没必要了, 因为在 System 命名空间下已经提供了 Lazy<T> ,而且还是 线程安全 的,可以使用这个类来延迟 资源密集型 的对象按需创建。
当使用 Lazy<T> 的时候,这里的 T 就是你要延迟的集合,那如何做到按需加载呢?调用 Lazy<T>.Value 即可,下面的代码片段展示了如何使用 Lazy<T> 。
Lazy<IEnumerable<Order>> orders = new Lazy<IEnumerable<Order>>();
IEnumerable<Order> result = lazyOrders.Value;
现在,考虑下面的两个类: Author 和 Blog ,一个作者可以写很多文章,所以这两个类之间是 一对多 的关系,下面的代码片段展示了这种关系。
public class Author
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public List<Blog> Blogs { get; set; }
}
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime PublicationDate { get; set; }
}
值得注意的是,关系型数据库中的 一对多 关系映射到对象模型就是 Author 类中增加一个 List Blogs 属性,使用这个属性,Author 就可以维持一个或者多个 Blog 实例对象,对吧。
现在假定在 用户界面 上仅需展示 Author 的基础信息,比如说:(firstname,lastname,address),在这种场景下,给 Author 对象加载 Blogs 集合是毫无意义的,当真的需要加载 Blogs 时,执行 Blogs.Value 即可立即执行,下面展示了 Lazy<Blog> Blogs 的用法。
public class Author
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public Lazy<IList<Blog>> Blogs => new Lazy<IList<Blog>>(() => GetBlogDetailsForAuthor(this.Id));
private IList<Blog> GetBlogDetailsForAuthor(int Id)
{
//Write code here to retrieve all blog details for an author.
}
}
使用通用的 Lazy
接下来让我们看看如何使用泛型的 Lazy 实现单例模式,下面的 StateManager 是线程安全的,同时为了演示 延迟初始化 ,我使用了 静态构造函数 来确保 C# 编译器不会将它标记为 beforefieldinit 。
public sealed class StateManager
{
private StateManager()
{
}
public static StateManager Instance
{
get
{
return Nested.obj;
}
}
private class Nested
{
static Nested()
{
}
internal static readonly StateManager obj = new StateManager();
}
}
下面我用 Lazy<T> 来包装 StateManager,你会发现使用 Lazy<T> 来做延迟初始化真的是太简单了。。。
public class StateManager
{
private static readonly Lazy<StateManager> obj = new Lazy<StateManager>(() => new StateManager());
private StateManager() { }
public static StateManager Instance
{
get
{
return obj.Value;
}
}
}
可以瞄一下上面代码的 Instance 属性,它被做成只读属性了,同时也要注意 obj.Value 也是一个只读属性。
public class Lazy<T>
{
public T Value
{
get
{
if (_state != null)
{
return CreateValue();
}
return _value;
}
}
}
延迟初始化 是一个很不错的性能优化技术,它允许你将那些 资源密集型 的对象延迟到你真正需要加载的时候再加载,大家结合自己的场景尽情的使用吧!
总结
译文链接:https://www.infoworld.com/article/3227207/how-to-perform-lazy-initialization-in-c.html
来源:https://mp.weixin.qq.com/s/JqHtcUbbcronoKnkmQaC4g


猜你喜欢
- 无障碍服务可以模拟一些用户操作,无障碍可以处理的对象,通过类 AccessibilityNodeInfo 表示,通过无障碍服务,可以通过它的
- 一、简介 1、地图 地图展示:普通地图(2D,3D)、卫星图和实时交通图。 地图操作:可通过接口或手势控制来实
- java 闰年判断前言:给定一个年份,判断这一年是不是闰年。当以下情况之一满足时,这一年是闰年:1. 年份是4的倍数而不是100的倍数;2.
- 在主Activity中:listview=(ListView)findViewById(R.id.listview);getData();/
- 本文实例讲述了java生成jar包的方法,是非常实用的技巧。分享给大家供大家参考。具体分析如下:很多Java初学者都会有这样的疑问:Java
- 一、问题反馈今天公司测试向我反馈,系统用户模糊查询功能在用户名称包含特殊字符时(_、\、%)无法正常查询结果。二、问题验证1、当like中包
- 添加方法:选择项目->引用->右击“添加引用”->选择COM 找到上面组件—>点击“确定”。实现代码如下: 
- 程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,则表明此数不是素数,反之是素数。#include <s
- 01.点明观点 C#中,非托管资源使用之后必须释放,而using()是使用非托管资源的最佳方式,可以确保资源在代码块结束之后被正确
- Okhttp 处理了很多网络疑难杂症,比如从很多常用的连接问题中自动恢复。如果你服务器配置了多个IP地址,当一个IP地址连接失败后Okhtt
- 目录第一章 前言概述第01节 概述第02节 区别第二章 核心代码第01节 成员变量第02节 构造方法第三章 扩容操作第01节 扩容代码第一章
- 本文汇总了Spring的常用注解,以方便大家查询和使用,具体如下:使用注解之前要开启自动扫描功能其中base-package为需要扫描的包(
- 当一个应用在后台执行时,前台界面就不会有什么信息,这时用户根本不知道程序是否在执行、执行进度如何、应用程序是否遇到错误终止等,这时需要使用进
- 在传统的单服务架构中,一般来说,只有一个服务器,那么不存在 Session共享问题,但是在分布式/集群项目中,Session 共享则是一个必
- 上篇文章我们讲解了使用Hibernate Validation来校验数据,当校验完数据后,如果发生错误我们需要给客户返回一个错误信息,因此这
- 很多人都知道:浮点数值不适用于无法接受舍入误差的金融计算中,即:我们常说的丢失精度问题。这是为什么呢?很多人还知道这样一句话:这种舍入误差的
- 今天给大家带来的是仅仅使用一个TextView实现一个 * 京东、淘宝、唯品会等各种电商APP的活动倒计时。最近公司一直加班也没来得及时间去整
- Java 中的线程有以下状态:新建状态(New):新创建的线程,还未执行。就绪状态(Runnable):执行了 start() 方法,等待运
- 通过自定义注解的方式(如:@SysLog(obj = "操作对象", text = "操作内容"),
- 近期工作内容需要涉及到相机开发,其中一个功能点就是实现一个相机预览页底部的滑动指示器,现在整理出来供大家讨论参考。先上一张图看下效果:主要实