惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
小众软件
小众软件
博客园 - 叶小钗
宝玉的分享
宝玉的分享
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
SegmentFault 最新的问题
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
Google DeepMind News
Google DeepMind News
U
Unit 42
F
Fortinet All Blogs
IT之家
IT之家
Y
Y Combinator Blog
Martin Fowler
Martin Fowler
T
The Blog of Author Tim Ferriss
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - lightsong

LoRA unsloth比transformer库本身的微调有什么优点? offline-llms +++ transformer + peft 微调 Train and Fine-Tune Sentence Transformers Models Symmetric vs. Asymmetric Semantic Search Hierarchical Navigable Small Worlds (HNSW) Vision Transformer + BentoML ML Serving/编排工具 Introducing Gemma 3 270M: The compact model for hyper-efficient AI Utopia -- 企业世界模型 trustgraph semantica semantica vs graphti Industrial-Strength Natural Language Processing seata reference with springboot and other valuable demo outbox pattern with springboot Saga pattern with springboot 基于 Sentence Transformers 的具体应用案例 Vault with Keycloak as workload IAM Ontology Reasoning System ADR Claude Code的hook The AI-Native SDLC playbook Introduction to Dapper Introduction to FluentValidation Introduction to AutoFixture Introduction to FluentAssertions Introduction to Refit Introduction to Carter Introduction to Minimal APIs
Understanding Return Types: IEnumerable, IReadOnlyCollect...
lightsong · 2026-08-28 · via 博客园 - lightsong

Understanding Return Types:
IEnumerable, IReadOnlyCollection, and List

https://jdaniel1987.github.io/CollectionReturnTypes

这是一篇关于 C# 集合返回类型选择的深度技术文章。我已经为你整理好了完整的中文翻译,并保留了图文并茂的排版结构,你可以直接复制到博客编辑器中发布。


博客文章草稿

标题: 理解返回类型:IEnumerable、IReadOnlyCollection 和 List
作者: Jaime Daniel Delgado Ortega
发布时间: 2024年9月25日
更新时间: 2024年9月26日
阅读时间: 4 分钟


引言

在 C# 中处理集合时,为方法选择合适的返回类型会极大地影响代码的性能、设计和灵活性。在这篇文章中,我们将探讨三种常用的返回类型:IEnumerable<T>IReadOnlyCollection<T>List<T>。我们将深入分析它们的区别、使用场景、优缺点,以帮助你决定在何时使用哪一种。


1. IEnumerable

IEnumerable<T> 是 .NET 中最基础的集合接口。它允许你遍历一系列元素,但不保证数据存储在内存中或随时可用。

代码示例

public static IEnumerable<int> GetNumbersDeferredExecution() =>
    // 延迟执行,存在风险
    Enumerable.Range(1, 5).Select(_ => new Random().Next(1, 100));

优点

  • 延迟执行 (Deferred execution):数据仅在需要时生成。如果你处理的是大型数据集或昂贵的操作,这在内存和性能上可能更高效。
  • 灵活性IEnumerable<T> 适用于任何实现它的集合类型,包括数组、列表甚至自定义集合。
  • 低内存占用:由于数据不一定存储在内存中,你可以避免在绝对必要之前将大型集合实例化(Materialize)。

缺点

  • 无法获取 Count 或索引:你不能直接获取集合的大小或通过索引访问元素。
  • 潜在的低效:多次访问数据可能效率低下,因为每次迭代时序列都会被重新计算,除非你显式地将其实例化(例如使用 ToList())。

注意: 请看下面的输出示例,两次迭代生成的随机数完全不同,这就是因为序列被重新计算了。

var numbers = GetNumbersDeferredExecution();

// 第一次迭代
Console.WriteLine("First iteration of random numbers:");
Console.WriteLine(string.Join(" ", numbers));
// 输出: 15 37 65 59 38

Console.WriteLine();

// 第二次迭代
Console.WriteLine("Second iteration of random numbers:");
Console.WriteLine(string.Join(" ", numbers));
// 输出: 75 14 74 27 44

何时使用

  • 当你处理大型数据集或希望进行惰性求值(Lazy evaluation)的操作时。
  • 当你确定调用者只需要遍历集合一次时。

2. IReadOnlyCollection

IReadOnlyCollection<T> 是一个更专门的接口,代表一个具有已知大小的只读集合。它保证调用者无法修改集合,但你仍然可以访问 Count 属性。

代码示例

public static IReadOnlyCollection<int> GetReadOnlyNumbers() =>
    // 已实例化的集合,不可变
    Enumerable.Range(1, 5).Select(_ => new Random().Next(1, 100)).ToList();

优点

  • 只读安全性:确保集合的使用者无法修改其内容。
  • 可访问 Count:与 IEnumerable<T> 不同,你可以直接检索集合中的元素数量。
  • 封装性:隐藏了实现细节(例如,它到底是一个 List<T> 还是一个数组),同时提供了只读访问权限。

缺点

  • 数据已实例化:与 IEnumerable<T> 不同,集合已在内存中实例化,这对于非常大的数据集可能不是理想的选择。
  • 功能有限:你不能修改集合或通过索引访问它,这限制了它在需要这些操作的场景中的使用。

何时使用

  • 当你想向调用者公开一个集合,但需要保证它不会被修改时。
  • 当集合的大小很重要,且你需要确保数据已经加载到内存中时。

3. List

List<T> 是 .NET 中最常用的集合类型。它提供了对集合的完全访问权限,包括修改集合和通过索引访问元素的能力。

代码示例

public static List<int> GetNumbersAsList() =>
    // 完整的列表访问权限
    Enumerable.Range(1, 5).Select(_ => new Random().Next(1, 100)).ToList();

优点

  • 完全控制:你可以添加、删除和修改元素,并通过索引访问它们。
  • 小集合效率高:当处理需要修改的相对较小的集合时,List<T> 是首选。
  • 丰富的 API:提供了广泛的方法来操作数据(Add, Remove, Insert 等)。

缺点

  • 更高的内存使用:由于数据完全在内存中实例化,处理大型数据集时效率可能较低。
  • 潜在的过度暴露:返回 List<T> 允许调用者修改数据,这并不总是我们所希望的。在这种情况下,暴露过多的控制权可能会导致意外的副作用。

何时使用

  • 当你需要对集合进行完全控制,并希望通过索引修改或访问元素时。
  • 当处理不会对内存造成显著影响的小型到中型数据集时。

特别篇:在 IEnumerable 上使用 ToList()

如果你在 IEnumerable<T> 上调用 ToList(),集合会立即被实例化,从而失去延迟执行的好处。但是,如果你要多次访问该集合,这可以提高效率。

代码示例

public static IEnumerable<int> GetNumbersMaterialized() =>
    // 已实例化的集合,保持灵活性
    Enumerable.Range(1, 5).Select(_ => new Random().Next(1, 100)).ToList();

通过转换为列表,你在调用 GetNumbersAsList()避免了多次迭代的低效问题。你也保留了灵活性,例如以后可以将集合转换为不同的类型(例如数组)。然而,这种方法牺牲了延迟执行的潜在优势


结论

根据你的具体需求,每种返回类型都有其用武之地:

  • IEnumerable<T>:当你需要灵活性、延迟执行或处理大型数据集时使用。
  • IReadOnlyCollection<T>:当你想公开一个集合但防止修改,同时又需要访问集合大小时,这是理想的选择。
  • List<T>:当你需要对集合进行完全控制,包括修改和随机访问时,这是最佳选择。

选择正确的返回类型会对代码的性能、安全性和灵活性产生巨大影响。请务必了解每个选项的权衡,以便针对你的特定用例进行优化。


示例项目链接:
GitHub - CollectionTypes

标签: #C# #.NET #Collections #IEnumerable #IReadOnlyCollection #List

(本文根据 CC BY 4.0 许可协议发布)

出处:http://www.cnblogs.com/lightsong/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。