C#:类持有List<Banana>时,如何在只读接口暴露List<IBananaRead>?
实现只读接口的列表映射(无需维护重复列表)
需求背景
为Box类创建只读接口IBoxRead,Box内部依赖List<Banana>处理所有操作;Banana类对应只读接口IBananaRead。需满足:
IBoxRead对外暴露IBananaRead类型的集合,而非Banana实例- 禁止维护两个重复的列表
- 支持两种交互:
- 只读权限类遍历
IBananaRead调用ReadTheBanana() - 编辑权限类遍历
Banana调用EditTheBanana()
- 只读权限类遍历
初始代码示例
class Box : IBoxRead { List<Banana> bananas; } interface IBoxRead { List<IBananaRead> bananas; }
不认可的方案(维护重复列表)
该方案需同步两个列表,易引发数据不一致,因此被否决:
class Box : IBoxRead { List<Banana> bananas; List<IBananaRead> bananaReads; } interface IBoxRead { List<IBananaRead> bananaReads; }
正确实现方案
1. 定义基础接口与实体类
确保Banana实现IBananaRead,分离只读与编辑方法:
public interface IBananaRead { void ReadTheBanana(); } public class Banana : IBananaRead { public void ReadTheBanana() { // 只读逻辑实现 } public void EditTheBanana() { // 编辑逻辑实现 } }
2. 实现只读接口与Box类
将IBoxRead的集合改为IReadOnlyList<IBananaRead>(避免外部修改),通过自定义包装类映射原List<Banana>,无需维护重复列表:
public interface IBoxRead { IReadOnlyList<IBananaRead> Bananas { get; } } public class Box : IBoxRead { private readonly List<Banana> _bananas = new List<Banana>(); // 对外暴露只读集合,通过包装类映射原列表 public IReadOnlyList<IBananaRead> Bananas => new ReadOnlyBananaWrapper(_bananas); // 给编辑权限类提供原列表访问入口(可添加权限校验逻辑) public List<Banana> GetEditableBananas() { return _bananas; } // 自定义包装类:将List<Banana>转换为IReadOnlyList<IBananaRead> private class ReadOnlyBananaWrapper : IReadOnlyList<IBananaRead> { private readonly List<Banana> _source; public ReadOnlyBananaWrapper(List<Banana> source) { _source = source; } public IBananaRead this[int index] => _source[index]; public int Count => _source.Count; public IEnumerator<IBananaRead> GetEnumerator() { foreach (var banana in _source) yield return banana; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } }
3. 使用场景示例
- 只读操作:通过
IBoxRead接口访问集合
void ProcessReadOnlyBananas(IBoxRead box) { foreach (var banana in box.Bananas) banana.ReadTheBanana(); }
- 编辑操作:直接访问
Box的可编辑列表
void EditBananas(Box box) { foreach (var banana in box.GetEditableBananas()) banana.EditTheBanana(); }
方案优势
- 无重复列表,所有操作基于原
List<Banana>,避免数据不一致 IReadOnlyList<IBananaRead>确保外部无法修改集合结构或调用编辑方法- 包装类仅在遍历/访问时映射,无额外内存开销,性能接近原列表
内容的提问来源于stack exchange,提问作者luminous
相关产品推荐
相关产品推荐

