Альтернативный синтаксис для C #, используя оператор для автоматического удаления объектов? - PullRequest
3 голосов
/ 07 марта 2012

Мне было интересно, может ли кто-нибудь придумать способ реализовать механизм, который работает как оператор using в C #, но с более чистым синтаксисом.

В C ++ / CLR вы можете написать

MyClass NewObject;

MyClass - это управляемый класс здесь.Как только переменная выйдет из области видимости, будет вызвана Dispose.По сути, он делает то же самое, что C # делает с using, но в более хорошем смысле.

Поэтому вместо записи

using (MyClass NewObject1=new MyClass())
{
    xxxx;
    using (MyClass NewObject2=new MyClass()
    {
    }
}

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

Я бы предпочел что-то вроде этого:

autodispose MyClass NewObject1=new MyClass();
xxxx;
autodispose MyClass NewObject2=new MyClass();

Кто-нибудь думает, что было бы возможнореализовать что-то подобное?Кажется, что фреймворки для AOP или контрактов кода используют механизмы, которые внедряют код, но я не уверен, как они это делают.

Ответы [ 3 ]

6 голосов
/ 07 марта 2012

MyClass является управляемым классом здесь.Как только переменная выйдет из области видимости, будет вызван Dispose.

Это просто неверно, даже в C ++ / CLR.Насколько я понимаю, C ++ / CLR по-прежнему опирается на ядро ​​.Net сборщика мусора для управляемых объектов, а не на традиционную семантику деструкторов C ++ ... и по этим правилам объект располагается в какой-то недетерминированной точке в будущем;это может быть немедленным ... но, скорее всего, нет. вероятно будет довольно скоро ... но вы не можете быть уверены.

Даже в мире C # блок using зарезервирован для неуправляемого ресурсы (то есть: все, кроме оперативной памяти).Вам не нужно помещать какой-либо объект в блок использования: большинство вещей можно безопасно создать без него.Когда вам нужен блок using, это когда что-то вроде сетевого подключения, подключения к базе данных, дескриптора файла, ресурса gdi, системного таймера и т. Д., Завернутого в тип, который вы создаете.

5 голосов
/ 07 марта 2012

Хотя у меня нет ответа, я чувствую, что стоит написать это как ответ, а не просто комментарии. Насколько я знаю, текущий ответ с наибольшим количеством голосов неверен. Согласно Гордону Хогенсону в Основах C ++ / CLI он поддерживает «синтаксический сахар или ловкость дескриптора» .... «Подводя итог, можно выделить объект, выделенный в куче , немедленно удаленный в конце блока вместо ленивого сбора мусора, и, как следствие, деструктор вызывается сразу после удаления ". шахты, р 63 Семантика стека и кучи

Программисты C ++ (предварительно умные указатели) привыкли к тому, что все, что они новые , они должны удалить . Однако, когда программист C ++ создает локальную переменную, ее не нужно помещать в кучу. Можно использовать семантику стека, и тогда объект не должен быть явно удален.

void Class::SomeMethod()
{ 
   DbConnection connection;  //No memory leak if not deleted
   DbConnection leaky_connection = new DbConnection(); //on the heap will leak if not deleted
}

В C ++ / CLI это выглядит немного иначе для выделения кучи:

DbConnection^ connection = gcnew DbConnection();

Но поскольку MS знала, что программисты на C ++ используются для создания семантики стека, они допускают семантическую версию стека:

DbConnection connection;

И при условии существования:

~DbConnection()
{
   //Close the connection
}

Семантическая версия стека немедленно вызовет деструктор в конце метода, где используется соединение.

Я думаю, что трудность сделать это в C # заключается в противоположности того, почему это разрешено в C ++ / CLI (и здесь я могу столкнуться с проблемами). Программисты C # привыкли позволять сборщику мусора заботиться о вещах. Они могут выделить локальный объект, вставить его в нелокальный контейнер и не беспокоиться о том, что он выйдет из области видимости в конце метода. ГК знает, что он в коллекции, и он не будет преждевременно уничтожен. C # всегда имеет дело со ссылками на объекты, и вы явно не указываете кучу против стека хранения. Реализация этой « ловкости ручки » в C #, вероятно, сломает много кода и ожиданий.

На самом деле, даже синтаксис оператора , использующий , может создать неожиданную проблему в C #. Я написал свой любимый пример этого в Когда «Уничтожение» выбрасывает ребенка с водой » некоторое время назад.

3 голосов
/ 07 марта 2012

Если вы хотите сжать ваши операторы использования для краткости, почему бы не сделать

using (MyClass class1 = new MyClass())
using (MyClass class2 = new MyClass())
using (MyClass class3 = new MyClass()) {
    object xxxx;
    // do some stuff
}

Вы можете сохранить себе несколько фигурных скобок и несколько лишних строк, поскольку кажется, что это то, что вам нужно, но это не важно. Если вы краткость-ОКР

using (var class1 = new MyClass())
using (var class2 = new MyClass())
using (var class3 = new MyClass()) {
    object xxxx;
    // do some stuff
}

Кстати, using - хорошая вещь для C #. Вы можете определить область действия переменной и точно знать, какова область действия этой переменной и когда она закончится. В противном случае область действия может полностью распространиться даже на какую-то другую функцию (например, передать ссылку на функцию или другой объект, содержащий ссылку на нее).

...