IEnumerable vs IReadonlyCollection vs ReadonlyCollection 用于公开列表成员

2024-04-13

我花了好几个小时思考曝光名单成员的问题。在与我类似的问题中,乔恩·斯基特(Jon Skeet)给出了很好的答案。请随意看看。

ReadOnlyCollection 或 IEnumerable 用于公开成员集合? https://stackoverflow.com/questions/491375/readonlycollection-or-ienumerable-for-exposing-member-collections

我通常对公开列表非常偏执,尤其是当您正在开发 API 时。

我一直使用 IEnumerable 来公开列表,因为它非常安全,并且提供了很大的灵活性。让我在这里举个例子:

public class Activity
{
    private readonly IList<WorkItem> workItems = new List<WorkItem>();

    public string Name { get; set; }

    public IEnumerable<WorkItem> WorkItems
    {
        get
        {
            return this.workItems;
        }
    }

    public void AddWorkItem(WorkItem workItem)
    {
        this.workItems.Add(workItem);
    }
}

任何针对 IEnumerable 进行编码的人在这里都是非常安全的。如果我后来决定使用有序列表或其他东西,它们的代码都不会中断,而且仍然很好。这样做的缺点是 IEnumerable 可以被强制转换回此类之外的列表。

因此,许多开发人员使用 ReadOnlyCollection 来公开成员。这是非常安全的,因为它永远不能被转换回列表。对我来说,我更喜欢 IEnumerable,因为它提供了更大的灵活性,如果我想要实现与列表不同的东西的话。

我想出了一个我更喜欢的新主意。使用 IReadOnlyCollection:

public class Activity
{
    private readonly IList<WorkItem> workItems = new List<WorkItem>();

    public string Name { get; set; }

    public IReadOnlyCollection<WorkItem> WorkItems
    {
        get
        {
            return new ReadOnlyCollection<WorkItem>(this.workItems);
        }
    }

    public void AddWorkItem(WorkItem workItem)
    {
        this.workItems.Add(workItem);
    }
}

我觉得这保留了 IEnumerable 的一些灵活性,并且封装得相当好。

我发布这个问题是为了了解我的想法。与 IEnumerable 相比,您更喜欢此解决方案吗?您认为使用 ReadOnlyCollection 的具体返回值更好吗?这是一场相当激烈的辩论,我想尝试看看我们都能提出哪些优点/缺点。

EDIT

首先感谢大家对这里的讨论做出了如此多的贡献。我确实从每个人身上学到了很多东西,并真诚地感谢你们。

我正在添加一些额外的场景和信息。

IReadOnlyCollection 和 IEnumerable 有一些常见的陷阱。

考虑下面的例子:

public IReadOnlyCollection<WorkItem> WorkItems
{
    get
    {
        return this.workItems;
    }
}

即使接口是只读的,上面的示例也可以转换回列表并进行更改。尽管接口同名,但它并不能保证不变性。您需要提供一个不可变的解决方案,因此您应该返回一个新的 ReadOnlyCollection。通过创建一个新列表(本质上是一个副本),对象的状态是安全可靠的。

Richiban 在他的评论中说得最好:界面只保证某些东西可以做什么,而不保证它不能做什么。

请参阅下面的示例:

public IEnumerable<WorkItem> WorkItems
{
    get
    {
        return new List<WorkItem>(this.workItems);
    }
}

上面的内容可以被转换和改变,但你的对象仍然是不可变的。

另一个开箱即用的声明是集合类。考虑以下:

public class Bar : IEnumerable<string>
{
    private List<string> foo;

    public Bar()
    {
        this.foo = new List<string> { "123", "456" };
    }

    public IEnumerator<string> GetEnumerator()
    {
        return this.foo.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

上面的类可以具有按照您希望的方式改变 foo 的方法,但是您的对象永远不能转换为任何类型的列表并发生改变。

Carsten Führmann 对 IEnumerables 中的yield return 语句提出了一个精彩的观点。


到目前为止,答案似乎缺少一个重要的方面:

When an IEnumerable<T>返回给调用者时,他们必须考虑返回的对象是“惰性流”的可能性,例如以“收益回报”构建的集合。也就是说,生产元素的性能损失IEnumerable<T>调用者可能必须为每次使用 IEnumerable 付费。 (生产力工具“Resharper”实际上指出这是代码味道。)

相比之下,一个IReadOnlyCollection<T>向调用者发出信号,表明不会有惰性求值。 (这Count财产,而不是 of IEnumerable<T>(继承自IReadOnlyCollection<T>所以它也有这个方法),表示不懒惰。事实上,似乎没有 IReadOnlyCollection 的惰性实现。)

这对于输入参数也有效,因为请求IReadOnlyCollection<T>代替IEnumerable<T>表示该方法需要对集合进行多次迭代。当然,该方法可以从以下位置创建自己的列表:IEnumerable<T>并对其进行迭代,但由于调用者手头可能已经有一个加载的集合,因此只要有可能就利用它是有意义的。如果调用者只有一个IEnumerable<T>手头的,他只需要添加.ToArray() or .ToList()到参数。

IReadOnlyCollection 的作用not要做的就是防止调用者强制转换为其他集合类型。对于这种保护,人们必须使用class ReadOnlyCollection<T>.

综上所述,only thing IReadOnlyCollection<T>确实相对于IEnumerable<T>是添加一个Count财产,从而表明不涉及懒惰。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IEnumerable vs IReadonlyCollection vs ReadonlyCollection 用于公开列表成员 的相关文章

  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • 如何将图像和 POST 数据上传到 Azure 移动服务 ApiController 终结点?

    我正在尝试上传图片and POST表单数据 尽管理想情况下我希望它是json 到我的端点Azure 移动服务应用 我有ApiController method HttpPost Route api upload databaseId sea
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • Json.NET - 反序列化接口属性引发错误“类型是接口或抽象类,无法实例化”

    我有一个类 其属性是接口 public class Foo public int Number get set public ISomething Thing get set 尝试反序列化Foo使用 Json NET 的类给我一条错误消息
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • Github Action 在运行可执行文件时卡住

    我正在尝试设置运行google tests on a C repository using Github Actions正在运行的Windows Latest 构建过程完成 但是当运行测试时 它被卡住并且不执行从生成的可执行文件Visual
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • 为什么我收到“找不到编译动态表达式所需的一种或多种类型。”?

    我有一个已更新的项目 NET 3 5 MVC v2 到 NET 4 0 MVC v3 当我尝试使用或设置时编译出现错误 ViewBag Title财产 找不到编译动态表达式所需的一种或多种类型 您是否缺少对 Microsoft CSharp
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐

  • 在jquery中创建循环背景动画

    我想要的是 当页面加载时 背景颜色为红色 10 秒后 bgColor 变为绿色 并带有淡入淡出动画 再过 10 秒后 它会变成橙色 然后又变成红色 依此类推 有人可以帮忙吗 Use 设置间隔 http www w3schools com j
  • Firestore - 如何在数据库中自动减少整数值?

    Firestore 最近推出了一项新功能 可以自动递增和递减整数值 我可以使用增加整数值 例如 FieldValue increment 50 但如何减量呢 我尝试使用FieldValue decrement 50 但FieldValue中
  • 在 C++ 中旋转图像而不使用 OpenCV 函数

    描述 我正在尝试在不使用 C 中的 OpenCV 函数的情况下旋转图像 旋转中心不必是图像的中心 它可能是不同的点 偏离图像中心 到目前为止 我遵循各种来源进行图像插值 我知道source https stackoverflow com a
  • 检测节点的系统路径上是否存在可执行文件

    Question 有没有一种简单的方法可以使用节点判断系统可执行文件在系统路径上是否可用 例如 如果用户安装了 python usr bin python and usr bin is in PATH我如何在 Node 中检测到这一点 相反
  • 在 Filter 内执行并呈现 JSP

    我有一个包含页面顶部内容的 JSP 我们将其称为 header jsp 出于性能原因 我想在构建页面的其余部分之前呈现此 JSP 并将其刷新给用户 看here http developer yahoo com performance rul
  • 元素不可点击错误 Ruby / Watir

    在我的测试中 我尝试访问 etsy com 进行搜索 单击结果 然后将商品添加到我的购物车 我可以做所有事情 直到我尝试单击 添加到购物车 按钮 下面的代码实际上在 IRB 中工作 所以我知道我的定位器是可靠的 但是当我运行测试时 我得到一
  • 在 Elasticsearch 中过滤折叠结果

    我有一个弹性搜索索引 其中包含表示给定时间点实体的文档 当实体更改状态时 会创建带有时间戳的新文档 当我需要获取所有实体的当前状态时 我可以执行以下操作 GET https 127 0 0 1 9200 myindex search col
  • .NET RIA 服务与 MVC 风格存储库?

    我有一个包含多个项目的解决方案 包括两个共享位于外部程序集中 也在同一解决方案中 的存储库和模型的 asp net mvc 项目 本质上 Core 存储库 楷模 国内 Web 基本MVC站点 引用核心项目 国际网 基本MVC站点 引用核心项
  • 使用 NativeMessaging 进行边缘扩展

    我有一个具有本机消息传递支持的边缘扩展 它与系统中运行的 uwp 应用程序进行通信 是否必须将扩展打包到 uwp 应用程序的 appx 文件夹中 如果没有 那么我们如何将扩展上传到边缘扩展存储中 我遵循 secureInput 示例 htt
  • 快速向 SQL Server 插入 200 万行

    我必须从文本文件中插入大约 200 万行 通过插入 我必须创建一些主表 将如此大的数据集插入 SQL Server 的最佳且快速的方法是什么 我认为最好读取 DataSet 中文本文件的数据 试用SQL批量复制 从 C 应用程序批量插入 S
  • GSON反序列化:如何知道对象?

    我尝试使用 gson 库来反序列化发送给我的对象流 在我见过的所有示例中 当调用 fromJson 方法时 我们已经知道我们期望拥有什么类型的对象 就我而言 我收到不同对象的流 我想知道在反序列化对象之前了解对象类的最佳方法 A B B1
  • Android 自定义通知布局与 RemoteViews

    我正在尝试使用此为我的 Android 应用程序创建自定义通知post https stackoverflow com questions 18367631 change notification layout 我偶然发现了一个我在过去 2
  • 使用 LIMIT 时获取总行数? [复制]

    这个问题在这里已经有答案了 可能的重复 使用 offset limit 查找 mySQL 查询中的结果总数 https stackoverflow com questions 5928611 find total number of res
  • JAX-RS自定义ExceptionMapper不拦截RuntimeException

    我想包裹底层RuntimeExceptions自定义 json 格式 使得 servlet 容器不会将堆栈跟踪转储到客户端 我关注这个问题 使用 XML 或 JSON 的 JAX RS Jersey 自定义异常 https stackove
  • 强制 MySQL 在连接上使用两个索引

    我试图强制 MySQL 使用两个索引 我正在加入一个表 我想利用两个索引之间的交叉 具体术语是 Using intersect 这里是 MySQL 文档的链接 http dev mysql com doc refman 5 0 en ind
  • Xamarin 表单:从 Xamarin Forms 应用程序启动 IOS 应用程序时出现问题(输入 URL 无效)

    我正在尝试从我的 xamarin forms ios 应用程序打开一个 ios 应用程序 我已经提到过this https stackoverflow com questions 43944283 launch another ios ap
  • 使用 NuGet 安装 NHibernate 3.2

    我是 NHibernate 的新手 一直在尝试使用 NuGet 来启动和运行它 Fluent NHibernate 和 NProf 读完这篇文章后 http gurustop net blog 2011 03 13 nhibernate 3
  • SVGforeignObject 无法在任何浏览器上显示,为什么?

    我在 SVG 元素中有一个foreignObject 所有其他元素都会显示 但foreignObject 及其内容是不可见的 在 Chrome Firefox 和 Edge 中进行了测试 结果均相同 这是代码
  • 尝试使用 PHP 通过 HMAC-SHA1 进行数字签名

    我正在尝试设置一些 Google Maps Premier API 操作 为此 我需要对我的网址进行签名以进行身份 验证 如果您查看签名示例 可以看到一些 Python C 和 Java 代码向您展示如何通过 HMAC SHA1 进行签名
  • IEnumerable vs IReadonlyCollection vs ReadonlyCollection 用于公开列表成员

    我花了好几个小时思考曝光名单成员的问题 在与我类似的问题中 乔恩 斯基特 Jon Skeet 给出了很好的答案 请随意看看 ReadOnlyCollection 或 IEnumerable 用于公开成员集合 https stackoverf