如何在ClassA中为IInterfaceA的ListSequences属性实现延迟初始化
实现ListSequences的延迟初始化与数据加载
要在ClassA中实现ListSequences属性的延迟初始化(首次访问时才加载数据),同时满足接口的只读属性要求,推荐两种实现方式:
方式一:使用.NET内置的Lazy<T>(推荐)
Lazy<T>是.NET官方提供的懒加载工具类,自带线程安全控制,代码简洁且易维护。
修改后的ClassA代码
using System; using System.Collections.Generic; using System.Threading; public interface IInterfaceA : IBase { int Sequence { get; } IList<IInterfaceA> ListSequences { get; } string ApprovedBy { get; } DateTime ApprovedOn { get; } } public interface IBase { string ID { get; } string Name { get; } string Notes { get; } } public class Base : IBase { public string ID { get; } public string Name { get; } public string Notes { get; } public Base(string id, string name, string notes) { ID = id; Name = name; Notes = notes; } } public class ClassA : Base, IInterfaceA { private readonly int _sequence; private readonly string _approvedBy; private readonly DateTime _approvedOn; // 懒加载字段,存储ListSequences的加载逻辑 private readonly Lazy<IList<IInterfaceA>> _lazyListSequences; // 构造函数:传入加载子序列的逻辑(灵活适配不同数据源) public ClassA(string id, string name, string notes, int sequence, string approvedBy, DateTime approvedOn, Func<IList<IInterfaceA>> loadSequences) : base(id, name, notes) { _sequence = sequence; _approvedBy = approvedBy; _approvedOn = approvedOn; // 初始化Lazy,指定线程安全模式(ExecutionAndPublication确保仅一次执行加载逻辑) _lazyListSequences = new Lazy<IList<IInterfaceA>>(loadSequences, LazyThreadSafetyMode.ExecutionAndPublication); } // 重载构造函数:内置默认数据源加载逻辑 public ClassA(string id, string name, string notes, int sequence, string approvedBy, DateTime approvedOn) : base(id, name, notes) { _sequence = sequence; _approvedBy = approvedBy; _approvedOn = approvedOn; _lazyListSequences = new Lazy<IList<IInterfaceA>>(() => LoadSequencesFromDataSource(ID), LazyThreadSafetyMode.ExecutionAndPublication); } // 实现接口属性:首次访问时触发加载 public int Sequence => _sequence; public string ApprovedBy => _approvedBy; public DateTime ApprovedOn => _approvedOn; public IList<IInterfaceA> ListSequences => _lazyListSequences.Value; // 模拟从数据源加载子序列的方法(替换为实际业务逻辑) private IList<IInterfaceA> LoadSequencesFromDataSource(string parentId) { // 示例:从数据库/API查询当前ClassA对应的子序列 var sequences = new List<IInterfaceA>(); sequences.Add(new ClassA($"{parentId}_sub1", "子序列1", "备注1", 1, "admin", DateTime.Now)); sequences.Add(new ClassA($"{parentId}_sub2", "子序列2", "备注2", 2, "admin", DateTime.Now)); return sequences; } }
关键说明
Lazy<T>的Value属性首次被访问时,才会执行传入的加载委托,实现延迟初始化。LazyThreadSafetyMode.ExecutionAndPublication确保多线程环境下仅执行一次加载逻辑,避免重复加载。- 提供两种构造函数:一种允许外部传入加载逻辑(灵活适配不同场景),另一种内置默认加载逻辑(适合固定数据源)。
方式二:手动实现双重检查锁定(自定义线程安全控制)
如果需要更精细的线程安全控制,可以手动实现双重检查锁定的懒加载逻辑:
修改后的ListSequences属性实现
public class ClassA : Base, IInterfaceA { // ... 其他字段和构造函数保持不变 ... private IList<IInterfaceA> _listSequences; // 用于锁定的私有对象(避免用this锁定引发其他问题) private readonly object _lockObj = new object(); public IList<IInterfaceA> ListSequences { get { // 第一次检查:未初始化才进入锁定逻辑 if (_listSequences == null) { lock (_lockObj) { // 第二次检查:确保锁定期间未被其他线程初始化 if (_listSequences == null) { _listSequences = LoadSequencesFromDataSource(ID); } } } return _listSequences; } } // ... 其他属性和方法保持不变 ... }
关键说明
- 双重检查锁定避免了每次访问属性都进入锁定逻辑,兼顾性能和线程安全。
- 使用独立的
_lockObj作为锁定对象,避免因外部锁定this导致的死锁风险。
注意事项
- 由于
IInterfaceA中ListSequences定义为只读属性(仅get),因此无法通过公共 setter 赋值,只能通过懒加载的方式在首次访问时填充数据。 - 加载逻辑需根据实际业务场景实现(如数据库查询、API调用等),示例中的
LoadSequencesFromDataSource仅为模拟代码。
内容的提问来源于stack exchange,提问作者AMDI
相关产品推荐
相关产品推荐

