Каково ваше мнение о том, как одноразовые объекты внедряются в .Net? И как вы решаете повторяемость реализации IDisposable классов?
Я чувствую, что типы IDisposable не являются первоклассными гражданами, которых они должны были быть. Слишком много осталось на милость разработчика.
В частности, я задаюсь вопросом, не должно ли быть лучшей поддержки на языках и инструментах, чтобы убедиться, что одноразовые вещи реализованы правильно и правильно утилизированы.
В С#, например, что, если мой класс, который должен реализовать одноразовую семантику, может быть объявлен следующим образом:
public class disposable MyDisposableThing
{
~MyDisposableThing()
{
// Dispose managed resources
}
}
В этом случае компилятор может легко сгенерировать реализацию интерфейса IDisposable. Деструктор ~ MyDisposableThing может быть преобразован в фактический метод Dispose, который должен освобождать управляемые ресурсы.
Промежуточный код С# будет выглядеть следующим образом:
public class MyDisposableThing : IDisposable
{
private void MyDisposableThingDestructor()
{
// Dispose my managed resources
}
~MyDisposableThing()
{
DisposeMe(false);
}
public void Dispose()
{
DisposeMe(true);
GC.SuppressFinalize(this);
}
private bool _disposed;
private void DisposeMe(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Call the userdefined "destructor"
MyDisposableThingDestructor();
}
}
_disposed = true;
}
}
Это приведет к значительно более чистым кодам, меньшему тиражированию кода и постоянному способу утилизации управляемых ресурсов. Реализация IDisposable вручную будет по-прежнему поддерживаться для краевых случаев и неуправляемых ресурсов.
Обеспечение правильного расположения экземпляров - еще одна проблема. Рассмотрим следующий код:
private string ReadFile(string filename)
{
var reader = new StreamReader();
return reader.ReadToEnd(filename);
}
Переменная считывателя никогда не выделяет область действия метода, но придется ждать, пока GC ее утилизирует. В этом случае компилятор может вызвать ошибку, чтобы объект StreamReader не был явно удален. Эта ошибка заставит разработчика обернуть его в оператор using:
private string ReadFile(string filename)
{
using (var reader = new StreamReader())
{
return reader.ReadToEnd(filename);
}
}