是否有可能获得 IEnumerator来自 T[]?
假设我想创建一个默认情况下线程安全的集合类。
在内部,该类有一个名为 Values
的受保护 List
属性。
对于初学者来说,让类实现 ICollection
是有意义的。该接口的一些成员非常容易实现;例如,Count
返回 this.Values.Count
。
但是实现 ICollection
需要我实现 IEnumerable
以及 IEnumerable
(非泛型),这有点棘手用于线程安全的集合。
当然,我总是可以在 IEnumerable
和 IEnumerable.GetEnumerator
上抛出 NotSupportedException
,但这感觉像是一种逃避大部头书。
我已经有一个线程安全的 getValues
函数,它锁定 Values
并以 T[]
数组的形式返回一个副本。所以我的想法是通过返回 this.getValues().GetEnumerator() 来实现 GetEnumerator ,以便以下代码实际上是线程安全的:
ThreadSafeCollection coll = new ThreadSafeCollection ();
// add some items to coll
foreach (T value in coll) {
// do something with value
}
不幸的是,这个实现似乎只是适用于 IEnumerable.GetEnumerator
,而不是通用版本(因此上面的代码会抛出 InvalidCastException
)。
我的一个想法似乎可行,就是在调用之前将 T[]
返回值从 getValues
转换为 IEnumerable
GetEnumerator
就可以了。另一种方法是更改 getValues
以首先返回 IEnumerable
,然后返回非泛型 IEnumerable.GetEnumerator
只需将返回值从 getValues
转换为非泛型 IEnumerable
即可。但我无法真正决定这些方法是否让人感到草率或完全可以接受。
无论如何,有人知道如何去做这件事吗?我听说过 .Synchronized 方法,但它们似乎仅适用于 System.Collections 命名空间中的非泛型集合。也许 .NET 中已经存在一个我根本不知道的通用变体?
Let's say I want to create a collection class that is thread-safe by default.
Internally, the class has a protected List<T>
property called Values
.
For starters, it makes sense to have the class implement ICollection<T>
. Some of this interface's members are quite easy to implement; for example, Count
returns this.Values.Count
.
But implementing ICollection<T>
requires me to implement IEnumerable<T>
as well as IEnumerable
(non-generic), which is a bit tricky for a thread-safe collection.
Of course, I could always throw a NotSupportedException
on IEnumerable<T>.GetEnumerator
and IEnumerable.GetEnumerator
, but that feels like a cop-out to me.
I already have a thread-safe getValues
function which locks on Values
and returns a copy in the form of a T[]
array. So my idea was to implement GetEnumerator
by returning this.getValues().GetEnumerator()
so that the following code would actually be thread-safe:
ThreadSafeCollection coll = new ThreadSafeCollection ();
// add some items to coll
foreach (T value in coll) {
// do something with value
}
Unfortunately this implementation only seems to work for IEnumerable.GetEnumerator
, not the generic version (and so the above code throws an InvalidCastException
).
One idea I had, which seemed to work, was to cast the T[]
return value from getValues
to an IEnumerable<T>
before calling GetEnumerator
on it. An alternative would be to change getValues
to return an IEnumerable<T>
in the first place, but then for the non-generic IEnumerable.GetEnumerator
simply cast the return value from getValues
to a non-generic IEnumerable
. But I can't really decide if these approaches feel sloppy or perfectly acceptable.
In any case, does anyone have a better idea of how to go about doing this? I have heard of the .Synchronized
methods, but they seem to only be available for non-generic collections in the System.Collections
namespace. Maybe there is a generic variant of this that already exists in .NET that I simply don't know about?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
大多数集合都指定您不能在迭代时向集合中添加或删除内容。因此,对于线程安全的集合,您希望在任何线程迭代时锁定其他线程,使其无法修改集合。使用迭代器语法应该很容易做到这一点,并且不需要您制作副本:
这假设可能修改集合的所有其他操作也锁定
this.Values
。只要这是真的,你应该没问题。Most collections specify that you cannot add or remove things from the collection while iterating. It follows that for a thread-safe collection, you want to lock out other threads from modifying the collection while any thread is iterating. This should be easy to do with the iterators syntax, and doesn't require you to make a copy:
This assumes that all of the other operations that might modify the collection also lock
this.Values
. As long as that's true, you should be fine.对我来说似乎很奇怪。您是否显式实现了非泛型 IEnumerable?即你是否写过
另外,你是否尝试过使用迭代器语法实现 IEnumerable 。这应该很简单:
如果您尝试过,为什么它不适合您的需求?
Seems strange for me. Have you implemented non-generic IEnumerable explicitly? I.e. have you written
Also, have you tried to implement IEnumerable with iterators syntax. It should be easy:
If you've tried, why doesn't it suits your needs?
类型
T[]
与其派生的类型System.Array
具有特殊关系。像T[]
这样的数组是在 .NET 中引入泛型之前创建的(否则语法可能是Array
)。System.Array
类型有一个 < code>GetEnumerator() 实例方法,public
。此方法返回非泛型IEnumerator
(自 .NET 1 起)。而且System.Array
没有显式的GetEnumerator()
接口实现。这解释了你的观察结果。但是,当 .NET 2.0 中引入泛型时,进行了一种特殊的“黑客”操作,让是一)。出于这个原因,我认为使用它是完全合理的:
T[]
实现IList
及其基本接口(其中< code>IEnumerable在我检查的 .NET 版本中,存在以下类:
The type
T[]
has a special realtionship to the typeSystem.Array
from which it derives. Arrays likeT[]
were made before generics were introduced in .NET (otherwise the syntax could have beenArray<T>
).The type
System.Array
has oneGetEnumerator()
instance method,public
. This method returns non-genericIEnumerator
(since .NET 1). AndSystem.Array
has no explicit interface implementations forGetEnumerator()
. This explains your observations.But when generics were introduced in .NET 2.0, a special "hack" was made to have a
T[]
implementIList<T>
and its base interfaces (of whichIEnumerable<T>
is one). For this reason I think it's perfectly reasonable to use:In the version of .NET where I'm checking this, the following classes exist: