Написал класс — оболочку для COM-объекта. Все работает замечательно, вот только при удалении класса-оболочки мне необходимо сделать некоторые действия с COM-объектом, точнее послать ему сообщения о завершении.
Я создаю WIN — формочку и создаю экземпляр оболочки. При закрытии формы должен вызываться диструктор этой оболочки и посылаться сообщение COM-объекту. На деле же, в методе Finalize COM объект уже очищен — независимо от того CriticalFinalizerObject у меня оболочка или нет. Даже через диспетчер задач видно что COM-объект удаляется, когда закрывается формочка, без ожидания вызова дистркутора оболочки.
Почему так, и как бороться, вот код:
public class MyClass : CriticalFinalizerObject
{
private MyCOMObject _Application;
public MyClass ()
{
_Application = new MyCOMObject ();
}
~MyClass ()
{
//тут в COM объект должно посылатсья сообщение, но вываливается исключение
//"COM object that has been separated from its underlying RCW cannot be used."
_Application.Do("End");
System.Runtime.InteropServices.Marshal.ReleaseComObject(_Application);
}
DF>Написал класс — оболочку для COM-объекта. Все работает замечательно, вот только при удалении класса-оболочки мне необходимо сделать некоторые действия с COM-объектом, точнее послать ему сообщения о завершении. DF>Я создаю WIN — формочку и создаю экземпляр оболочки. При закрытии формы должен вызываться диструктор этой оболочки и посылаться сообщение COM-объекту. На деле же, в методе Finalize COM объект уже очищен — независимо от того CriticalFinalizerObject у меня оболочка или нет. Даже через диспетчер задач видно что COM-объект удаляется, когда закрывается формочка, без ожидания вызова дистркутора оболочки.
Все правильно — CriticalFinalizerObject вызывается последним. на данном этапе MyCOMObject был уже финализирован.
Вам надо в вашей "оболочке" делать Marshal.GetIUnknownForObject и хранить его — в этом случае, будет гарантия того, что объект не "умрет" раньше времени.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
TK>Все правильно — CriticalFinalizerObject вызывается последним. на данном этапе MyCOMObject был уже финализирован. TK>Вам надо в вашей "оболочке" делать Marshal.GetIUnknownForObject и хранить его — в этом случае, будет гарантия того, что объект не "умрет" раньше времени.
Теперь я пишу так:
public class MyClass : CriticalFinalizerObject
{
private MyCOMObject _Application;
private IntPrt _Pointer;
public MyClass ()
{
_Application = new MyCOMObject ();
_Pointer = Marshal.GetIUnknownForObject(_Application);
}
~MyClass ()
{
//тут в COM объект должно посылатсья сообщение, но вываливается исключение
//"COM object that has been separated from its underlying RCW cannot be used."
_Application.Do("End");
Marshal.Release(_Pointer);
}
Та же самая ошибка вылезает... Никакого эффекта...
Здравствуйте, TK, Вы писали:
TK>Здравствуйте, DragonFire, Вы писали:
DF>>Теперь я пишу так: DF>>Та же самая ошибка вылезает... Никакого эффекта...
TK>Надо взять _Pointer, из него сделать объект и уже тогда дергать. А так, не удивительно, что вылезает — ничего ведь не изменилось...
Хорошо, а так:
public class MyClass : CriticalFinalizerObject
{
private MyCOMObject _Application;
public MyClass ()
{
_Application = (MyCOMObject)Marshal.GetObjectForIUnknown(Marshal.GetIUnknownForObject(new MyCOMObject()));
}
~MyClass ()
{
//тут в COM объект должно посылатсья сообщение, но вываливается исключение
//"COM object that has been separated from its underlying RCW cannot be used."
_Application.Do("End");
Marshal.ReleaseComObject(_Application );
}
Здравствуйте, TK, Вы писали:
TK>Здравствуйте, DragonFire, Вы писали:
DF>>Или я чего-то не понимаю?...(
TK>Marshal.GetObjectForIUnknown надо вызывать в финализаторе.
Так ведь, когда до финализатора дело доходит, COM объекта уже не существует. Или вызов этот предотвратит его удаление?
Здравствуйте, DragonFire, Вы писали:
DF>Здравствуйте, TK, Вы писали:
TK>>Здравствуйте, DragonFire, Вы писали:
DF>>>Или я чего-то не понимаю?...(
TK>>Marshal.GetObjectForIUnknown надо вызывать в финализаторе.
DF>Так ведь, когда до финализатора дело доходит, COM объекта уже не существует. Или вызов этот предотвратит его удаление?
Да и к тому же если пытатся вызвать этот метод в финализоторе, вылазит ошибка:
The application called an interface that was marshalled for a different thread.
Здравствуйте, DragonFire, Вы писали:
DF>>Так ведь, когда до финализатора дело доходит, COM объекта уже не существует. Или вызов этот предотвратит его удаление?
Как это не существует? GetIUnknownForObject добавляет ссылку к объекту. Следовательно, сам объект будет жить пока эту ссылку не отпустят.
DF>Да и к тому же если пытатся вызвать этот метод в финализоторе, вылазит ошибка: DF>The application called an interface that was marshalled for a different thread.
GetIUnknownForObject вызывается из STA потока?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
TK>Здравствуйте, DragonFire, Вы писали:
DF>>>Так ведь, когда до финализатора дело доходит, COM объекта уже не существует. Или вызов этот предотвратит его удаление?
TK>Как это не существует? GetIUnknownForObject добавляет ссылку к объекту. Следовательно, сам объект будет жить пока эту ссылку не отпустят.
DF>>Да и к тому же если пытатся вызвать этот метод в финализоторе, вылазит ошибка: DF>>The application called an interface that was marshalled for a different thread.
TK>GetIUnknownForObject вызывается из STA потока?
Да, но сборщик мусора работает всегда в отдельном потоке... Тем более, как я уже говорил, вызов GetIUnknownForObject и сохранение ссылки ничего не дает — объект умирает когда вызывается финалайз... Через диспетчер задач просто видно что COM — объект завершается, если в финалайз брейкпойнт поставить...
Здравствуйте, DragonFire, Вы писали:
TK>>GetIUnknownForObject вызывается из STA потока?
DF>Да, но сборщик мусора работает всегда в отдельном потоке...
Маловероятно, что сборщик мусора делает это в STA ;) В остальном при использовании MTA дополнительного маршаллинга COM указателей не требуется.
DF>Тем более, как я уже говорил, вызов GetIUnknownForObject и сохранение ссылки ничего не дает — объект умирает когда вызывается финалайз... Через диспетчер задач просто видно что COM — объект завершается, если в финалайз брейкпойнт поставить...
Значит вы как-то еще выгружаете объект... GetIUnknownForObject инкрементирует счетчик ссылок объекта и пока не вызван Release — сам он выгружаться не будет
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
TK>Здравствуйте, DragonFire, Вы писали:
TK>>>GetIUnknownForObject вызывается из STA потока?
DF>>Да, но сборщик мусора работает всегда в отдельном потоке...
TK>Маловероятно, что сборщик мусора делает это в STA В остальном при использовании MTA дополнительного маршаллинга COM указателей не требуется.
DF>>Тем более, как я уже говорил, вызов GetIUnknownForObject и сохранение ссылки ничего не дает — объект умирает когда вызывается финалайз... Через диспетчер задач просто видно что COM — объект завершается, если в финалайз брейкпойнт поставить...
TK>Значит вы как-то еще выгружаете объект... GetIUnknownForObject инкрементирует счетчик ссылок объекта и пока не вызван Release — сам он выгружаться не будет
Ну тогда, скорее всего, COM объект умирает, когда умирает поток... Хотя поидее потом не должен умирать пока не выполнится finalize... Сам я COM не чищу нигде.
Как я уже говорил — экземпляр класса (пример пара постов выше) просто создается как поле формы...
Здравствуйте, DragonFire, Вы писали:
DF>Здравствуйте, TK, Вы писали:
TK>>Здравствуйте, DragonFire, Вы писали:
TK>>>>GetIUnknownForObject вызывается из STA потока?
DF>>>Да, но сборщик мусора работает всегда в отдельном потоке...
TK>>Маловероятно, что сборщик мусора делает это в STA В остальном при использовании MTA дополнительного маршаллинга COM указателей не требуется.
DF>>>Тем более, как я уже говорил, вызов GetIUnknownForObject и сохранение ссылки ничего не дает — объект умирает когда вызывается финалайз... Через диспетчер задач просто видно что COM — объект завершается, если в финалайз брейкпойнт поставить...
TK>>Значит вы как-то еще выгружаете объект... GetIUnknownForObject инкрементирует счетчик ссылок объекта и пока не вызван Release — сам он выгружаться не будет
DF>Ну тогда, скорее всего, COM объект умирает, когда умирает поток... Хотя поидее потом не должен умирать пока не выполнится finalize... Сам я COM не чищу нигде. DF>Как я уже говорил — экземпляр класса (пример пара постов выше) просто создается как поле формы...
Причем сейчас создал консольное приложение — там все отлично работает. Подозреваю что косяк где-то изза вызовов Dispose и компонентной модели WinForms...
Здравствуйте, DragonFire, Вы писали:
DF>Ну тогда, скорее всего, COM объект умирает, когда умирает поток... Хотя поидее потом не должен умирать пока не выполнится finalize... Сам я COM не чищу нигде.
1. Время жизни COM объекта не зависит от времени жизни потока.
2. Finalize кого? При реализации finalize стоит руководствоваться простым правилом — финализировать надо только себя. все другие объекты уже скорее всего финализированы (за редкими исключениями).
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
TK>Здравствуйте, DragonFire, Вы писали:
DF>>Ну тогда, скорее всего, COM объект умирает, когда умирает поток... Хотя поидее потом не должен умирать пока не выполнится finalize... Сам я COM не чищу нигде.
TK>1. Время жизни COM объекта не зависит от времени жизни потока. TK>2. Finalize кого? При реализации finalize стоит руководствоваться простым правилом — финализировать надо только себя. все другие объекты уже скорее всего финализированы (за редкими исключениями).
Конечно финалайз объекта...
Re: COM объект и Finalize
От:
Аноним
Дата:
17.07.09 06:50
Оценка:
Здравствуйте, DragonFire, Вы писали:
DF>День добрый всем.
DF>Написал класс — оболочку для COM-объекта. Все работает замечательно, вот только при удалении класса-оболочки мне необходимо сделать некоторые действия с COM-объектом, точнее послать ему сообщения о завершении. DF>Я создаю WIN — формочку и создаю экземпляр оболочки. При закрытии формы должен вызываться диструктор этой оболочки и посылаться сообщение COM-объекту. На деле же, в методе Finalize COM объект уже очищен — независимо от того CriticalFinalizerObject у меня оболочка или нет. Даже через диспетчер задач видно что COM-объект удаляется, когда закрывается формочка, без ожидания вызова дистркутора оболочки.
DF>Почему так, и как бороться, вот код: DF>
DF>public class MyClass : CriticalFinalizerObject
DF>{
DF> private MyCOMObject _Application;
DF> public MyClass ()
DF> {
DF> _Application = new MyCOMObject ();
DF> }
DF> ~MyClass ()
DF> {
DF> //тут в COM объект должно посылатсья сообщение, но вываливается исключение
DF> //"COM object that has been separated from its underlying RCW cannot be used."
DF> _Application.Do("End");
DF> System.Runtime.InteropServices.Marshal.ReleaseComObject(_Application);
DF> }
DF>
Возможно, я ошибаюсь, но думаю, что среда разрывает связь MyCOMObject с реальным COM-объектом ещё до его финализации. Происходит это потому, что деструктор вызывается сбощиком, который работает в отдельном потоке, и если Вы создали объект в STA, то из другого потока обратиться к нему не удастся, COM'овская прокси не пропустит вызов из чужого апартамента.
В качестве решения — почему-бы Вам не снабдить Ваш MyClass интерфейсом IDisposable? И _Application.Do("End") вызывать в Dispose. Тогда MyClass.Dispose можно будет вызвать из Dispose(disposing) формы, а заодно и с using будет работать.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, DragonFire, Вы писали:
DF>>День добрый всем.
DF>>Написал класс — оболочку для COM-объекта. Все работает замечательно, вот только при удалении класса-оболочки мне необходимо сделать некоторые действия с COM-объектом, точнее послать ему сообщения о завершении. DF>>Я создаю WIN — формочку и создаю экземпляр оболочки. При закрытии формы должен вызываться диструктор этой оболочки и посылаться сообщение COM-объекту. На деле же, в методе Finalize COM объект уже очищен — независимо от того CriticalFinalizerObject у меня оболочка или нет. Даже через диспетчер задач видно что COM-объект удаляется, когда закрывается формочка, без ожидания вызова дистркутора оболочки.
DF>>Почему так, и как бороться, вот код: DF>>
DF>>public class MyClass : CriticalFinalizerObject
DF>>{
DF>> private MyCOMObject _Application;
DF>> public MyClass ()
DF>> {
DF>> _Application = new MyCOMObject ();
DF>> }
DF>> ~MyClass ()
DF>> {
DF>> //тут в COM объект должно посылатсья сообщение, но вываливается исключение
DF>> //"COM object that has been separated from its underlying RCW cannot be used."
DF>> _Application.Do("End");
DF>> System.Runtime.InteropServices.Marshal.ReleaseComObject(_Application);
DF>> }
DF>>
А>Возможно, я ошибаюсь, но думаю, что среда разрывает связь MyCOMObject с реальным COM-объектом ещё до его финализации. Происходит это потому, что деструктор вызывается сбощиком, который работает в отдельном потоке, и если Вы создали объект в STA, то из другого потока обратиться к нему не удастся, COM'овская прокси не пропустит вызов из чужого апартамента.
А>В качестве решения — почему-бы Вам не снабдить Ваш MyClass интерфейсом IDisposable? И _Application.Do("End") вызывать в Dispose. Тогда MyClass.Dispose можно будет вызвать из Dispose(disposing) формы, а заодно и с using будет работать.
Я уже думал над этим, но просто суть в том, что мой класс, а точнее заключенный в него COM объект, могут использовтаь другие сущности, например сущность "Таблица". Такая сущность перед тем, как завершиться, должна послать моему объекту "Table Close", иначе системные ресурсы (файл таблицы на диске) будет продолжать использоваться и процесс не уничтожиться.
Для этого я и использовал CriticalFinalizerObject — чтобы любые другие сущность могли спокойно себя очистить.
Re[3]: COM объект и Finalize
От:
Аноним
Дата:
18.07.09 08:45
Оценка:
Здравствуйте, DragonFire, Вы писали:
DF>Я уже думал над этим, но просто суть в том, что мой класс, а точнее заключенный в него COM объект, могут использовтаь другие сущности, например сущность "Таблица". Такая сущность перед тем, как завершиться, должна послать моему объекту "Table Close", иначе системные ресурсы (файл таблицы на диске) будет продолжать использоваться и процесс не уничтожиться. DF>Для этого я и использовал CriticalFinalizerObject — чтобы любые другие сущность могли спокойно себя очистить.
Хм, я конечно в NET новичок, но насколько понял по беглому знакомству, так, как хотите Вы, заботливая NET сделать не даст. Финализация всех объектов идёт в отдельном потоке, то есть в общем случае COM-апартамент потока сборщика и того потока, в котором создавался COM-объект, не совпадают. А из чужого апартамента нельзя удалить COM-объект. Т.е. в частном случае, когда у нас In-process сервер, и заявленная им апартаментная модель совпадает с моделью создавшего его потока, удалить его технически возможно, но это будет явным и грубым нарушением требований COM, и может привести к непредсказуемым результатам. Это во-первых, а во-вторых мы не можем, насколько я понял, знать заранее порядок финализации объектом сборщиком, а следовательно и не должны в деструкторе пытаться обращаться к другим управляемым объектам, даже если мы храним ссылки на них.
Отсюда следует, что для Вашей задачи финализатор — место совсем не подходящее, надо искать другое. А вот порядком вызова Dispose мы вполне способны управлять. Вот я смотрю — Dispose формы вызывает Dispose всех своих компонентов. Почему-бы и Вашим сущностям не выполнить свои завершающие действия здесь-же, даже если они не являются компонентами. А если являются, то можно это сделать в их Dispose.
Другие варианты, которые мне приходят в голову, связаны с неуправляемым кодом. Если этот СОМ-объект написан Вами, то почему-бы ему перед удалением не закрывать все открытые им ресурсы самостоятельно, без понукания. Вообще вот эта фраза
должна послать моему объекту "Table Close", иначе системные ресурсы (файл таблицы на диске) будет продолжать использоваться и процесс не уничтожиться.
выглядит немного странно СОМ-объект должен, как правило, уничтожаться, когда на него нет внешних ссылок, а если это последний объект в процессе, то и процесс, как правило, при этом завершается, а значит и автоматически закрываются все имеющиеся у него хёндлы, что приводит и к закрытию открытых им файлов. Впрочем, с завершением возможны конечно вариации.
Если объект не Ваш, то, как вариант, можно написать для него свой враппер, который перед последним вызовом Release этого объекта будет выдавать ему команду на завершение.
Что забавно, в нативном коде такой тпроблемы вообще-бы не возникло
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, DragonFire, Вы писали:
DF>>Я уже думал над этим, но просто суть в том, что мой класс, а точнее заключенный в него COM объект, могут использовтаь другие сущности, например сущность "Таблица". Такая сущность перед тем, как завершиться, должна послать моему объекту "Table Close", иначе системные ресурсы (файл таблицы на диске) будет продолжать использоваться и процесс не уничтожиться. DF>>Для этого я и использовал CriticalFinalizerObject — чтобы любые другие сущность могли спокойно себя очистить.
А>Хм, я конечно в NET новичок, но насколько понял по беглому знакомству, так, как хотите Вы, заботливая NET сделать не даст. Финализация всех объектов идёт в отдельном потоке, то есть в общем случае COM-апартамент потока сборщика и того потока, в котором создавался COM-объект, не совпадают. А из чужого апартамента нельзя удалить COM-объект. Т.е. в частном случае, когда у нас In-process сервер, и заявленная им апартаментная модель совпадает с моделью создавшего его потока, удалить его технически возможно, но это будет явным и грубым нарушением требований COM, и может привести к непредсказуемым результатам. Это во-первых, а во-вторых мы не можем, насколько я понял, знать заранее порядок финализации объектом сборщиком, а следовательно и не должны в деструкторе пытаться обращаться к другим управляемым объектам, даже если мы храним ссылки на них.
Почитайте CriticalFinalizerObject — с помощью него мы МОЖЕМ управлять порядком вызовов финализаторов.
А>Отсюда следует, что для Вашей задачи финализатор — место совсем не подходящее, надо искать другое. А вот порядком вызова Dispose мы вполне способны управлять. Вот я смотрю — Dispose формы вызывает Dispose всех своих компонентов. Почему-бы и Вашим сущностям не выполнить свои завершающие действия здесь-же, даже если они не являются компонентами. А если являются, то можно это сделать в их Dispose.
А вот тут как раз мы не можем предсказать что вызовется раньше — Dispose моей оболочки COM-объекта или Dispose таблицы, ссылающейся на эту оболочку. И тогда, опять же, может возникнуть ситуация когда таблица не сможет закрыться из-за завершенности соединения с COM.
А>Другие варианты, которые мне приходят в голову, связаны с неуправляемым кодом. Если этот СОМ-объект написан Вами, то почему-бы ему перед удалением не закрывать все открытые им ресурсы самостоятельно, без понукания. Вообще вот эта фраза А>
А>должна послать моему объекту "Table Close", иначе системные ресурсы (файл таблицы на диске) будет продолжать использоваться и процесс не уничтожиться.
А>выглядит немного странно СОМ-объект должен, как правило, уничтожаться, когда на него нет внешних ссылок, а если это последний объект в процессе, то и процесс, как правило, при этом завершается, а значит и автоматически закрываются все имеющиеся у него хёндлы, что приводит и к закрытию открытых им файлов. Впрочем, с завершением возможны конечно вариации. А>Если объект не Ваш, то, как вариант, можно написать для него свой враппер, который перед последним вызовом Release этого объекта будет выдавать ему команду на завершение.
Объект не мой, и повлиять на его завершение я не могу. Более того, если бы он сам чистил бы занятые системные ресурсы, проблем бы не было...
Re[5]: COM объект и Finalize
От:
Аноним
Дата:
18.07.09 13:39
Оценка:
Здравствуйте, DragonFire, Вы писали:
DF>Почитайте CriticalFinalizerObject — с помощью него мы МОЖЕМ управлять порядком вызовов финализаторов.
Обязательно, ещё раз.. и, возможно, не раз.
А>>Отсюда следует, что для Вашей задачи финализатор — место совсем не подходящее, надо искать другое. А вот порядком вызова Dispose мы вполне способны управлять. Вот я смотрю — Dispose формы вызывает Dispose всех своих компонентов. Почему-бы и Вашим сущностям не выполнить свои завершающие действия здесь-же, даже если они не являются компонентами. А если являются, то можно это сделать в их Dispose.
DF>А вот тут как раз мы не можем предсказать что вызовется раньше — Dispose моей оболочки COM-объекта или Dispose таблицы, ссылающейся на эту оболочку. И тогда, опять же, может возникнуть ситуация когда таблица не сможет закрыться из-за завершенности соединения с COM.
Странно. Мне показалось, что это как раз легко предсказуемо Попробовал — получилось. Но видиммо, я что-то не так делал.
А>>Другие варианты, которые мне приходят в голову, связаны с неуправляемым кодом. Если этот СОМ-объект написан Вами, то почему-бы ему перед удалением не закрывать все открытые им ресурсы самостоятельно, без понукания. Вообще вот эта фраза А>>
А>>должна послать моему объекту "Table Close", иначе системные ресурсы (файл таблицы на диске) будет продолжать использоваться и процесс не уничтожиться.
А>>выглядит немного странно СОМ-объект должен, как правило, уничтожаться, когда на него нет внешних ссылок, а если это последний объект в процессе, то и процесс, как правило, при этом завершается, а значит и автоматически закрываются все имеющиеся у него хёндлы, что приводит и к закрытию открытых им файлов. Впрочем, с завершением возможны конечно вариации. А>>Если объект не Ваш, то, как вариант, можно написать для него свой враппер, который перед последним вызовом Release этого объекта будет выдавать ему команду на завершение.
DF>Объект не мой, и повлиять на его завершение я не могу. Более того, если бы он сам чистил бы занятые системные ресурсы, проблем бы не было...
Ну а зачем пользоваться чем-то, что безграмотно написано? Впрочем, я так понял, что Вы уже нашли решение в рамках своей парадигмы. Но делиться своим решением с кем-либо не желаете...Ну что-же, тоже позиция, в некотором смысле.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, DragonFire, Вы писали:
А>>>Отсюда следует, что для Вашей задачи финализатор — место совсем не подходящее, надо искать другое. А вот порядком вызова Dispose мы вполне способны управлять. Вот я смотрю — Dispose формы вызывает Dispose всех своих компонентов. Почему-бы и Вашим сущностям не выполнить свои завершающие действия здесь-же, даже если они не являются компонентами. А если являются, то можно это сделать в их Dispose.
DF>>А вот тут как раз мы не можем предсказать что вызовется раньше — Dispose моей оболочки COM-объекта или Dispose таблицы, ссылающейся на эту оболочку. И тогда, опять же, может возникнуть ситуация когда таблица не сможет закрыться из-за завершенности соединения с COM.
А>Странно. Мне показалось, что это как раз легко предсказуемо Попробовал — получилось. Но видиммо, я что-то не так делал.
Тут когда как. Смотрите, есть форма и у нее такие поля:
MyTable t1;
MyCOMComponent c;
MyTable t2;
Создавая таблицы, я передаю им компонент, примерно так: t1 = new MyTable(c);
Теперь при закрытии формы каждая таблица должна выполнить нечто вроде c.Exec("Close Table t1.tab");
И может я ошибаюсь, но я не вижу гарантии что выполнится именно так программа:
t1.Dispose(); //c.Exec("Close Table t1.tab");
t2.Dispose(); //c.Exec("Close Table t2.tab");
c.Dispose(); //this.Exec("End Application");
А не так:
t1.Dispose(); //c.Exec("Close Table t1.tab");
c.Dispose(); //this.Exec("End Application");
t2.Dispose(); //Ошибка
А>Ну а зачем пользоваться чем-то, что безграмотно написано? Впрочем, я так понял, что Вы уже нашли решение в рамках своей парадигмы. Но делиться своим решением с кем-либо не желаете...Ну что-же, тоже позиция, в некотором смысле. А>Желаю удачи.
Решение не нашел еще Временное решение — на событие OnClose формы вручную прописал закрытие всех таблиц.
Т.к. пишу некую библиотеку классов, такое решение естественно неприемлемо, так что вопрос открытый.
Прошу прощения, если оскорбил Вас чем-либо... В отпуск на неделю ухожу, мб чего в голову гениальное еще придет, через неделю вернусь в эту тему обязательно.
А насчет пользоваться... Тут я с Вами полностью согласен, но приходиться, когда альтернативы нету...
Re[7]: COM объект и Finalize
От:
Аноним
Дата:
18.07.09 14:44
Оценка:
Здравствуйте, DragonFire, Вы писали:
DF>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, DragonFire, Вы писали:
А>>>>Отсюда следует, что для Вашей задачи финализатор — место совсем не подходящее, надо искать другое. А вот порядком вызова Dispose мы вполне способны управлять. Вот я смотрю — Dispose формы вызывает Dispose всех своих компонентов. Почему-бы и Вашим сущностям не выполнить свои завершающие действия здесь-же, даже если они не являются компонентами. А если являются, то можно это сделать в их Dispose.
DF>>>А вот тут как раз мы не можем предсказать что вызовется раньше — Dispose моей оболочки COM-объекта или Dispose таблицы, ссылающейся на эту оболочку. И тогда, опять же, может возникнуть ситуация когда таблица не сможет закрыться из-за завершенности соединения с COM.
А>>Странно. Мне показалось, что это как раз легко предсказуемо Попробовал — получилось. Но видиммо, я что-то не так делал.
DF>Тут когда как. Смотрите, есть форма и у нее такие поля: DF>MyTable t1; DF>MyCOMComponent c; DF>MyTable t2;
DF>Создавая таблицы, я передаю им компонент, примерно так: t1 = new MyTable(c); DF>Теперь при закрытии формы каждая таблица должна выполнить нечто вроде c.Exec("Close Table t1.tab"); DF>И может я ошибаюсь, но я не вижу гарантии что выполнится именно так программа: DF>t1.Dispose(); //c.Exec("Close Table t1.tab"); DF>t2.Dispose(); //c.Exec("Close Table t2.tab"); DF>c.Dispose(); //this.Exec("End Application"); DF>А не так: DF>t1.Dispose(); //c.Exec("Close Table t1.tab"); DF>c.Dispose(); //this.Exec("End Application"); DF>t2.Dispose(); //Ошибка
Ну почему?! Вы же в методе шызщыу ормы вольны сами задать порядок вызова.
Возможно, моё предложение навеяно нативом, и не совсем подходяще для NET, но я бы сделал так — коль скоро пользователи Вашего враппера написаны Вами-же, то пусть они в конструкторе добавляют себя в список "корреспондентов" Вашего враппера. Тогда этот враппер в своём Dispose сможет вызвать Dispose всех своих актуальных корреспондентов, ну а необходимость вызова Dispose для самого враппера уже подразумевается реализацией им IDisposable, а кто этого не сделает, тот Сам Себе Злобный Буратино. По-моему, всё равно более жёстко это обусловить невозможно, и если я не прав, то пусть более опытные в NET товарищи меня поправят. Это подразумевает, что пользователи Вашего враппера должны иметь флаг disposed, для нейтрализации попыток многократного вызова этого метода, но это, как я понял, нормально для NET. Впрочем, при желании для этого можно задействоовать и какое-нибудь nullable поле, хотя вряд-ли оно того стоит.
DF>В отпуск на неделю ухожу
Блин, отпуск — это хорошо, но неделя — это просто издевательство Не, я где-нибудь в середине или начале августа, по погоде, и — на месяц! Завалюсь в тайгу к другу и телефон выключу, всё одно там не примет!!!
Здравствуйте, Аноним, Вы писали:
А>Ну почему?! Вы же в методе шызщыу ормы вольны сами задать порядок вызова. А>Возможно, моё предложение навеяно нативом, и не совсем подходяще для NET, но я бы сделал так — коль скоро пользователи Вашего враппера написаны Вами-же, то пусть они в конструкторе добавляют себя в список "корреспондентов" Вашего враппера. Тогда этот враппер в своём Dispose сможет вызвать Dispose всех своих актуальных корреспондентов, ну а необходимость вызова Dispose для самого враппера уже подразумевается реализацией им IDisposable, а кто этого не сделает, тот Сам Себе Злобный Буратино. По-моему, всё равно более жёстко это обусловить невозможно, и если я не прав, то пусть более опытные в NET товарищи меня поправят. Это подразумевает, что пользователи Вашего враппера должны иметь флаг disposed, для нейтрализации попыток многократного вызова этого метода, но это, как я понял, нормально для NET. Впрочем, при желании для этого можно задействоовать и какое-нибудь nullable поле, хотя вряд-ли оно того стоит.
Да, вариант хорош... Через неделю попробую реализовать его и не связываться со сборщиком мусора...
А>Блин, отпуск — это хорошо, но неделя — это просто издевательство Не, я где-нибудь в середине или начале августа, по погоде, и — на месяц! Завалюсь в тайгу к другу и телефон выключу, всё одно там не примет!!!
Да я бы тоже уехал, да у нас студентов, лето — возможность поработать в два раза больше чем зимой
Неделя мало конечно, зато вообще никакой работы, как ты верно сказал — мобильник выключить
Если кому-нибудь будет интересно — реализовал через Dispose и непосредственный вызов его при закрытии формы...
Если чего-нибудь новое придумаю, отпишу тут...
Здравствуйте, DragonFire, Вы писали:
DF>День добрый всем.
Мы на эти грабли наступили когда тесты писали под MSный тест-фреймворк. Проблема получила кодовое название "отслоение сетчатки COM-объекта"
Лечили следующим образом. Т.к. в проблеммном коде COM-объект создается и финализируется на разных тредах, гарантируем его создание на MTAшном треде (после тред можно не держать, главное чтоб инстанс КОМ-объекта был на нем создан), после всего в диспозе все что нужно объекту сообщаем и ему дергаем диспоз чтобы финализатор GC не вызывался. Нам помогло.
Если руки золотые, не важно из какого места они растут.