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

拈花ヽ惹草 提交于 2019-12-24 03:05:11

问题


When a variable is IDisposable, we have the using keyword to manage the disposal. But what if we return the value in a method, should we have using twice?

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. 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?

b) keep only using with new together, and no need in other cases?:

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?:

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)


回答1:


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. For example, File.OpenRead wouldn't dispose of the stream that it returns, would it?

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.




回答2:


Having methods that return IDisposable objects is not an uncommon pattern, but preventing resource leaks when exceptions occur can be difficult. 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. The caller would then be expected to Dispose the thing in question, whether the method that produced it returned normally or threw an exception.

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:

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.



来源:https://stackoverflow.com/questions/16861329/best-practice-to-avoid-multiple-disposals-with-the-using-keyword-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!