Как я могу определенным образом распоряжаться управляемым объектом C ++ / CLI из C #? - PullRequest
12 голосов
/ 08 февраля 2011

У меня есть управляемый объект в сборке C ++ / CLI. Будучи C ++ / CLI, он реализует шаблон Disposable через своего «деструктора» (да, я знаю, что он не такой же, как стандартный деструктор C ++). Из C ++ / CLI я бы просто delete объект. Однако я использую этот объект как переменную-член в классе C #.

Тогда из моего класса C # я бы хотел вызвать эквивалент метода Dispose () для объекта C ++ / CLI, когда я закончу его использовать. Так как она является (и должна быть) переменной-членом класса, использование блока using () исключено. Насколько я могу судить, не существует открытого метода для прямого, детерминированного удаления ресурсов из языка, отличного от C ++ / CLI. Как мне это сделать?

Ответы [ 3 ]

10 голосов
/ 08 февраля 2011

Это не так очевидно в C ++ / CLI, но работает точно так же, как в C #. Вы можете увидеть это, когда посмотрите на класс с помощью Object Browser. Или декомпилятор, такой как ildasm.exe, лучший способ узнать, что он делает.

Когда вы пишете деструктор, компилятор C ++ / CLI автоматически генерирует кучу кода. Он реализует одноразовый шаблон, ваш класс автоматически реализует IDisposable, даже если вы не объявили его таким образом. И вы получаете открытый метод Dispose (), защищенный метод Dispose (bool) и автоматический вызов GC :: SuppressFinalize ().

Вы используете delete в C ++ / CLI для его явного вызова, компилятор вызывает вызов Dispose (). И вы получаете эквивалент RAII в C ++ / CLI, используя семантика стека , компилятор автоматически отправляет вызов Dispose в конце блока области видимости. Синтаксис и поведение, знакомые программистам C ++.

Вы делаете то же самое, что и в C #, если бы класс был написан на C #. Вы вызываете Dispose () для явного вызова, вы используете оператор using, чтобы неявно вызывать его безопасным для исключения способом.

В остальных случаях применяются те же правила, вам нужен деструктор, когда вам нужно освободить что-то, что не является управляемой памятью. Почти всегда нативный объект, который вы разместили в конструкторе. Учтите, что не стоит беспокоиться, если этот неуправляемый объект небольшой и что GC :: AddMemoryPressure () является очень достойной альтернативой. Однако вы должны реализовать финализатор (!ClassName()) в таком классе-оболочке. Вы не можете заставить внешний клиентский код вызывать Dispose (), это необязательно, и о нем часто забывают. Вы не хотите, чтобы такой упуск вызывал неуправляемую утечку памяти, финализатор гарантирует, что она все еще освобождена. Обычно самый простой способ написать деструктор - это явно вызвать финализатор (this->!ClassName();)

9 голосов
/ 08 февраля 2011

Синтаксис, похожий на деструктор C ++ / CLI, автоматически реализует IDisposable, но делает это аналогично явной реализации интерфейса C # . Это означает, что вам нужно привести к IDisposable для доступа к методу Dispose:

((IDisposable)obj).Dispose();
0 голосов
/ 08 февраля 2011

Вы не можете. По крайней мере, не из C #. Пусть сборщик мусора сделает свое дело.

...