简体   繁体   English

避免在C#中使用`using`关键字进行多次处置的最佳实践

[英]Best practice to avoid multiple disposals with the `using` keyword in C#

When a variable is IDisposable, we have the using keyword to manage the disposal. 当变量是IDisposable时,我们有using关键字来管理处置。 But what if we return the value in a method, should we have using twice? 但是,如果我们在方法中返回值,应该using两次吗?

StringContent stringToStringContent(string str)
{
    using (StringContent content = new StringContent(str))
    {
        return content;
    }
}

void logStringContent()
{
    using (StringContent content = stringToStringContent("test"))
    {
        Debug.WriteLine(content.ToString());
        return;
    }
}

In this example above, I only have 1 new but I have 2 using for the same thing. 在上面这个例子中,我只有1个new ,但我有2个using了同样的事情。 So I feel it's unbalanced. 所以我觉得这很不平衡。 Is it better to: 更好:

a) keep both using , and the language/compiler knows its job to avoid double-disposal? a)同时using ,并且语言/编译器知道其工作以避免双重处理?

b) keep only using with new together, and no need in other cases?: b)只能与new一起using ,而在其他情况下不需要吗?

void logStringContent()
{
    StringContent content = stringToStringContent("test");
    Debug.WriteLine(content.ToString());
    return;
}

c) keep only using when you don't return, and no need when you return?: c)仅在不返回时才using ,而在返回时则不需要?

StringContent stringToStringContent(string str)
{
    return new StringContent(str);
}

The only thing I can feel is that b) isn't the correct answer, because it wouldn't work for issues like the one described here: .NET HttpClient hangs after several requests (unless Fiddler is active) 我唯一能感觉到的是b)不是正确的答案,因为它不适用于此处所述的问题: .NET HttpClient在多个请求后挂起(除非Fiddler处于活动状态)

I think c is the right answer here - you're returning (a reference to) an object from the method - it makes no sense to have already disposed of that object before you return it. 我认为这里的c是正确的答案-您正在从方法中返回一个对象(对它的引用)-在返回该对象之前已经处置掉该对象没有任何意义。 For example, File.OpenRead wouldn't dispose of the stream that it returns, would it? 例如, File.OpenRead不会处理它返回的流,不是吗?

It would be a good idea to indicate in the method documentation that the caller takes responsibility for disposing of the object though. 最好在方法文档中指出调用者负责处置对象。 Likewise, some methods accept a disposable type and state that the caller then shouldn't dispose of the object themselves. 同样,某些方法接受可抛弃的类型,并声明调用者则不应自己处置该对象。 In both case there's effectively a transfer of responsibility for disposing of the object properly. 在这两种情况下,实际上都有责任转移,以正确处置该物体。

Having methods that return IDisposable objects is not an uncommon pattern, but preventing resource leaks when exceptions occur can be difficult. 拥有返回IDisposable对象的方法并不是很常见的模式,但是在发生异常时防止资源泄漏可能很困难。 An alternative approach is to have a method which will produce a new IDisposable accept an out or (if the method is unsealed and virtual) ref parameter, and store a reference to the new object in that. 一种替代方法是拥有一个将产生新的IDisposable的方法,该方法接受out或(如果该方法是未密封和虚拟的) ref参数,并在其中存储对新对象的引用。 The caller would then be expected to Dispose the thing in question, whether the method that produced it returned normally or threw an exception. 然后,将要求调用者Dispose有问题的事物,无论产生该事物的方法是正常返回还是引发异常。

Otherwise, if you want your method's return value to be a new IDisposable , and if any code will execute between the time your method acquires a resource and the time it returns, you should guard your code with something like: 否则,如果您希望方法的返回值是一个新的IDisposable ,并且如果在方法获取资源的时间与返回时间之间将执行任何代码,则应使用以下方法来保护代码:

DisposableThing thingToDispose = null;
try
{
    thingToDispose = new DisposableThing(whatever);
    // Now do stuff that might throw.
    // Once you know you're going to return successfully...
    DisposableThing thingToReturn = thingToDispose;
    thingToDispose = null;
    return thingToReturn;
}
finally
{
    if (thingToDispose != null)
      thingToDispose.Dispose();
}

Note that this code doesn't "catch" any exceptions, but if the function exits other than via the proper designated path the newly-constructed object will get disposed. 请注意,此代码不会“捕获”任何异常,但是如果函数通过正确的指定路径以外的其他途径退出,则将丢弃新构造的对象。 Note that if this function throws an exception without disposing of the newly-constructed object, any resources acquired by that object will leak, since the caller won't be able to dispose it. 请注意,如果此函数在不处置新构造的对象的情况下引发异常,则该对象获取的任何资源都会泄漏,因为调用者将无法处置它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM