假设我想创建一个产生IDisposable
项的迭代器函数。
IEnumerable<Disposable> GetItems()
{
yield return new Disposable();
yield return new Disposable();
}
这似乎不适合客户端代码:
foreach (var item in source.GetItems())
{
using (item)
{
// ...
}
}
直观地说,using
为时已晚。事情可能会被转移。有人可能会意外地在<{em> foreach
和using
之间插入代码。不理想。
我正在寻找更好的选择!
我想到的一种方法是创建以下API而不是迭代器函数:
// Client
while (source.HasItem)
{
using (var item = source.GetNextItem())
{
// ...
}
}
// Source
private IEnumerator<Disposable> Enumerator { get; }
private bool? _hasItem;
bool HasItem
{
get
{
if (this._hasItem == null) this._hasItem = this.Enumerator.MoveNext();
return this._hasItem;
}
}
Disposable GetNextItem()
{
if (!this.HasItem) throw new IndexOutOfBoundsException();
this._hasItem = null;
return this.Enumerator.Current;
}
但现在看来源必须成为IDisposable
!怎么会知道何时处置Enumerator
?这可能是一种令人不快的副作用。
我正在寻找一种在客户端感觉稳固的替代方案,但这也使源不会变为IDisposable
。
编辑 - 澄清:我忘了提到我们需要的一些内容来自迭代器。具体来说,假设我们正在返回IDbCommand
个实例,IDisposable
。在返回每个命令之前,我们需要使用一些查询数据填充它,而查询数据又来自一个简单的迭代器方法。
答案 0 :(得分:4)
如果我理解正确,以下模式适合您
foreach (var item in source.GetItems())
{
using (item)
{
// ...
}
}
但潜在的问题是将一些代码放在using
块之外。那你为什么不把这个逻辑包装在自定义扩展方法中呢?
public static class EnumerableExtennisons
{
public static IEnumerable<T> WithUsing<T>(this IEnumerable<T> source)
where T : IDisposable
{
foreach (var item in source)
{
using (item)
yield return item;
}
}
}
通过这种方式,您可以确保将项目包装在using
块*中,然后再将其返回给调用者,因此调用者无法在其之前/之后插入代码。 C#编译器生成的代码确保在item.Dispose
的{{1}}或MoveNext
方法中调用Dispose
(如果迭代结束时更早)。
用法是在需要时附加IEnumerator<T>
来代替.WithUsing()
阻止:
using
答案 1 :(得分:1)
我们只能 @register.simple_tag
def localdate():
lang = translation.get_language()
fmt = DATE_FORMATS.get(lang, DATE_FORMATS[DEFAULT_LANG])
now = datetime.now()
return datefilter(now, fmt)
,只支持IEnumerator<T>
和MoveNext()
。
现在,底层的私有迭代器函数可以是流式传输,负责处理项目。不会向客户端引入无效操作 - 除非他们尝试存储借用的对象并稍后尝试使用它们,否则很明显已经处理了这些对象。
Current
答案 2 :(得分:-1)
迭代器函数本身可以负责放置使用(即在请求下一个时处理当前项目)。
IEnumerable<Disposable> GetItems()
{
// Assumming CreateItems() is an iterator as well
foreach (var item in this.CreateItems())
using (item) yield return item;
}
因此,我们将基本上拥有一个仅限流的迭代器。像ToList()
这样的方法变得毫无意义,因为一次只能使用一个项目。
不幸的是,这确实会产生错误的空间。