.NET 中的延迟初始化:Lazy<T> 与LazyInitializer

发布于:2025-08-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

标签:线程安全、延迟初始化、按需初始化、提升启动性能

项目地址:NitasDemo/12Lazy/LazyDemo at main · Nita121388/NitasDemo

Lazy

官方文档:Lazy<T> 类 (System) | Microsoft Learn

源码:Lazy.cs

1. 概念

Lazy<T> 是 .NET 4.0 引入的泛型类,实现延迟初始化

它确保对象仅在首次访问时被创建,从而避免不必要的资源消耗并提升启动性能。

该类封装了延迟初始化的逻辑,并提供了线程安全的初始化机制。

  • 特性

    特性 说明
    延迟初始化 对象在第一次访问 `.Value` 时才被实例化,提升启动性能。
    节省资源 如果对象从未被使用,则不会创建,节省内存和 CPU。
    线程安全 默认支持多线程环境下的安全初始化(可设置线程安全模式)
    可复用 一旦初始化完成,后续访问 `.Value` 将直接返回已创建的对象,不会重复创建。
    支持复杂逻辑 可通过委托传入自定义初始化逻辑。
  • 优点

    减少启动时间,按需加载资源。

  • 缺点

    • 首次访问可能有延迟。
    • 线程安全模式存在锁竞争和异常放大,滥用会浪费性能
    • 过度使用会导致代码可读性下降。
  • 最佳实践

    仅对真正需要延迟初始化的对象使用 Lazy<T>

2. 基本用法

  • 用法1:默认构造函数(要求无参构造)

    // 简单创建(非线程安全)
    Lazy<ExpensiveObject> lazySimple = new Lazy<ExpensiveObject>();
    ExpensiveObject obj = lazySimple.Value; // 首次访问时初始化
    
  • 用法2:使用委托自定义初始化逻辑

    Lazy<MyClass> lazy = new Lazy<MyClass>(() => new MyClass("自定义构造"));
    

3. 异常处理

  • 初始化异常被缓存

    首次初始化失败后,异常会在每次调用时重新抛出。

  • 解决方案

    使用 Lazy<T> 的构造函数重载捕获异常并重试。

Lazy<ExpensiveObject> lazyWithRetry = new Lazy<ExpensiveObject>(() => 
{
    try { return new ExpensiveObject(); }
    catch { /* 重试逻辑 */ }
});

4. 线程安全模式

PublicationOnly

通过 LazyThreadSafetyMode 指定初始化行为:

  • 构造函数

    public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode);
    
    模式枚举值 含义说明 适用场景
    `ExecutionAndPublication` 线程安全,确保只有一个线程执行初始化逻辑。 多线程环境(默认)
    `PublicationOnly` 多线程下允许多个线程同时初始化,但只保留第一个完成的实例。 避免加锁阻塞、初始化成本高、重复初始化无影响,允许短暂浪费资源时
    `None` 非线程安全 单线程环境(高性能)
    • ExecutionAndPublication 模式部分源码

      
              private void ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor)
              {
                  lock (executionAndPublication)
                  {
                      // it's possible for multiple calls to have piled up behind the lock, so we need to check
                      // to see if the ExecutionAndPublication object is still the current implementation.
                      if (ReferenceEquals(_state, executionAndPublication))
                      {
                          if (useDefaultConstructor)
                          {
                              ViaConstructor();
                          }
                          else
                          {
                              ViaFactory(LazyThreadSafetyMode.ExecutionAndPublication);
                          }
                      }
                  }
              }
       
      
    • PublicationOnly模式部分源码

      private void PublicationOnly(LazyHelper publicationOnly, T possibleValue)
              {
                  LazyHelper? previous = Interlocked.CompareExchange(ref _state, LazyHelper.PublicationOnlyWaitForOtherThreadToPublish, publicationOnly);
                  if (previous == publicationOnly)
                  {
                      _factory = null;
                      _value = possibleValue;
                      _state = null; // volatile write, must occur after setting _value
                  }
              }
      
// 线程安全模式(默认:确保仅初始化一次)
Lazy<ExpensiveObject> safeLazy = new Lazy<ExpensiveObject>(
    () => new ExpensiveObject(),
    LazyThreadSafetyMode.ExecutionAndPublication
);

//避免加锁阻塞、初始化成本高、允许短暂浪费资源时,使用 PublicationOnly 
Lazy<ExpensiveCache> cache = new Lazy<ExpensiveCache>( 
() => new ExpensiveObject(), 
LazyThreadSafetyMode.PublicationOnly);

// 非线程安全模式(高性能单线程场景)
Lazy<ExpensiveObject> unsafeLazy = new Lazy<ExpensiveObject>(
    () => new ExpensiveObject(),
    LazyThreadSafetyMode.None
);


5. 示例

1. 线程安全模式 (ExecutionAndPublication)

场景:全局配置加载

using System;
using System.Threading;
using System.Threading.Tasks;

#region 模拟配置类 Configuration

public class Configuration
{
    public string Environment { get; set; }
    public int MaxConnections { get; set; }
    public DateTime LoadTime { get; set; }

    public override string ToString() => 
        $"[{Environment}] MaxConnections={MaxConnections}, LoadTime={LoadTime:HH:mm:ss.fff}";
}


#endregion 模拟配置类

#region 配置服务使用线程安全的Lazy初始化
public class AppConfigService
{
    private static int _loadCounter = 0;  // 用于跟踪实际加载次数
    
    private static readonly Lazy<Configuration> _config = 
        new Lazy<Configuration>(() => 
        {
            Interlocked.Increment(ref _loadCounter);//记录实际初始化次数
            Console.WriteLine($">>> [线程 {Thread.CurrentThread.ManagedThreadId}] 开始加载配置...");
            Thread.Sleep(2000);  // 模拟数据库/IO延迟
            
            return new Configuration {
                Environment = "Production",
                MaxConnections = 100,
                LoadTime = DateTime.Now
            };
        }, LazyThreadSafetyMode.ExecutionAndPublication);

    public static Configuration Config => _config.Value; 
    public static int LoadCount => _loadCounter;
}

#endregion

#region Usage

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("=== 配置加载测试(线程安全模式)===");
        Console.WriteLine($"主线程ID: {Thread.CurrentThread.ManagedThreadId}\n");

        // 创建10个并发请求线程
        Parallel.For(0, 10, i => {
            Thread.Sleep(new Random().Next(50));  // 随机延迟增加并发冲突概率
            
            Console.WriteLine($"[线程 {Thread.CurrentThread.ManagedThreadId}] 请求配置...");
            var config = AppConfigService.Config;
            
            Console.WriteLine($"[线程 {Thread.CurrentThread.ManagedThreadId}] 获取配置: {config}");
        });

        Console.WriteLine($"\n实际加载次数: {AppConfigService.LoadCount}");
        Console.WriteLine("测试完成。按任意键退出...");
        Console.ReadKey();
    }
}

#endregion

输出:

=== 配置加载测试(线程安全模式)===
主线程ID: 1

[线程 12] 请求配置...
>>> [线程 12] 开始加载配置...
[线程 6] 请求配置...
[线程 7] 请求配置...
[线程 8] 请求配置...
[线程 9] 请求配置...
[线程 4] 请求配置...
[线程 10] 请求配置...
[线程 1] 请求配置...
[线程 11] 请求配置...
[线程 13] 请求配置...
[线程 1] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 9] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 11] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 6] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 13] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 7] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 8] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 12] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 4] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 10] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947

实际加载次数: 1
测试完成。按任意键退出...



为何适用

  • 配置加载成本高(数据库查询)
  • 需确保所有线程获取同一实例
  • 需避免重复初始化导致资源浪费

2. 发布模式 (PublicationOnly)

场景:轻量级日志记录器

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace PublicationOnlyLoggerDemo
{
    // 日志接口
    public interface ILogger
    {
        void Log(string message);
    }

    // 线程安全的文件日志记录器
    public class FileLogger : ILogger
    {
        private readonly string _filePath;
        
        // 静态锁确保多实例写入时的线程安全
        private static readonly object _fileLock = new object();
        
        // 记录已创建实例数量(用于演示)
        public static int InstanceCount = 0;
        
        // 记录实际写入次数(用于演示)
        public static readonly ConcurrentBag<string> AllLogs = new ConcurrentBag<string>();

        public FileLogger(string filePath)
        {
            
            if (!File.Exists(filePath))
            {
                File.Create(filePath).Close();
            }

            _filePath = filePath;
            Interlocked.Increment(ref InstanceCount);

            lock (_fileLock)
            {
                // 初始化日志文件
                File.WriteAllText(filePath, $"Log initialized at {DateTime.Now:HH:mm:ss.fff}\n");
            }

        }

        public void Log(string message)
        {
            lock (_fileLock)
            {
                File.AppendAllText(_filePath, $"{DateTime.Now:HH:mm:ss.fff} - {message}\n");
            }
            AllLogs.Add(message);
        }
    }

    // 日志工厂(使用PublicationOnly模式)
    public static class LoggerFactory
    {
        private static readonly Lazy<ILogger> _logger = 
            new Lazy<ILogger>(
                () => new FileLogger("app.log"), 
                LazyThreadSafetyMode.PublicationOnly
            );

        public static ILogger GetLogger() => _logger.Value;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("===开启并行日志记录测试===");
            
            // 并行日志记录测试
            Parallel.For(0, 10, i => 
            {
                var logger = LoggerFactory.GetLogger();
                logger.Log($"Task {i} 开启");
                Thread.Sleep(50); // 模拟工作负载
                logger.Log($"Task {i} 完成");
            });

            // 显示统计结果
            Console.WriteLine("\n测试结果:");
            Console.WriteLine($"日志实例创建个数: {FileLogger.InstanceCount}");
            Console.WriteLine($"总计写入日志条目:{FileLogger.AllLogs.Count}");
            Console.WriteLine($"首次使用的日志实例:{FileLogger.AllLogs.First()}");
            Console.WriteLine($"最后使用的日志实例:{FileLogger.AllLogs.Last()}");

            Console.WriteLine("\n日志文件内容:");
            Console.WriteLine("-----------------");
            Console.WriteLine(File.ReadAllText("app.log"));
            
            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }
    }
}

输出:


测试结果:
日志实例创建个数: 10
总计写入日志条目:20
首次使用的日志实例:Task 3 完成
最后使用的日志实例:Task 5 开启

日志文件内容:
-----------------
Log initialized at 10:13:27.464
10:13:27.464 - Task 3 开启
10:13:27.518 - Task 0 完成
10:13:27.518 - Task 2 完成
10:13:27.518 - Task 4 完成
10:13:27.518 - Task 3 完成
10:13:27.518 - Task 5 完成
10:13:27.519 - Task 7 完成
10:13:27.519 - Task 8 完成
10:13:27.519 - Task 1 完成
10:13:27.519 - Task 6 完成
10:13:27.519 - Task 9 完成


按任意键退出...


"
===开启并行日志记录测试===

测试结果:
日志实例创建个数: 10
总计写入日志条目:20
首次使用的日志实例:Task 3 完成
最后使用的日志实例:Task 5 开启

日志文件内容:
-----------------
Log initialized at 10:13:27.464
10:13:27.464 - Task 3 开启
10:13:27.518 - Task 0 完成
10:13:27.518 - Task 2 完成
10:13:27.518 - Task 4 完成
10:13:27.518 - Task 3 完成
10:13:27.518 - Task 5 完成
10:13:27.519 - Task 7 完成
10:13:27.519 - Task 8 完成
10:13:27.519 - Task 1 完成
10:13:27.519 - Task 6 完成
10:13:27.519 - Task 9 完成


按任意键退出...



为何适用

  • 日志初始化简单(创建文件句柄)
  • 可容忍短暂存在多个日志实例
  • 避免锁竞争提升性能

3. 结合依赖注入 (DI)

场景:解决循环依赖

遵循了依赖倒置原则,通过引入抽象层(Lazy代理)解耦了服务之间的直接依赖关系,解决循环依赖问题 。

using System;
using Microsoft.Extensions.DependencyInjection;

public class Program
{
    static void Main(string[] args)
    {
        // 设置依赖注入容器
        var services = new ServiceCollection();
        
        // 注册服务(注意顺序很重要)
        services.AddScoped<PaymentService>();
        services.AddScoped<OrderService>();
        
        // 使用Lazy打破循环依赖
        services.AddScoped(sp => 
            new Lazy<OrderService>(() => sp.GetRequiredService<OrderService>()));
        
        using var serviceProvider = services.BuildServiceProvider();
        
        // 模拟请求范围
        using (var scope = serviceProvider.CreateScope())
        {
            var scopedProvider = scope.ServiceProvider;
            
            Console.WriteLine("解析OrderService...");
            var orderService = scopedProvider.GetRequiredService<OrderService>();
            
            Console.WriteLine("\n调用OrderService处理订单:");
            orderService.ProcessOrder(100.50m);
        }
        
        Console.WriteLine("\n按任意键退出...");
        Console.ReadKey();
    }
}

public class OrderService
{
    private readonly PaymentService _paymentService;
    
    // 正常依赖PaymentService
    public OrderService(PaymentService paymentService)
    {
        Console.WriteLine(">>> OrderService 已创建");
        _paymentService = paymentService;
    }
    
    public void ProcessOrder(decimal amount)
    {
        Console.WriteLine($"处理订单: ${amount}");
        _paymentService.ProcessPayment(amount);
        
        // 模拟其他操作
        Console.WriteLine("订单处理完成!");
    }
    
    public Order GetCurrentOrder() => new Order(DateTime.Now, 100.50m);
}

public class PaymentService
{
    private readonly Lazy<OrderService> _lazyOrderService;
    
    // 通过Lazy间接依赖OrderService
    public PaymentService(Lazy<OrderService> lazyOrderService)
    {
        Console.WriteLine(">>> PaymentService 已创建");
        _lazyOrderService = lazyOrderService;
    }
    
    public void ProcessPayment(decimal amount)
    {
        Console.WriteLine($"处理支付: ${amount}");
        
        // 按需访问OrderService(实际使用时才解析)
        Console.WriteLine("\n需要订单信息,访问Lazy.Value...");
        var currentOrder = _lazyOrderService.Value.GetCurrentOrder();
        
        Console.WriteLine($"获取到当前订单: {currentOrder}");
    }
}

public record Order(DateTime CreatedTime, decimal Amount)
{
    public override string ToString() => 
        $"[{CreatedTime:HH:mm:ss}] ${Amount}";
}

输出

解析OrderService...
>>> PaymentService 已创建
>>> OrderService 已创建

调用OrderService处理订单:
处理订单: $100.50
处理支付: $100.50

需要订单信息,访问Lazy.Value...
获取到当前订单: [10:44:31] $100.50

按任意键退出...


说明:

遵循了依赖倒置原则,引入抽象层(Lazy代理),解耦了服务之间的直接依赖关系,解决循环依赖问题 。

  • 依赖倒置(DIP,Dependency Inversion Principle)设计

    • OrderService → 直接依赖 PaymentService
    • PaymentService → 依赖 Lazy<OrderService>(非直接依赖)
    • 关键点:将强依赖转换为弱依赖
    直接依赖
    依赖代理
    延迟解析
    OrderService
    PaymentService
    LazyProxy
  • 阶段说明

    • 构造阶段:只需要Lazy代理,不触发实际解析

      DI容器 OrderService PaymentService Lazy包装器 尝试创建 需要依赖 请求依赖 返回未初始化代理 返回实例 创建成功 DI容器 OrderService PaymentService Lazy包装器
      • PaymentService 只需要一个"承诺"(Lazy代理),不需要实际 OrderService 实例
      • 避免初始化死锁
    • 执行阶段:依赖树已建立,安全访问

      App OrderService PaymentService Lazy包装器 DI容器 调用方法 传递调用 访问.Value 请求真实实例 返回已存在的OrderService 返回真实实例 完成操作 App OrderService PaymentService Lazy包装器 DI容器
      • 首次访问 .Value 触发实际解析
      • 此时 OrderService 已完全初始化
      • 后续访问使用缓存实例

为何适用

  • 解决紧耦合服务的循环引用问题
  • 延迟初始化高开销服务(如数据库连接)
  • 动态插件加载(Lazy<IPlugin> 按需激活)

使用场景总结

场景 技术选型 理由
全局配置/缓存 线程安全模式 多线程共享 + 单次初始化
轻量级工具类(如日志) 发布模式 允许冗余初始化 + 避免锁性能损耗
UI组件/单线程模块 非线程安全模式 明确线程上下文 + 零开销
DI容器中的复杂服务 `Lazy<T>`注入 打破循环依赖 + 按需加载
网络请求/文件加载 `Lazy<Task<T>>` 或 `AsyncLazy<T>` 非阻塞初始化 + 结果缓存

6. 注意事项与最佳实践

注意点 建议做法
构造函数中不要访问 `.Value` 会导致死循环或异常
避免在委托中抛出异常 使用 try-catch 包裹初始化逻辑,或设置异常处理策略
使用 `IsValueCreated` 检查状态 可用于调试或日志输出

7. 总结

  • 优势

    平衡性能与资源,提供线程安全的按需初始化。

  • 注意

    1. 优先选择默认线程安全模式。
    2. 避免在频繁调用的方法中滥用。 (存在锁竞争/异常放大
    3. 谨慎处理初始化异常。

LazyInitializer

官方文档:LazyInitializer.EnsureInitialized 方法 (System.Threading) | Microsoft Learn

源码:LazyInitializer.cs

1. 概念

  • 基本信息
    • 命名空间System.Threading
    • 程序集System.Threading.dll
    • 继承关系ObjectLazyInitializer
  • 特性
    特性 说明
    零分配开销 避免创建专用延迟初始化实例,比 `Lazy<T>` 更轻量(无额外对象分配)
    引用初始化 通过引用传递确保初始化状态一致性
    线程安全 内部通过锁或原子操作保证线程安全,支持多线程并发调用
    静态方法 直接操作字段,无需创建包装器
    异常处理 初始化函数抛出异常时,后续访问会重试(与 `Lazy<T>` 的缓存异常不同)
    轻量级替代方案 相比 `Lazy<T>` ,无需额外包装对象,直接操作目标字段。
  • 示例
    ExpensiveData _data = null;
    bool _dataInitialized = false;
    object _dataLock = new object();
    
    // 使用示例
    ExpensiveData dataToUse = LazyInitializer.EnsureInitialized(
        ref _data,
        ref _dataInitialized,
        ref _dataLock);
    

2. 方法重载详解

  • 🔧 方法列表

    EnsureInitialized\<T>(T) 在目标引用或值类型尚未初始化的情况下,使用其类型的无参数构造函数初始化目标引用类型。
    EnsureInitialized\<T>(T, Boolean, Object) 在目标引用或值类型尚未初始化的情况下,使用其无参数构造函数对其进行初始化。
    EnsureInitialized\<T>(T, Boolean, Object, Func\<T>) 在目标引用或值类型尚未初始化的情况下,使用指定函数初始化目标引用或值类型。
    EnsureInitialized\<T>(T, Func\<T>) 在目标引用类型尚未初始化的情况下,使用指定函数初始化目标引用类型。
    EnsureInitialized\<T>(T, Object, Func\<T>) 在目标引用类型尚未初始化的情况下,使用指定函数初始化目标引用类型。
  • 重载 1:默认构造函数

    public static T EnsureInitialized<T> (ref T? target) where T : class;
    
    
    • 适用场景:类型有无参构造函数
    • 线程安全:低竞争环境下安全(可能多次构造但最终保留一个实例,类似与Lazy<T>的PublicationOnly模式)
    • 返回: 已初始化的对象。
    • 示例
      private ExpensiveResource _resource;
      public ExpensiveResource Resource => 
          LazyInitializer.EnsureInitialized(ref _resource);
      
  • 重载 2:自定义初始化函数

    public static T EnsureInitialized<T> (ref T? target, Func<T> valueFactory) where T : class;
    
    
    • 适用场景:需参数化构造或复杂初始化逻辑
    • 线程安全:低竞争环境下安全(可能多次构造但最终保留一个实例)
    • 返回: 已初始化的对象。
    • 示例
      private DatabaseConnection _db;
      public DatabaseConnection Db => 
          LazyInitializer.EnsureInitialized(ref _db, 
          () => new DatabaseConnection(_config));
      
  • 重载 3:完全线程安全控制

    public static T EnsureInitialized<T> (ref T target, ref bool initialized, ref object? syncLock, Func<T> valueFactory);
    
    • 适用场景:高并发环境要求严格单次初始化
    • 参数说明
      1. ref T target:需确保初始化的目标对象。 如果是 null,则将其视为未初始化;否则,将其视为已初始化。
      2. ref bool initialized:跟踪初始化状态。如果 initialized 指定为 true,则不会进一步初始化。
      3. ref object syncLock:同步锁对象(可传入 null,方法内部初始化)
      4. Func<T> valueFactory:创建对象的工厂方法,未初始化时调用此方法生成新实例,支持自定义逻辑(如构造函数、依赖注入等)。
    • 示例
      private Logger _logger;
      private bool _loggerInitialized;
      private object _loggerLock = new object();
      
      public Logger Logger => 
          LazyInitializer.EnsureInitialized(
              ref _logger, 
              ref _loggerInitialized, 
              ref _loggerLock, 
              () => new Logger("app.log"));
      

3. 与 Lazy 的对比

特性 LazyInitializer.EnsureInitialized() Lazy\<T>
内存开销 无额外对象分配(直接操作字段) 需分配 `Lazy<T>` 包装器实例
异常缓存 不缓存异常(每次失败后重试) 缓存异常(首次异常后永远抛出)
适用类型 仅引用类型 支持值类型和引用类型
初始化状态跟踪 需手动管理 内置状态管理

4. 最佳实践

  1. 首选场景
    • 性能敏感且需最小化内存开销时
    • 直接初始化现有字段(非新属性)
  2. 线程安全建议
    • 低竞争环境 → 使用重载 1 或 2
    • 高并发场景 → 使用重载 3(严格单次初始化)
  3. 锁对象管理
    • 传入 null 让方法初始化锁对象:

      object _lock = null; // 方法内部会替换为 new object()
      
    • 若需复用同一锁,提前初始化锁对象

  4. 避免值类型:不支持值类型(编译错误),需改用 Lazy<T>

5. 总结

通过引用传递和锁对象机制,LazyInitializer 提供了比 Lazy<T> 更轻量的延迟初始化方案,适用于需要精细控制初始化过程的场景。

  • 优势:轻量高效、直接操作字段、灵活控制线程安全。
  • 适用:引用类型的延迟初始化,性能敏感场景。
  • 注意
    • 高并发环境须使用重载 3
    • 需要异常重试逻辑时优先选择(与 Lazy<T> 异常缓存行为不同)
    • 避免用于值类型

选择建议

  • 如果需要快速实现线程安全的延迟初始化且对性能要求不是极致,可优先选择Lazy<T>
  • 如果在性能敏感的场景下,且初始化逻辑简单,可选择LazyInitializer.EnsureInitialized

总结

Lazy<T>LazyInitializer.EnsureInitialized可以实现延迟初始化,按需加载资源,提升启动性能并节省内存。

Lazy<T>提供了封装良好的延迟初始化机制,支持复杂的初始化逻辑和多种线程安全模式,适用于需要延迟加载的场景。

LazyInitializer.EnsureInitialized 则更加轻量级,直接操作字段,适用于性能敏感且需要最小化内存开销的场景。

在实际应用中,需要根据具体需求选择合适的方式。

  1. 需要线程安全的场景,Lazy<T>的默认模式(ExecutionAndPublication)是首选;
  2. 而对于性能敏感且初始化逻辑简单的场景,LazyInitializer.EnsureInitialized 的重载提供了更高效的解决方案。
  3. 同时,开发者还需要注意异常处理、线程安全模式的选择以及避免滥用延迟初始化导致的性能问题。

网站公告

今日签到

点亮在社区的每一天
去签到