Как я могу детерминировать распоряжаться управляемым объектом С++/CLI из С#?

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

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

Ответ 1

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

((IDisposable)obj).Dispose();

Ответ 2

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

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

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

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

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

Ответ 3

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