比方说,我想创建一个集合类是线程安全的默认。

在内部,类有称为List<T>受保护Values属性。

对于初学者来说,是有意义的具有类实现ICollection<T>。一些该接口的成员是非常容易实现;例如,Count返回this.Values.Count

但是实现ICollection<T>要求我执行IEnumerable<T>以及IEnumerable(非通用),这是一个有点棘手的一个线程安全的集合。

当然,我总是可以扔在NotSupportedExceptionIEnumerable<T>.GetEnumerator一个IEnumerable.GetEnumerator,但感觉就像一种逃避我。

我已经有其上getValues并返回锁定一个拷贝在一个Values阵列形式的线程安全T[]功能。所以我的想法是通过返回GetEnumerator实现this.getValues().GetEnumerator()使下面的代码实际上是线程安全的:

ThreadSafeCollection coll = new ThreadSafeCollection ();

// add some items to coll

foreach (T value in coll) {
    // do something with value
}

不幸的是该实施方式中只似乎为IEnumerable.GetEnumerator,而不是通用版本工作(并且因此上述的代码引发InvalidCastException)。

我有一个想法,这似乎工作,是它调用之前T[]getValuesIEnumerable<T>返回值的GetEnumerator。另一种方法是,以改变getValues在首位返回IEnumerable<T>,但随后的非通用IEnumerable.GetEnumerator简单地将返回值从getValues到非通用IEnumerable。但我真的不能决定,如果这些方法觉得草率或完全可以接受的。

在任何情况下,任何人都不会有如何去这样做一个更好的主意吗?我听到的.Synchronized方法,但他们似乎只可在System.Collections命名空间非泛型集合。也许有这个已经存在于.NET泛型的变种,我根本不知道?

有帮助吗?

解决方案

大多数集合指定你不能同时迭代集合添加或删除的东西。由此可见,一个线程安全的集合,要从修改集合,而任何线程迭代锁定其他线程。这应该是很容易与迭代器的语法做了,不需要你做一个副本:

public IEnumerator<T> GetEnumerator()
{
    lock (this.Values) // or an internal mutex you use for synchronization
    {
        foreach (T val in this.Values)
        {
            yield return val;
        }
    }
    yield break;
}

这假定所有可能还会修改集合的其他操作锁定this.Values。只要这是真的,你应该罚款。

其他提示

  

不幸的是该实施方式中只似乎为IEnumerable.GetEnumerator,而不是通用版本工作(因此上面的代码引发InvalidCastException)。

似乎很奇怪我。你有没有实现的非通用IEnumerable的明确?即你写过

public IEnumerator<T> GetEnumerator() { ...}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator<T>(); }

此外,你有没有试着用迭代器的语法来实现IEnumerable。应该很容易:

public IEnumerator<T> GetEnumerator()
{
    T[] values;
    lock(this.Values)
        values = this.Values.ToArray();
    foreach(var value in values)
        yield return value;
}

如果您已经试过,为什么没有适合您的需求?

在型T[]具有特殊realtionship到它导出类型System.Array。之前在.NET(否则语法可能是T[])引入泛型像Array<T>阵列被做了。

在型System.Array具有一个 GetEnumerator() 实例方法,public。此方法返回非通用IEnumerator(因为.NET 1)。而System.ArrayGetEnumerator()没有明确的接口实现。这说明你的看法。

但是,当在泛型.NET 2.0进行了介绍,一个特殊的“黑客”被制成具有T[]实施IList<T>及其基接口(其中IEnumerable<T>是其中之一)。为此,我认为这是完全合理的使用:

((IList<T>)(this.getValues())).GetEnumerator()

在.NET其中我检查此的版本,以下类存在:

namespace System
{
  public abstract class Array
  {
    private sealed class SZArrayEnumerator  // instance of this is returned with standard GetEnumerator() on a T[]
    {
    }
  }

  internal sealed class SZArrayHelper
  {
    private sealed class SZGenericArrayEnumerator<T>  // instance of this is returned with generic GetEnumerator() on a T[] which has been cast to IList<T>
    {
    }
  }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top