在 Linq 中处置 IDisposable
(这是对 这个问题)
在我发布该问题 18 个月后,有人在 我的 Linq 示例之一,其中我在方法链的中间使用了 IDisposable,它永远不会被释放。
我尝试编写一个扩展方法来处理此问题:
public static IEnumerable<R> Using<T, R>(
this IEnumerable<T> list, Func<T, R> selector) where R : IDisposable
{
foreach(var item in list)
using(var disposable = selector(item))
yield return disposable;
}
var q = Enumerable.Range(0, 10)
.Using(i => new Disposable(i))
.Select(d => d.Id);
看到 Marc 对我上面提到的问题的回答,我想知道是否可以直接重载 Select 扩展方法,但如果我这样做(通过将 Using
重命名为Select
),编译器会对 Select(d => d.Id)
发出尖叫声,因为没有从 'string' 到 'System.IDisposable 的隐式转换'
。
这是一个测试课...
public class Disposable : IDisposable
{
private string _id;
private bool _disposed = false;
public Disposable(int id)
{
Id = id.ToString();
Console.WriteLine("Creating " + Id);
}
public void Dispose()
{
Console.WriteLine("Disposing " + Id);
_disposed = true;
}
public string Id
{
get
{
if(_disposed) throw new Exception("Call to disposed object!");
return _id;
}
set { _id = value; }
}
}
(This is a follow on from a comment on an answer to this question)
18 months after I posted it, someone spotted a bug in one of my Linq examples, where I use an IDisposable half way through a method chain, which never gets disposed.
I attempted to write an extension method to handle this:
public static IEnumerable<R> Using<T, R>(
this IEnumerable<T> list, Func<T, R> selector) where R : IDisposable
{
foreach(var item in list)
using(var disposable = selector(item))
yield return disposable;
}
var q = Enumerable.Range(0, 10)
.Using(i => new Disposable(i))
.Select(d => d.Id);
After seeing Marc's answer to the question I referenced above, I wondered if I could overload the Select extension method directly, but if I do (by renaming Using
to Select
), the compiler squeals about Select(d => d.Id)
, because There is no implicit conversion from 'string' to 'System.IDisposable'
.
Here's a test class...
public class Disposable : IDisposable
{
private string _id;
private bool _disposed = false;
public Disposable(int id)
{
Id = id.ToString();
Console.WriteLine("Creating " + Id);
}
public void Dispose()
{
Console.WriteLine("Disposing " + Id);
_disposed = true;
}
public string Id
{
get
{
if(_disposed) throw new Exception("Call to disposed object!");
return _id;
}
set { _id = value; }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
像这样吗?除了构造函数的使用之外,我在这里并没有真正改变太多......
但是!这里需要注意的是,我们没有引入任何冲突的 LINQ 操作。
Like so? I haven't really changed much here, except the constructor usage...
However! The thing to watch here is that we don't introduce any conflicting LINQ operations.