Будучи главным разработчиком C ++, отсутствие RAII (Resource Acquisition Is Initialization) в Java и .NET всегда беспокоило меня. Тот факт, что ответственность за очистку переходит от автора класса к его потребителю (с помощью try finally
или .NET using
конструкции ), по-видимому, заметно уступает.
Я понимаю, почему в Java нет поддержки RAII, поскольку все объекты расположены в куче, а сборщик мусора по своей природе не поддерживает детерминированное уничтожение, но в .NET с введением типов-значений (struct
) у нас (казалось бы) идеальный кандидат в RAII. Тип значения, созданный в стеке, имеет четко определенную область видимости, и можно использовать семантику деструктора C ++. Однако CLR не позволяет типу значения иметь деструктор.
Мой случайный поиск нашел один аргумент, что если тип значения в штучной упаковке , он попадает под юрисдикцию сборщика мусора, и поэтому его уничтожение становится недетерминированным.
Мне кажется, что этот аргумент недостаточно силен, преимущества RAII достаточно велики, чтобы сказать, что тип-значение с деструктором не может быть упакован (или использован в качестве члена класса).
Короче говоря, мой вопрос : существуют ли другие причины, по которым типы значений нельзя использовать для представления RAII в .NET? (или вы думаете, что мой аргумент об очевидных преимуществах RAII неверен?)
Редактировать: Должно быть, я не четко сформулировал вопрос, так как первые четыре ответа упустили из виду. Я знаю о Finalize
и его недетерминированных характеристиках, я знаю о конструкции using
и чувствую, что эти два варианта ниже RAII. using
- еще одна вещь, которую должен запомнить потребитель класса (сколько людей забыли поместить StreamReader
в блок using
?). У меня философский вопрос о языковом дизайне, почему он таков и может быть улучшен?
Например, с помощью общего детерминированного разрушаемого типа значения я могу сделать избыточными ключевые слова using
и lock
(достижимо с помощью библиотечных классов):
public struct Disposer<T> where T : IDisposable
{
T val;
public Disposer(T t) { val = t; }
public T Value { get { return val; } }
~Disposer() // Currently illegal
{
if (val != default(T))
val.Dispose();
}
}
Не могу не закончить приведенной цитатой, которую я однажды видел, но в настоящее время не могу найти ее происхождение.
Вы можете взять мое детерминированное уничтожение, когда моя холодная мертвая рука выходит за рамки. - Anon