如果我自己实现IEnumerator接口,那么我能够(内部foreach语句)在albumsList不产生异常的情况下添加或删除项目.但是如果foreach语句使用了IEnumerator提供的albumsList,那么尝试添加/删除(在foreach内部)项目albumsList将来自导致异常:
class Program
{
static void Main(string[] args)
{
string[] rockAlbums = { "rock", "roll", "rain dogs" };
ArrayList albumsList = new ArrayList(rockAlbums);
AlbumsCollection ac = new AlbumsCollection(albumsList);
foreach (string item in ac)
{
Console.WriteLine(item);
albumsList.Remove(item); //works
}
foreach (string item in albumsList)
{
albumsList.Remove(item); //exception
}
}
class MyEnumerator : IEnumerator
{
ArrayList table;
int _current = -1;
public Object Current
{
get
{
return table[_current];
}
}
public bool MoveNext()
{
if (_current + 1 < table.Count)
{
_current++;
return true;
}
else
return false;
}
public void Reset()
{
_current = -1;
}
public MyEnumerator(ArrayList albums)
{
this.table = albums;
}
}
class AlbumsCollection : IEnumerable
{
public ArrayList albums;
public IEnumerator GetEnumerator()
{
return new MyEnumerator(this.albums);
}
public AlbumsCollection(ArrayList albums)
{
this.albums = albums;
}
}
}
Run Code Online (Sandbox Code Playgroud)
a)我假设抛出异常的代码(当使用提供的IEnumerator实现时)位于里面?AalbumsListA
b)如果我想能够从集合中添加/删除项目(当foreach迭代它时),我是否总是需要提供我自己的IEnumerator接口实现,或者可以将albumsList设置为允许添加/删除项目?
谢谢
Ste*_*per 15
最简单的方法是反转项目for(int i = items.Count-1; i >=0; i--),或者循环一次,收集要在列表中删除的所有项目,然后循环删除项目,将其从原始列表中删除.
Dan*_*Tao 13
通常不鼓励设计允许您在枚举时修改集合的集合类,除非您打算专门设计一些线程安全的东西以便这样做(例如,从一个线程添加而从另一个线程枚举).
原因无数.这是一个.
您的MyEnumerator课程通过递增内部计数器来工作.它的Current属性暴露了给定索引的值ArrayList.这意味着枚举集合并删除"每个"项目实际上将无法按预期工作(即,它不会删除列表中的每个项目).
考虑这种可能性:
您发布的代码实际上会执行此操作:
Current"摇滚".你删除"摇滚".["roll", "rain dogs"],你增加你的指数为1,使得Current等于"太阳雨"(而不是"卷") .接下来,你删除"雨狗".["roll"],你将索引增加到2(这是> Count); 所以你的普查员认为它已经完成了.不过,还有其他原因,这是一个有问题的实现.例如,使用你的代码的人可能不理解你的枚举器是如何工作的(他们也不应该 - 实现应该无关紧要),因此没有意识到Remove在一个foreach块内调用的成本会受到惩罚IndexOf- 即线性搜索- 每次迭代(请参阅MSDN文档ArrayList.Remove以验证这一点).
基本上,我得到的是:你不希望能够从一个foreach循环内删除项目(再次,除非你设计一些线程安全的东西...... 也许).
好的,那么替代方案是什么?以下几点可以帮助您入门:
Clear(删除所有项目)或RemoveAll(删除与指定过滤器匹配的项目)等方法.ArrayList已经有了一个Clear方法,就像你在.NET中可能使用的大多数集合类一样.否则,如果您的内部集合已编制索引,则删除多个项目的常用方法是使用for循环从顶部索引枚举并调用RemoveAt需要删除的索引(注意这会立即修复两个问题:从顶部向后退,您确保访问集合中的每个项目;此外,通过使用RemoveAt而不是Remove,您可以避免重复线性搜索的惩罚).ArrayList尽量避免使用非通用集合.与强类型的通用对应物List(Of Album)相反(假设你有一个Album类 - 否则,List(Of String)它仍然比类型更安全ArrayList).| 归档时间: |
|
| 查看次数: |
15461 次 |
| 最近记录: |