假设我有一个方法
foo
,它返回一个ValueTuple
,其中一个成员是一次性的,例如(IDisposable, int)
。
确保返回的一次性对象在调用方正确处置的最佳方法是什么?
我尝试了以下方法:
using (var (disposable, number) = foo())
{
// do some stuff using disposable and number
}
但这不会编译:
'(IDisposabledisposable, int number)':using 语句中使用的类型必须隐式转换为 'System.IDisposable'
我真的需要将代码包装在 try-finally 块中并在 finally 块中显式处置我的对象吗?还是有更好的方法来做到这一点?
实际上我希望看到新的 ValueTuples 实现
IDisposable
接口并在其所有一次性成员上调用 Dispose()
。对于 Microsoft 来说,这是一个值得的功能请求吗?
只需将方法调用移到
using
语句之外,然后只需 use 一次性对象:
var (disposable, number) = foo();
using (disposable)
{
// do some stuff using disposable and number
}
您的版本不起作用的原因很简单,因为无论
using
括号内的表达式结果如何,都需要是一次性的,但值元组本身不是一次性的。所以你只需要把它分开。幸运的是,不需要使用 using
语句来构造该表达式中的对象,您只需将任何现有对象传递给它即可。
实际上我希望看到新的 ValueTuples 实现
接口并在其所有一次性成员上调用IDisposable
。对于 Microsoft 来说,这是一个值得的功能请求吗?Dispose()
按照这个逻辑,所有集合都必须这样做。例如,处置列表应处置其所有成员,处置字典应处置其所有值(和键?!?!)。当您有一个仅使用简单列表的类型时,该对象也需要是一次性的。
所以基本上,你最终会传播它并最终得到很多突然被丢弃的物体,尽管它们实际上没有任何需要它的实际资源。
使物品成为一次性物品不应该轻易进行。通常,创建一次性对象的对象稍后负责正确处置该对象,它们“拥有”该对象的生命周期。但对于收藏来说,情况往往并非如此。集合通常就是这样:保存对象的集合,但这并没有说明它们是否由集合“拥有”——大多数情况下,它们由同时创建集合的对象拥有,因此然后,对象应该在某个时候通过简单地循环访问集合来处理对象。
var (disposable, number) = foo();
using (disposable)
{
// do some stuff using disposable and number
}
建议添加另一对括号来结束范围。
{
var (disposable, number) = foo();
using (disposable)
{
// do some stuff using disposable and number
}
}
如果
foo
IDisposable
接口的对象。
实现其Dispose
方法以委托给其所有一次性成员
例如:
public class Result : IDisposable
{
public int Number { get; set; }
public HttpClient HttpClient { get; set; }
public HttpContent HttpContent{ get; set; }
public void Dispose()
{
try
{
HttpClient?.Dispose();
}
catch
{
// in case there is more than one disposable member
}
try
{
HttpContent?.Dispose();
}
catch
{
// in case there is more than one disposable member
}
}
}
并像这样使用它:
public static void Main(string[] args)
{
using Result result = Foo();
Console.WriteLine(result.HttpClient?.ToString());
Console.WriteLine(result.HttpContent?.ToString());
// it will now dispose result and all the internal IDisposable members
}
public static Result Foo()
{
return new Result();
}
如果其中一个
Dispose
调用引发异常,则行为可能会有所不同,在这种情况下您将看不到它,因此如果只有一个 Disposable 成员,您可以在没有
try-catch
块的情况下委托给其 Dispose .