2016-03-07 37 views
3

我有以下问题:明确的IEnumerator <T>执行VS产量的回报实现

我想实现我自己的收藏,这也将实现ICollection<T>接口。这意味着我还需要实现IEnumerable<T>接口。通过使私人结构实现IEnumerator<T>GetEnumerator()方法返回它

第二条本办法:实施IEnumerable<T>可以通过两种方式:

第一种方法我可以只使用迭代器(使用yield return),并让编译器为我生成IEnumerator班。

我也希望我的统计员任何MoveNext()(或Reset())调用抛出InvalidOperationException的集合被修改 as it is specified in MS documentation

后,如果我将使用第一种方法,那么一切都OK(我只是保存的版本我创建新的枚举器时的集合,然后在MoveNext()我只是检查它是否没有改变)。 MS Collections使用相同的技巧但这里是问题 - 如果我将使用第二种方法我想我不能执行以下行为。考虑下面的代码。

class MyCollection : ICollcetion<T> 
{ 
int _version = 0; 
T[] _collectionData; 
public void Modify() 
    { 
    ... // do the modification 
    _version++; // change version, so enumerators can check that they are invalid 
    } 

... 

public IEnumerator<T> GetEnumerator() 
    { 
    int _enmVersion = _version; 
    int i = 0; 
    yield return _collectionData[i]; 
    if(_enmVersion != _version) // check if there was not modificaction 
    { 
     throw new InvalidOperationException(); 
    } 
    } 

... 

} 

... 

var collection = new MyCollection(); 
var e = collection.GetEnumerator(); 
myCollection.Modfiy(); //collection modification, so e becomes irrecoverably invalidated 
e.MoveNext(); // right now I want to throw exception 
       //but instead of that, code until first yield return executed 
       //and the version is saved... :(

只有在集合obataining枚举对象修改后,会出现此问题,但之前,首先调用MoveNext(),但它仍然是问题...

我的问题是:是否有可能以某种方式使用第二种方法并强制执行正确的行为或我需要为这种情况下坚持第一种方法

我怀疑的是,我必须使用第一种方法,因为迭代方法的代码仅exeuted当我打电话MoveNext(),而不是在编译器生成的类的构造函数,但我想是的......

回答

1

你的问题是迭代器方法将不会运行任何代码,直到第一个MoveNext()调用。

可以解决此问题通过环绕立即抓住版本,并将其作为一个参数的非迭代方法,迭代器:

public IEnumerator<T> GetEnumerator() { 
    return GetRealEnumerator(_version); 
} 

private IEnumerator<T> GetRealEnumerator(int baseVersion) { 
+0

非常感谢你,它的工作。我认为迭代器方法签名需要被编译器注意到GetEnumerator()。 – videokojot

+0

否;任何方法都可以是迭代器。迭代器也可以返回'IEnumerable '。 – SLaks