ReadOnlyCollection 类是糟糕设计的一个很好的例子吗?

发布于 2024-09-26 21:40:26 字数 1432 浏览 8 评论 0原文

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

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

发布评论

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

评论(8

失与倦" 2024-10-03 21:40:26

是的,这确实是糟糕的设计。 .NET 中缺少集合接口:没有只读接口。

您是否知道 string[] 实现了 IList (其他类型也是如此)?这也有同样的问题:您希望可以在界面上调用 AddRemove,但它会抛出异常。

不幸的是,在不破坏向后兼容性的情况下不能再改变这一点,但我同意你的观点,这是非常糟糕的设计。更好的设计应该为只读功能提供单独的接口。

Yes, it is bad design indeed. The collection interfaces are lacking in .NET: there are no read-only interfaces.

Did you know that string[] implements IList<string> (and ditto for other types)? This has the same problem: you would expect that you can call Add and Remove on the interface, but it would throw.

Unfortunately, this cannot be changed anymore without breaking backwards compatibility, but I agree with you that it is very bad design. A better design would have seen separate interfaces for the read-only capabilities.

旧夏天 2024-10-03 21:40:26

虽然 IList 接口定义了 Add(T)Insert(int,T) 方法,但它还定义了 IsReadOnly code> 属性,并且如果您仔细阅读 IList 的定义。插入(int,T)IList MSDN 上的 .Add(T) 方法,您可以看到它们都指定如果 list 是只读的,方法可能会抛出 NotSupportedException

因为这个原因说它是糟糕的设计就像说它也是糟糕的设计,因为当索引为负或大于大小时 Insert(int, T) 可能会抛出 ArgumentOutOfRangeException的收藏。

Although IList<T> interface defines Add(T) and Insert(int,T) methods, it also defines IsReadOnly property and if you read carefully definition of IList.Insert(int,T) and IList.Add(T) methods on MSDN, you can see that they both specify that methods could throw NotSupportedException if list is read-only.

Saying that it's bad design for that reason is like saying that it is also bad design because Insert(int, T) can throw ArgumentOutOfRangeException when index is negative or bigger than the size of collection.

躲猫猫 2024-10-03 21:40:26

这不是一个伟大的设计,但在我看来是一个必要的罪恶。

不幸的是,微软没有在框架中包含诸如 IReadableList<>IWriteableList<> 之类的东西,并且拥有 IList<> 本身实现这两个(或者甚至完全跳过IList<>并让IWriteableList<>实现IReadableList<>)。问题解决了。

但现在改变已经太晚了,如果您需要集合具有列表语义,并且您更愿意在运行时抛出异常而不是允许突变,那么 ReadOnlyCollection<> 是你最好的选择。

It's not a great design, but a necessary evil in my opinion.

It's unfortunate that Microsoft didn't include something like IReadableList<> and IWriteableList<> in the framework and have IList<> itself implement both of those (or even skip IList<> altogether and have IWriteableList<> implement IReadableList<>). Problem solved.

But it's too late to change now, and if you have a situation where you need your collection to have list semantics and you'd prefer to throw an exception at runtime rather than allow mutations, then ReadOnlyCollection<> is, unfortunately, your best option.

煮酒 2024-10-03 21:40:26

IList 有一些读取方法和属性,如 Item 和 IndexOf(..)。如果 ReadOnlyCollection 仅实现 IEnumerable 那么您就会错过这些。


还有什么替代方案吗?有 IList 的只读版本和写入版本吗?这会使整个 BCL 变得复杂(更不用说 LINQ)。


另外,我不认为它违反了里氏替换原则,因为它是在(IList)基础级别定义的,它可以抛出不支持的异常。

IList has some read method and properties like Item, and IndexOf(..). If ReadOnlyCollection would implement IEnumerable only then you would miss out on those.


Whats the alternative? Having a readonly version of IList and a write version? That would complicate the entire BCL (not to talk about LINQ).


Also I don't think it violates the Liskov Substitution Principle because it is defined at the base level (of IList) that it can throw a not supported exception.

时光暖心i 2024-10-03 21:40:26

我认为这是抽象和专业化之间权衡的一个很好的例子。

你想要IList的灵活性,但你也想施加一些约束,那么你该怎么办?它的设计方式有点尴尬,并且可能在技术上违反了一些设计原则,但我不确定什么会更好,并且仍然为您提供相同的功能和简单性。

在这种情况下,最好有一个单独的 IListReadOnly 接口。然而,很容易走上疯狂的一次性使用界面扩散之路,并使事情变得非常混乱。

I think it's a good example of a trade off between abstraction and specialization.

You want the flexibility of IList, but you also want to impose some constraints, so what do you do? The way it's designed is a little awkward, and probably technically violates some design principles, but I'm not sure what would be better and still give you the same functionality and simplicity.

In this case it may have been better to have a separate IListReadOnly interface. However, it is easy to go down the path to crazy one time use interface proliferation land and make things very confusing.

无妨# 2024-10-03 21:40:26

我想说这是一个糟糕的设计。即使人们接受具有功能查询的中等大接口的概念,也应该有从它们继承的其他接口,以保证允许某些行为。例如:

  1. IEnumerable(与现有的非常相似,但没有重置,并且不承诺如果在枚举期间更改集合会发生什么)
  2. IMul​​tipassEnumerable(添加重置,并保证更改集合的重复枚举将返回相同的数据或抛出异常)
  3. ICountableEnumerable(多遍枚举,加上“计数”属性,以及同时获取枚举器和计数的方法)
  4. IModabilEnumerable(一个 IEnumerator,如果在枚举期间由执行枚举的线程修改集合,则不会抛出异常。不会指定精确的行为,但在枚举期间未更改的项目必须恰好返回一次;在枚举期间修改的项目必须返回每次添加或修改最多返回一次,如果它们在枚举开始时存在,则加一。此接口本身不提供任何突变,但将与其他提供突变的接口一起使用。
  5. ICopyableAsEnumerable(包括一个 count 属性和一个返回 IEnumerable 的方法,该 IEnumerable 表示列表的快照;实际上不是 IEnumerable 本身,而是 IEnumerable 提供的有用功能)。
  6. IImmutable(无成员,但可继承以创建保证不可变的接口)
  7. 不可变可枚举
  8. IIImmutableCountableEnumerable
  9. IList(可以是可读的、读写的或不可变的)
  10. IImmutableList(没有新成员,但继承IImmutable)
  11. IWritableList(没有新成员,但保证可写)

这只是一个小样本,但应该传达设计理念。

I would say it's a bad design. Even if one accepts the concept of a moderately large interface with capability queries, there should have been other interfaces which inherited from them which would guarantee that certain behaviors be allowed. For example:

  1. IEnumerable (much like existing one, but without reset, and no promise of what will happen if the collection is changed during enumeration)
  2. IMultipassEnumerable (adds reset, and guarantees repeated enumerations of a changing collection will either return the same data or throw and exception)
  3. ICountableEnumerable (a multipass enumerable, plus a 'count' property, and a method to get an enumerator and count simultaneously)
  4. IModifiableEnumerable (an IEnumerator which will not throw if a collection is modified during enumeration by the thread doing the enumerating. The precise behavior would not be specified, but items which are unchanged during enumeration must be returned exactly once; those which are modified during enumeration must be returned at most once for each addition or modification, plus one if they existed at enumeration start. This interface itself does not provide any mutations, but would be used in conjunction with others that do).
  5. ICopyableAsEnumerable (includes a count property, and a method to return an IEnumerable which represents a snapshot of the list; not actually an IEnumerable itself, but a useful feature for an IEnumerable to provide).
  6. IImmutable (no members, but inheritable to create guaranteed-immutable interfaces)
  7. IImmutableEnumerable
  8. IImmutableCountableEnumerable
  9. IList (could be readable, read-write, or immutable)
  10. IImmutableList (no new members, but inherits IImmutable)
  11. IWritableList (no new members, but is guaranteed writable)

That's just a small sampling, but should convey the design idea.

无人接听 2024-10-03 21:40:26

在我看来,它的设计很糟糕。可能是由于向后兼容性问题,缺少协方差和逆变等。现在幸运的是,他们在 .NET 4.5 中解决了这个问题:

IReadOnlyList<out T>
IReadOnlyCollection<out T>
IReadOnlyDictionary<TKey, TValue>

但是我缺少带有“bool Contains(T)”的“只读”接口。

Its bad design IMO. Probably forced by backward compatibility issues, missing co-variance and contra-variance etc. etc. Now luckily they addressed it in .NET 4.5 with the:

IReadOnlyList<out T>
IReadOnlyCollection<out T>
IReadOnlyDictionary<TKey, TValue>

However I am missing "read-only" interface with "bool Contains(T)".

审判长 2024-10-03 21:40:26

我认为如果有一个糟糕的设计,那就是在不检查 ReadOnly 属性的情况下添加到 IList 的习惯。程序员忽略接口部分的习惯并不意味着接口很差。

事实上,我们程序员中很少有人会费心去阅读规范。说实话,对我来说,有很多事情比坐下来阅读整个规范文档更令人兴奋。 (例如,看看一个人是否真的可以用牙签睁开眼睛。)此外,我还有一个限制,那就是我无论如何都不会记住所有事情。

话虽如此,在不至少查看属性和方法列表的情况下,不应使用接口。您认为名为“ReadOnly”的布尔属性的用途是什么?也许是因为该列表只能出于某种原因而被读取。如果您要获取从您自己的代码之外的某个地方传递的列表,您应该在尝试添加列表之前检查该列表是否是只读的。

I think if there is a bad design going on it is a habit of adding to an IList without checking the ReadOnly property. The habit of programmers to ignore portions of an interface doesn't mean the interface is poor.

The truth is that few of us programmers ever bother to read the specifications. And truthfully there are many things that seem more exciting to me than sitting down and reading through the entire specification document. (Things like seeing if one really can hold the eyes open with toothpicks for example.) Besides, I have the limitation that I wouldn't remember everything anyway.

Having said that, one should not use an interface without at least looking at the list of properties and methods. And just what purpose do you think a boolean property named "ReadOnly" is for? Perhaps because the list can be read only for one reason or another. And if you are taking a list passed from someplace outside your own code you should check that the list is not read only before you try to add to it.

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