问题标签 [readonly-collection]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c# - 不变性/只读语义(特别是 C# IReadOnlyCollection)
我怀疑我对System.Collection.Generic.IReadOnlyCollection<T>
语义的理解,也怀疑如何使用只读和不可变等概念进行设计。让我通过使用文档来描述我怀疑的两种性质,其中指出
表示强类型的只读元素集合。
根据我是强调“代表”还是“只读”(在我脑海中发音时,或者如果那是你的风格的话),我觉得这句话改变了意思:
- 当我强调“只读”时,我认为文档定义了观察不变性(Eric Lippert 的文章中使用的术语),这意味着只要没有公开可见的突变†,接口的实现就可以随心所欲地执行。
- 当我强调“代表”时,文档定义(在我看来,再次)一个不可变的外观(再次在 Eric Lippert 的文章中描述),这是一种较弱的形式,其中可能发生突变,但不能由用户进行。例如,类型属性
IReadOnlyCollection<T>
向用户(即针对声明类型进行编码的人)明确表示他不能修改此集合。但是,声明类型本身是否可以修改集合是模棱两可的。 - 为了完整起见:接口除了其成员签名所携带的语义外,不携带任何语义。在这种情况下,观察或外观不变性是依赖于实现的(不仅依赖于接口的实现,还依赖于实例)。
第一个选项实际上是我更喜欢的解释,尽管这个契约很容易被打破,例如通过ReadOnlyCollection<T>
从 's 的数组构造 aT
然后将值设置到包装器数组中。
BCL 具有出色的外观不变性接口,例如IReadOnlyCollection<T>
,IReadOnlyList<T>
甚至可能IEnumerable<T>
等。但是,我发现观察不变性也很有用,据我所知,BCL 中没有任何接口具有此含义(请指出它们如果我错了对我来说)。这些不存在是有道理的,因为这种形式的不变性不能由接口声明强制执行,只能由实现者强制执行(接口可以携带语义,如下所示)。旁白:我希望在未来的 C# 版本中拥有这种能力!
示例:(可能被跳过)我经常必须实现一个方法,该方法将另一个线程也使用的集合作为参数,但该方法要求集合在执行期间不被修改,因此我将参数声明为类型IReadOnlyCollection<T>
拍拍自己的后背,认为我已经达到了要求。错误......对于调用者来说,签名看起来好像方法承诺不会更改集合,没有别的,如果调用者对文档(外观)进行第二种解释,他可能只是认为允许突变并且方法在问题是抗拒的。尽管此示例还有其他更常规的解决方案,但我希望您看到这个问题可能是一个实际问题,特别是当其他人使用您的代码时(或未来的您)。
所以现在我的实际问题(这引发了对现有接口语义的怀疑):
我想使用观察不变性和外观不变性并区分它们。我想到的两个选择是:
- 每次使用 BCL 接口并记录它是观察性的还是只是外观不变性。缺点:使用此类代码的用户只会在为时已晚(即发现错误时)查阅文档。我要带领他们进入成功的深渊;文档不能这样做)。此外,我发现这种语义足够重要,可以在类型系统中看到,而不仅仅是在文档中。
- 定义明确携带观察不变性语义的接口,例如
IImmutableCollection<T> : IReadOnlyCollection<T> { }
和IImmutableList<T> : IReadOnlyList<T> { }
。请注意,除了继承的接口之外,接口没有任何成员。这些接口的目的只是说“即使声明类型也不会改变我!”‡我在这里特别说“不会”而不是“不能”。这里有一个缺点:一个邪恶的(或错误的,为了保持礼貌)实现者不会被编译器或其他任何东西阻止破坏这个合同。然而,优点是选择实现这个接口而不是它直接继承的接口的程序员很可能知道这个接口发送的额外消息,因为程序员知道这个接口的存在,
我正在考虑使用第二个选项,但恐怕它的设计问题与委托类型的设计问题相当(这些委托类型是为了在无语义的对应物上携带语义信息而发明的Func
)Action
并且不知何故失败了,请参见此处。
我想知道您是否也遇到过/讨论过这个问题,或者我是否只是对语义的争论太多,应该只接受现有的接口,以及我是否只是不知道 BCL 中的现有解决方案。任何像上面提到的设计问题都会有所帮助。但我对您可能(已经)针对我的问题提出的其他解决方案特别感兴趣(简而言之,在声明和使用中区分观察和外观不变性)。
先感谢您。
†我忽略了集合元素上的字段等的突变。
‡ 这对于我之前给出的示例是有效的,但该陈述实际上更广泛。例如,任何声明方法都不会改变它,或者这种类型的参数表明该方法可以期望集合在其执行期间不会改变(这与说该方法不能改变集合不同,这是唯一的声明一个可以使用现有接口),可能还有许多其他接口。
c# - 来自 IReadOnlyList 的 Encoding.GetString
IReadOnlyList<byte>
给定一个特定的,有没有办法从一个字符串中取出一个字符串Encoding
?
更准确地说,有没有办法在将集合的内容传递给 Encoding 对象之前不复制它?
我主要关心的是性能,其次是内存使用。
c# - 未找到检索到的字典键
我有一个SortedDictionary
这样的声明:
当它填充了值时,如果我从字典中获取任何键,然后尝试立即引用它,我会得到KeyNotFoundException
:
当我使用调试器将鼠标悬停在字典上(出现错误后)时,我可以清楚地看到我试图引用的相同键实际上包含在字典中。我正在使用ReadOnlyCollection
of填充字典MyObjects
。也许那里正在发生一些奇怪的事情?我尝试覆盖==
运算符和Equals
方法来获得我想要的显式比较,但没有这样的运气。这真的不重要,因为我实际上是直接从Dictionary
然后查询Dictionary
使用相同的密钥获取密钥。我无法弄清楚是什么原因造成的。有没有人见过这种行为?
编辑 1
在重写Equals
时,我也重载了(如 MS 建议GetHashCode
的那样)。这是MyObject
任何有兴趣的人的实现:
我从调试中注意到的是,如果我KeyNotFoundException
为表达式添加一个快速监视(在抛出之后):
它返回真。怎么会这样?
编辑 2
所以问题最终是因为SortedDictionary
(Dictionary
以及)不是线程安全的。有一个后台线程正在对字典执行一些操作,这似乎触发了集合的使用(将项目添加到集合中会这样做)。同时,当字典遍历值以找到我的键时,集合正在更改,即使它在那里也找不到我的键。
对于所有要求提供此代码的人,我很抱歉,我目前正在调试我继承的应用程序,但我没有意识到这是在定时后台线程上进行的。因此,我以为我复制并粘贴了所有相关代码,但我没有意识到在操纵集合的所有内容背后还有另一个线程在运行。
c# - 添加到构造函数中的只读集合?
是否有 ac# 语言构造允许我将项目添加到构造函数中的只读集合属性?我想做这样的事情:
...在我的代码某处...
(不是一个很好的例子,但我希望这能让你明白)......
更新
好的,对不起,我需要更清楚。我没有写这Node
门课,我不能改变它。我在问是否有 ac# 语言概念允许我添加到第二个片段的无参数构造函数中的只读集合中,假设Node
类不可更改。
c# - 如何连接 ReadOnlyCollection
ReadOnlyCollection 构造函数要求您为其提供 IList。但是,如果您有一些 ROC 想要连接并生成一个新的 ROC,Concat 方法将返回 IEnumerable。这不是传递给 ROC 构造函数的有效参数。
那么如何创建一个 ROC 作为其他 ROC 的串联呢?
到目前为止,这是我能想到的最好的:
c# - 如何序列化从 ReadOnlyCollection 派生的类
当我尝试序列化我自己的从 ReadOnlyCollection 派生的类时,出现错误:
具有 CollectionDataContractAttribute 属性的类型 'MyReadOnlyCollection`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' 是无效的集合类型,因为它没有默认构造函数。
现在错误是有道理的,确实我没有默认构造函数。但是,即使 ReadOnlyCollection 没有无参数的默认构造函数,我也可以使用 DataContractSerializer 序列化 ReadOnlyCollection。
两个问题:
- 为什么我可以序列化 ReadOnlyCollection 而不是我的派生类?
- 我应该如何正确序列化我的派生类?
更新: 我在上面添加了我的派生类
c# - Best way to expose ReadOnlyCollection of ReadOnlyCollection while still being able to modify it inside class
I don't know if this is possible, but basically, I want to expose a property of type ReadOnlyCollection<ReadOnlyCollection<MyType>>
, while still being able to modify the underlying collection inside the class exposing the property. Further, I want users of my class to be able to hold a reference to the collection returned, so that it updates as I update it internally in the class exposing the property.
For instance, If this were a single collection, I could do something like this:
Which would still allow for adding items to the list inside my class by doing _List.Add()
. Further, if a client of this class was to do, say:
Then collectionRef
would also change as I add elements to the list from inside MyClass
.
The problem arises if I want a list of lists:
The immediate problem with the above attempt is that AsReadonly()
only applies to the outer list. So I'd be trying to return a ReadOnlyCollection<List<MyItem>>
which is not the declared type for the property. The only way I can think of to satisfy the declared property type would involve creating a new ReadOnlyCollection
in a way similar to:
or
But I'm not sure what the syntax for creating this nested collection would be; Also, I'm not sure if by creating 'new' collections, I won't be able to track changes to the underlying lists by means of a ref to the value returned by the property. That is, if inside MyClass
I do _List[1].Add(myTypeInstance)
I'm not sure that someone holding a ref to the readonly version will see that new item.
I'm open to other approaches all together honesty. Basically I just need to expose a list of lists of items which is readonly but can be modified inside the class that exposes the property and for clients to be able to see the changes reflected without needing to get the value again from the property accessor.
c# - 在几个构造函数中重复的只读属性集代码
我有一个DataStructure
类,我希望它是不可变的。
通常,我只是确保我的所有成员都被定义为readonly
- 工作完成。但是其中一个成员是一个列表(整数),所以我需要确保List
不能修改;所以我将其更改为ReadOnlyCollection<T>
. 美好的。
我还需要以某种方式对该集合进行排序 - 再次很好,我在通过.AsReadOnly()
.
到目前为止,一切都很好。
但最后一步是我想要 3 个不同的构造函数——每个构造函数都接受不同格式的原始数据。现在我必须在每个构造函数中复制将列表转换为必要格式的代码。
如果我将它共同化为一个setList()
方法,那么变量不能是readonly
,因为它是在非构造方法中分配的。现在我失去了一些不变性。
理想情况下,我可以通过某种方式声明该setList
方法只能从构造函数调用,因此允许编辑readonly
成员,但我认为不存在。
我可以在吸气剂等中创建包装所有内容,以便该类从外部是不可变的,但我更希望它从内部也是不可变的(特别是考虑到我可以实现这一点,我牺牲了 DRYness)
有没有人对我忘记的语言功能有任何聪明的想法可以解决这个问题?
c# - 如何创建一个空的 IReadOnlyCollection
我正在为MultiValueDictionary创建一个扩展方法来封装频繁ContainsKey
检查,我想知道创建空的最佳方法是什么IReadOnlyCollection
?
到目前为止我使用的是new List<TValue>(0).AsReadOnly()
,但必须有更好的方法,相当于IEnumerable
'sEnumerable.Empty
c# - 为什么 ReadOnlyCollection 不允许协方差?
此代码有效的原因是Enumerator
无法修改集合:
如果我们尝试用 aList<object>
而不是做同样的事情IEnumerable<object>
,我们会得到一个编译器错误,告诉我们我们不能将 type 隐式转换List<string>
为List<object>
。好吧,这是有道理的,在我看来,这是微软的一个很好的决定,作为从数组中吸取的教训。
但是,我不明白为什么这个强硬规则适用于类似的东西ReadOnlyCollection
?我们将无法修改 中的元素ReadOnlyCollection
,那么导致 Microsoft 阻止我们对只读内容使用协方差的安全问题是什么?有没有一种可能的方法来修改微软试图解释的那种类型的集合,比如通过指针?