数据访问层:暴露列表<>:坏主意?

发布于 2024-07-07 09:58:56 字数 278 浏览 5 评论 0 原文

我目前正在编写一个简单的数据访问层,我想知道应该向其他层公开哪种类型。

我将在内部将数据实现为 List<>,但我记得读过一些关于在不需要时不向消费者公开 List 类型的内容。

public List<User> GetAllUsers() // non C# users: that means List of User :)

你知道为什么吗(谷歌没有帮助)? 你通常会为这类事情暴露什么? 列表? IE可数?

I am currently coding a simple Data Access Layer, and I was wondering which type I should expose to the other layers.

I am going to internally implement the Data as a List<>, but I remember reading something about not exposing the List type to the consumers if not needed.

public List<User> GetAllUsers() // non C# users: that means List of User :)

Do you know why (google didn't help)? What do you usually expose for that kind of stuff? IList? IEnumerable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凝望流年 2024-07-14 09:58:56

通常最好公开用户仍然可以有意义地使用的最不强大的界面。 如果用户只需要一些可枚举数据,则返回IEnumerable。 如果这还不够,因为用户需要能够修改列表(注意!不应该经常出现这种情况),请返回 IList

/编辑:

乔尔在他的评论中提出了一个有效的问题:为什么确实暴露最不强大的接口而不是授予用户最大的权力? (解释)

这背后的想法是,返回数据的方法可能不希望用户修改其内容:该类的另一个方法可能仍然希望在返回对列表的引用后列表非空。 想象一下用户从列表中删除所有数据。 另一种方法现在必须进行额外的检查,以确定 ele 可能是不必要的。

更重要的是,这通过返回类型公开了部分内部实现。 如果我将来需要更改实现,以便它不再使用 IList 容器,我会遇到一个问题:我要么需要更改方法契约,引入破坏构建的更改。 或者我需要将数据复制到列表容器中。

举个例子,假设一个高效的实现使用字典并且只返回 Values 集合,而该集合没有实现 IList

Usually it's best to expose the least powerful interface that the user can still meaningfully work with. If the user just needs some enumerable data, return IEnumerable<User>. If that's not enough because the user needs to be able to modify the list (attention! shouldn't often be the case), return an IList<User>.

/EDIT:

Joel asks a valid question in his comment: Why indeed expose the least powerful interface instead of granting the user maximum power? (paraphrased)

The idea behind this is that the method returning the data might not expect the user to modify its content: Another method of the class might still expect the list to be non-empty after a reference to it was returned. Imagine the user removes all data from the list. The other method now has to make an additional check that ele might have been unnecessary.

More importantly, this exposes parts of the internal implementation through the return type. If I need to change the implementation in the future so that it no longer uses an IList container, I have a problem: I either need to change the method contract, introducing a build-breaking change. Or I need to copy the data into a list container.

As an example, imagine that an efficient implementation uses a Dictionary and just returns the Values collection which doesn't implement IList.

记忆里有你的影子 2024-07-14 09:58:56

绝对是我的事。 使用接口将减少耦合,并使以后更容易更改数据层实现的细节。 哪个接口要看具体情况。 IList 很好,但有时您可能需要 ICollection 功能或想要指定只读值。

Definitely an ISomething. Using an interface will reduce coupling and make it easier to change details of your data layer's implementation down the road. Which interface depends on the circumstances. IList is good, but sometimes you may need ICollection functionality or want to specify values that are ReadOnly.

小情绪 2024-07-14 09:58:56

返回 IEnumerable 之前应该仔细考虑。 如果底层代码使用“yield”生成 IEnumerable,或者使用 LINQ,那么您最终将保持打开任何使用的资源。

在返回之前,您应该将 IEnumerable 复制到另一个 IEnumerable 中。 通过使用 IList,您可以将其作为一项要求,这样任何人都不会无意中返回 IEnumerable。

另一方面,返回 IList 意味着调用者可以更改返回的列表。

You should think carefully before returning IEnumerable. If the underlying code is using "yield" to generate the IEnumerable, or is using LINQ, then you'll end up holding open any resources used.

You should copy the IEnumerable into another IEnumerable before returning it. By using IList, you make this a requirement, so that nobody can inadvertently return an IEnumerable.

On the other hand, returning an IList implies to the caller that they can change the returned list.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文