.NET: проблема с повышением и обработкой использования событий AppDomains

Использование Objective C Подсчет ссылок , что означает каждый Объект, имеет подсчет ссылок. Когда объект создается, он имеет подсчет ссылок "1". Просто разговор, когда объект упомянут (т.е., сохраненный где-нибудь), он "сохраняется", что означает, что его подсчет ссылок увеличен одним. Когда объект больше не необходим, он "выпущен", что означает, что его подсчет ссылок уменьшен одним.

, Когда подсчет ссылок объекта 0, объект освобожден. Это - основной подсчет ссылок.

Для некоторых языков, ссылки автоматически увеличены и уменьшены, но цель-c не является одним из тех языков. Таким образом программист ответственен за сохранение и выпуск.

А типичный способ записать метод:

id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;

проблема необходимости не забыть высвобождать любые полученные средства в коде и утомительна и подвержена ошибкам. Objective C представляет другое понятие, нацеленное на создание этого намного легче: Пулы автовыпуска. Пулы автовыпуска являются специальными объектами, которые установлены на каждом потоке. Они - довольно простой класс, если Вы ищете NSAutoreleasePool.

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

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

id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;

, поскольку объект автовыпущен, мы больше не должны явно называть "выпуск" на нем. Это вызвано тем, что мы знаем, что некоторый пул автовыпуска сделает это для нас позже.

, Надо надеяться, это помогает. Статья Wikipedia довольно хороша о подсчете ссылок. Больше информации приблизительно пулы автовыпуска может быть найдено здесь . Также обратите внимание, что, если Вы создаете для Mac OS X 10.5 и позже, можно сказать, что XCode для создания с включенной сборкой "мусора", позволяя Вам полностью проигнорировать сохраняет/выпускает/автовыпускает.

8
задан Rob Sobers 14 August 2009 в 00:21
поделиться

2 ответа

В своей первой попытке решить эту проблему я удалил Class B наследование MarshalByRefObject и вместо этого пометил его как сериализуемый. В результате объект был упорядочен по значению, и я только что получил копию Class C , которая выполняется в главном домене приложений. Это не то, что я хотел.

Реальное решение, которое я обнаружил, заключалось в том, что класс B ( DangerousProgram в примере) также должен наследовать от MarshalByRefObject так что обратный вызов также использует прокси для перехода потока обратно в домен приложения по умолчанию.

Кстати, вот отличная статья , которую я нашел Эриком Липпертом, которая объясняет маршал by ref vs. marshal by value очень умным способом.

5
ответ дан 3 November 2019 в 12:50
поделиться

Магия событий .NET скрывает тот факт, что, когда вы подписываетесь на событие в экземпляре B экземпляром A, A отправляется в домен приложения B. Если A не является MarshalByRef, то отправляется копия значения A. Теперь у вас есть два отдельных экземпляра A, поэтому вы столкнулись с неожиданным поведением.

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

Чтобы вызывать «события» в B (в домене приложения 2) и обрабатывать их в A (в домене приложения 1) без использования реальных событий, нам нужно создать второй объект, который переводит вызовы методов (которые пересекают границы без много шума) к событиям (которые ведут себя не так, как вы могли бы ожидать). Назовем этот класс X, будет создан в домене приложения 1, а его прокси будет отправлен в домен приложения 2. Вот код:

public class X : MarshalByRefObject
{
  public event EventHandler MyEvent;
  public void FireEvent(){ MyEvent(this, EventArgs.Empty); }
}

Псевдокод будет выглядеть примерно так:

  1. A , внутри AD1 , создает новый домен приложения. Назовите его AD2 .
  2. A вызывает CreateInstanceAndUnwrap на AD2 . B теперь существует в AD2 и B (прокси) существует в AD1 .
  3. A создает экземпляр X .
  4. A передает X на B (прокси)
  5. В AD2 , ] B теперь имеет экземпляр X (прокси) ( X is MBRO )
  6. В AD1 , регистрирует обработчик событий с помощью X. MyEvent
  7. В AD2 , B вызывает X (прокси) .FireEvent ()
  8. В AD1 , FireEvent выполняется на X , в результате чего запускается обработчик событий MyEvent
  9. A для FireEvent.

Для B для запускать событие обратно в AD1 , он должен иметь не только метод, но и экземпляр для запуска этого метода. Вот почему мы должны отправить прокси X в AD2 . Это также , почему междоменные события требуют, чтобы обработчик событий был упорядочен через границу домена! Событие - это просто причудливая оболочка для выполнения метода. И для этого вам понадобится не только метод, но и экземпляр, на котором он будет выполняться.

31
ответ дан 3 November 2019 в 12:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: