具有一次性成员的 C# ValueTuple

问题描述 投票:0回答:3

假设我有一个方法

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 来说,这是一个值得的功能请求吗?

c# using idisposable valuetuple
3个回答
22
投票

只需将方法调用移到

using
语句之外,然后只需 use 一次性对象:

var (disposable, number) = foo();
using (disposable)
{
    // do some stuff using disposable and number
}

您的版本不起作用的原因很简单,因为无论

using
括号内的表达式结果如何,都需要是一次性的,但值元组本身不是一次性的。所以你只需要把它分开。幸运的是,不需要使用
using
语句来构造该表达式中的对象,您只需将任何现有对象传递给它即可。


实际上我希望看到新的 ValueTuples 实现

IDisposable
接口并在其所有一次性成员上调用
Dispose()
。对于 Microsoft 来说,这是一个值得的功能请求吗?

按照这个逻辑,所有集合都必须这样做。例如,处置列表应处置其所有成员,处置字典应处置其所有值(和键?!?!)。当您有一个仅使用简单列表的类型时,该对象也需要是一次性的。

所以基本上,你最终会传播它并最终得到很多突然被丢弃的物体,尽管它们实际上没有任何需要它的实际资源。

使物品成为一次性物品不应该轻易进行。通常,创建一次性对象的对象稍后负责正确处置该对象,它们“拥有”该对象的生命周期。但对于收藏来说,情况往往并非如此。集合通常就是这样:保存对象的集合,但这并没有说明它们是否由集合“拥有”——大多数情况下,它们由同时创建集合的对象拥有,因此然后,对象应该在某个时候通过简单地循环访问集合来处理对象。 var (disposable, number) = foo(); using (disposable) { // do some stuff using disposable and number }


1
投票
建议添加另一对括号来结束范围。

{ var (disposable, number) = foo(); using (disposable) { // do some stuff using disposable and number } }

如果 
foo

0
投票
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 .

    

© www.soinside.com 2019 - 2024. All rights reserved.