Рекомендуется избегать многократного удаления с ключевым словом `using` в C#
Когда переменная является IDisposable, мы имеем using
Ключевое слово для управления утилизацией. Но что, если мы вернем значение в методе, мы должны иметь 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;
}
}
В этом примере выше, у меня есть только 1 new
но у меня есть 2 using
за то же самое. Поэтому я чувствую, что это не сбалансировано. Это лучше:
а) сохранить оба using
, а язык / компилятор знает свою работу, чтобы избежать двойной утилизации?
б) хранить только using
с new
вместе и не нужно в других случаях?
void logStringContent()
{
StringContent content = stringToStringContent("test");
Debug.WriteLine(content.ToString());
return;
}
в) хранить только using
когда ты не вернешься, и не нужно, когда ты вернешься?
StringContent stringToStringContent(string str)
{
return new StringContent(str);
}
Единственное, что я чувствую, это то, что б) не правильный ответ, потому что он не будет работать для проблем, подобных описанной здесь: .NET HttpClient зависает после нескольких запросов (если Fiddler не активен)
2 ответа
Я думаю c
здесь правильный ответ - вы возвращаете (ссылку на) объект из метода - нет смысла уже удалять этот объект до того, как вы его вернете. Например, File.OpenRead
не избавится от потока, который он возвращает, не так ли?
Было бы неплохо указать в документации метода, что вызывающая сторона берет на себя ответственность за утилизацию объекта. Аналогичным образом, некоторые методы принимают одноразовый тип и утверждают, что вызывающая сторона не должна сама избавляться от объекта. В обоих случаях фактически происходит передача ответственности за правильную утилизацию объекта.
Наличие методов, которые возвращают IDisposable
Объекты - это не редкость, но предотвращение утечек ресурсов при возникновении исключений может быть затруднено. Альтернативный подход заключается в том, чтобы иметь метод, который будет производить новый IDisposable
принять out
или (если метод открытый и виртуальный) ref
параметр, и сохранить ссылку на новый объект в этом. Затем ожидается, что вызывающий абонент Dispose
вопрос в том, возвращал ли метод, который это произвел, нормально или выбрасывал исключение.
В противном случае, если вы хотите, чтобы возвращаемое значение вашего метода было новым 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();
}
Обратите внимание, что этот код не "перехватывает" какие-либо исключения, но если функция завершается не по правильному назначенному пути, вновь созданный объект будет удален. Обратите внимание, что если эта функция выдает исключение, не удаляя вновь созданный объект, любые ресурсы, полученные этим объектом, будут утечки, так как вызывающая сторона не сможет их утилизировать.