如何使用 C# 中的 Lazy

共 3594字,需浏览 8分钟

 ·

2020-12-19 13:20


延迟初始化 是一种将对象的创建延迟到第一次需要用时的技术,换句话说,对象的初始化是发生在真正需要的时候才执行,值得注意的是,术语 延迟初始化 和 延迟实例化 的意思是相同的——可以互换使用,通过使用 延迟初始化 技术,可以避免应用程序不必要的计算和内存消耗,这篇文章我们将会讨论如何在 C# 中使用 延迟初始化。

有些朋友听完这些可能会懵逼,接下来用一个简单的例子来了解下 延迟加载 的场景,考虑下面两个类, Customer 和 Order, Customer 类包含了一个 Orders 属性,一个人肯定会有很多的订单,也就意味着它可能包含了很多的数据,甚至还需要连接数据库去获取 Orders 记录,在这种场景下,没必要给 customer 集合中的所有人都带上完整的 orders,这个初始化开销是巨大的,优化点就是不加载 Orders,直到某些 customer 真的需要 Orders 时才按需灌入。

使用 Lazy

你可以自己写一段逻辑来实现 延迟初始化,在 .Net Framework 4.0 之后就没必要了, 因为在 System 命名空间下已经提供了 Lazy,而且还是 线程安全 的,可以使用这个类来延迟 资源密集型 的对象按需创建。

当使用 Lazy 的时候,这里的 T 就是你要延迟的集合,那如何做到按需加载呢?调用 Lazy.Value 即可,下面的代码片段展示了如何使用 Lazy


Lazy> orders = new Lazy>();
IEnumerable result = lazyOrders.Value;

现在,考虑下面的两个类: Author 和 Blog,一个作者可以写很多文章,所以这两个类之间是 一对多 的关系,下面的代码片段展示了这种关系。


    public class Author
    {
        public int Id { getset; }
        public string FirstName { getset; }
        public string LastName { getset; }
        public string Address { getset; }
        public List Blogs { getset; }
    }
    public class Blog
    {
        public int Id { getset; }
        public string Title { getset; }
        public DateTime PublicationDate { getset; }
    }

值得注意的是,关系型数据库中的 一对多 关系映射到对象模型就是 Author 类中增加一个 List Blogs 属性,使用这个属性,Author 就可以维持一个或者多个 Blog 实例对象,对吧。

现在假定在 用户界面 上仅需展示 Author 的基础信息,比如说:(firstname,lastname,address),在这种场景下,给 Author 对象加载 Blogs 集合是毫无意义的,当真的需要加载 Blogs 时,执行 Blogs.Value 即可立即执行,下面展示了 Lazy Blogs 的用法。


    public class Author
    {
        public int Id { getset; }
        public string FirstName { getset; }
        public string LastName { getset; }
        public string Address { getset; }
        public Lazy> Blogs => new Lazy>(() => GetBlogDetailsForAuthor(this.Id));
        private IList 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 来包装 StateManager,你会发现使用 Lazy 来做延迟初始化真的是太简单了。。。


    public class StateManager
    {
        private static readonly Lazy obj = new Lazy(() => 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


往期精彩回顾




【推荐】.NET Core开发实战视频课程 ★★★

.NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

【.NET Core微服务实战-统一身份认证】开篇及目录索引

Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南)

.NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

10个小技巧助您写出高性能的ASP.NET Core代码

用abp vNext快速开发Quartz.NET定时任务管理界面

在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度

现身说法:实际业务出发分析百亿数据量下的多表查询优化

关于C#异步编程你应该了解的几点建议

C#异步编程看这篇就够了


浏览 12
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报