Почему нет RAII in.NET?



будучи в первую очередь разработчиком C++ отсутствие RAII (сбор ресурсов является инициализацией) в Java и .NET всегда беспокоило меня. Дело в том, что бремя очистки перемещается от класса writer к его потребителю (с помощью try finally или .NET using построить), кажется, заметно уступает.



Я вижу, почему в Java нет поддержки RAII, так как все объекты расположены в куче и сборщике мусора по своей сути не поддерживает детерминированное разрушение, но в .NET с введением типов значений (struct) у нас есть (казалось бы) идеальный кандидат для RAII. Тип значения, созданный в стеке, имеет четко определенную область действия, и можно использовать семантику деструктора C++. Однако среда CLR не позволяет типу значения иметь деструктор.



мои случайные поиски нашли один аргумент, что если тип значения в штучной упаковке это подпадает под юрисдикцию сборщика мусора и поэтому его разрушение становится недетерминированным.
Я чувствую, что этот аргумент недостаточно силен, преимущества RAII достаточно велики, чтобы сказать, что тип значения с деструктором не может быть упакован (или использован в качестве члена класса).



короче говоря, мой вопрос: существуют ли какие-либо другие причины, по которым типы значений не могут использоваться для введения RAII в .NET? (или вы думаете, что мой аргумент об очевидных преимуществах RAII испорченный?)



Edit: я, должно быть, не сформулировал вопрос ясно, так как первые четыре ответа упустили суть. Я знаю о 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();
}
}




Я не могу не закончить цитатой, которую я когда-то видел, но в настоящее время не могу найти ее происхождение.




вы можете взять мое детерминированное разрушение, когда моя холодная Мертвая рука выходит за рамки. -- Анон


700   7  

7 ответов:

лучшим названием было бы "почему нет RAII в C#/VB". C++ / CLI (эволюция аборта, который управлялся C++) имеет RAII в том же самом смысле, что и C++. Это всего лишь синтаксический сахар для того же шаблона завершения, что и остальные языки CLI (деструкторы в управляемых объектах для C++/CLI являются эффективными финализаторами), но он есть.

Вам может понравиться http://blogs.msdn.com/hsutter/archive/2004/07/31/203137.aspx

Отличный вопрос и тот, который меня очень беспокоил. Похоже, что преимущества RAII воспринимаются совсем по-другому. По моему опыту работы с .NET, отсутствие детерминированного (или, по крайней мере, надежного) сбора ресурсов является одним из основных недостатков. На самом деле, .NET заставил меня несколько раз использовать целые архитектуры для работы с неуправляемыми ресурсами, которые может (но не может) требовать явного сбора. Что, конечно, является огромным недостатком, потому что это делает общая архитектура более сложная и отвлекает внимание клиента от более центральных аспектов.

Брайан Гарри имеет хороший пост о рационалах здесь.

вот выдержка:

как насчет детерминированного завершения и типов значений (структур)?

-------------- Я видел много вопросов о структурах, имеющих деструкторы и т. д. Это стоит того комментировать. Есть целый ряд вопросы, почему некоторые языки не иметь их.

(1) Состав - они не дадут вам детерминированный жизни в целом случай для таких же видов состава причины описаны выше. Любой недетерминированный класс, содержащий один не будет вызывать деструктор, пока он был доработан ГК в любом случае.

(2) копировать конструкторы-одно место где было бы приятно находится в стек выделен местными жителями. Они были бы прицел к методу и все будет отличный. К сожалению, для того, чтобы получить это действительно работает, вы также должны добавление конструкторов копирования и позвоните им каждый раз, когда экземпляр копируется. Это один из самых уродливых и самых сложные вещи о c++. Вы в конечном итоге получение кода, выполняющегося по всему место, где вы этого не ожидаете. Оно вызывает пучки языковых проблем. Некоторые языковые дизайнеры выбрали держись от этого подальше.

допустим, мы создали структуры с помощью деструкторы, но добавили кучу ограничения на их поведение здравый смысл в отношении вопросов выше. Этот ограничения были бы что-то вроде:

(1) Вы можете объявить их только как локальные переменная.

(2) Вы можете только передать их by-ref

(3) Вы не можете назначить их, вы можно только получить доступ к полям и позвонить методы на них.

(4) Вы не можете боксировать их.

(5) Проблемы с их использованием через Отражение (позднее связывание), потому что обычно занимается боксом.

может быть, больше, но это хорошее начало.

какая польза от этих вещей? Бы вы на самом деле создаете файл или класс подключения к базе данных, который может Используется только как локальная переменная? Я не верю, что кто-то действительно будет. Вместо этого вы должны создать общецелевое соединение и после этого создайте автоматически разрушенную оболочку для используйте в качестве локальной переменной области действия. Этот абонент будет затем выбрать то, что они решили использовать. Обратите внимание, что абонент сделал a решение и то не совсем инкапсулируется в самом объекте. Учитывая, что вы могли бы использовать что-то как предложения, поступающие в пара секций.

заменой RAII в .NET является using-pattern, который работает почти так же хорошо, как только вы привыкнете к нему.

ближе всего вы получаете к этому очень ограниченный оператор stackalloc.

есть некоторые подобные потоки, если вы ищете их, но в основном это сводится к тому, что если вы хотите RAII на .NET просто реализовать тип IDisposable и использовать оператор "using" для получения детерминированного удаления. Таким образом, многие из тех же идеомов могут быть реализованы и использованы только немного более многословно.

ИМХО, большие вещи, которые VB.net а C# нужны такие:

  1. объявление "using"для полей, которое заставило бы компилятор генерировать код для удаления всех полей, помеченных таким образом. Поведение по умолчанию должно быть для компилятора, чтобы сделать реализацию класса IDisposable, если это не так, или вставить логику удаления перед началом основной процедуры удаления для любого из ряда общих шаблонов реализации IDisposal, или же использовать атрибут, чтобы указать, что удаление вещи должны идти в рутину с определенным именем.
  2. средство детерминированного удаления объектов, конструкторы и / или инициализаторы полей которых создают исключение, либо с помощью поведения по умолчанию (вызов метода удаления по умолчанию), либо с помощью пользовательского поведения (вызов метода с определенным именем).
  3. для vb.net, автоматически сгенерированный метод для обнуления всех полей WithEvent.

все из тех можно клудгед довольно хорошо внутри vb.net и несколько меньше хорошо в C#, но первоклассная поддержка для них улучшила бы оба языка.

вы можете сделать форму RAII в .net и java, используя методы finalize (). Перегрузка finalize () вызывается до того, как класс будет очищен GC, и поэтому может использоваться для очистки любых ресурсов, которые абсолютно не должны храниться классом (мьютексы, сокеты, дескрипторы файлов и т. д.). Однако это все еще не детерминировано.

с .NET вы можете сделать это детерминированно с помощью интерфейса IDisposable и ключевого слова using, но у этого есть ограничения (используя construct когда используется для детерминированного поведения, по-прежнему нет детерминированного освобождения памяти, не используется автоматически в классах и т. д.).

и да, я чувствую, что есть место для идей RAII, которые будут введены в .NET и другие управляемые языки, хотя точный механизм может обсуждаться бесконечно. Единственной альтернативой, которую я мог бы увидеть, было бы введение GC, который мог бы обрабатывать произвольную очистку ресурсов (а не только память), но тогда у вас есть проблемы, когда указанные ресурсы абсолютно есть быть освобожденным детерминистически.

Comments

    Ничего не найдено.