Нужно ли гнездовать с помощью IDisposable объектов?
Нужно ли обертывать все мои объекты IDisposable
в операторы using(){}
, даже если я просто перехожу один к другому? Например, следующим способом:
public static string ReadResponse(HttpWebResponse response)
{
string resp = null;
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader responseReader = new StreamReader(responseStream))
{
resp = responseReader.ReadToEnd();
}
}
return resp;
}
Могу ли я объединить это только с одним using
следующим образом:
public static string ReadResponse(HttpWebResponse response)
{
string resp = null;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
resp = reader.ReadToEnd();
}
return resp;
}
Могу ли я рассчитывать на размещение как Stream
, так и StreamReader
? Или мне нужно использовать два оператора using
?
Ответы
Ответ 1
Да, вы можете, но это потому, что документация конструктора StreamReader специально говорит: "Объект StreamReader вызывает Dispose на предоставленном объекте Stream при вызове StreamReader.Dispose."
Если это не так, вы можете сделать что-то вроде этого, чтобы хотя бы немного очистить код.
using (Stream responseStream = response.GetResponseStream())
using (StreamReader responseReader = new StreamReader(responseStream))
{
resp = responseReader.ReadToEnd();
}
Ответ 2
Человек/код/слой, создавший одноразовый объект, должен в целом нести ответственность за удаление объекта. Однако есть сценарии, которые могут возникнуть там, где это не так, и все в порядке. Это становится проблемой тогда документации.
Ответ 3
Я нашел этот вопрос более широким, чем простой вопрос о размещении инструкции using
, это довольно интересная проблема проектирования приложений.
Нужно ли обертывать все мои объекты IDisposable при использовании() {} операторов, даже если я просто перехожу один к другому?
Да, поскольку вы создаете экземпляр объекта, который реализует IDisposable
- вам известно об утилизации, либо путем переноса в using()
, либо явного вызова Dispose()
.
Причина этого проста, представьте себе следующий сценарий: у вас есть следующие сущности
- TransportService
- ReportService
- FeedService
все реализует IDisposable
. Оба ReportService
и FeedService
требуют, чтобы экземпляр TransportService
передавался в стадии строительства. И вопрос - правильно ли это распоряжаться TransportService
в Dispose()
ReportService или FeedService? Нет! Безусловно, один и тот же экземпляр транспортного сервиса может быть передан в обеих службах, и как только один из них будет транспортироваться - это повлияет и на все сервисы.
public sealed class ReportService : IDisposable
{
private readonly ITransportService transportService;
public ReportService(ITransportService transportService)
{
this.transportService = transportService;
}
public Dispose()
{
// ReportService should not dispose objects
// passed in since they could be used by other classes as well
// DO NOT: transportService.Dispose();
}
}