Поведение исключений внутри делегатов в C # 2, размещенных в MS Excel и COM - PullRequest
3 голосов
/ 17 октября 2008

Утро всем,

Здесь немного вопросов теории языка ... Я нашел в Интернете некоторые ссылки, предполагающие, что в некоторых случаях обработка исключений и делегаты в C # ведут себя по-разному, но я не могу найти какую-либо конкретную документацию по этому вопросу.

У нас недавно были некоторые большие проблемы с исключениями внутри делегатов для надстройки Microsoft Excel, вызывающими серьезный сбой во время выполнения MSVC. Удаление делегатов решило эту проблему, но теперь мне любопытно узнать подробности.

В качестве краткого примера кода ядра:

Delegate del; // initialized elsewhere
try
{
    del.DynamicInvoke();
}
catch(Exception e)
{
    /* Parsing of exception to generate user-friendly message here */
}

Приведенная выше конструкция допускала централизованную форму обработки ошибок и с точки зрения чистого кода была чистой и лаконичной. Каждая общедоступная функция была объявлена ​​как делегат и выполнена с помощью приведенного выше фрагмента.

В простом консольном приложении генерирование исключения из делегата или просто непредвиденная ошибка (например, «случайно» вызов ToString () для нулевого указателя) работает должным образом, и ошибка обрабатывается по желанию.

Добавьте MS Excel, и вы получите серьезные сбои. Пошаговое выполнение кода покажет, где произошла ошибка, но раскручивание стека no , по-видимому, происходит до того, как все рухнет в большой огненный шар разрушения.

Моя гипотеза состоит в том, что COM, размещающий среду выполнения .NET (и, следовательно, наш код), делает что-то отличное от нормального выполнения кода .NET. Это убивает конечную точку, и Excel не знает этого, который, в свою очередь, пытается получить доступ к конечной точке через COM, только чтобы обнаружить, что она каким-то образом исчезла, а Excel выдает ответную реакцию.

Это происходит только с комбинацией делегатов Excel + COM +, но я честно не знаю, что является наиболее влиятельным в этом поведении ... какие-либо мысли?

Ответы [ 4 ]

1 голос
/ 19 октября 2008

Я думаю, что вы можете найти здесь, что вы не выпускаете COM-объекты MS Excel, которые вы неявно создаете, когда выдается исключение. По моему опыту приложения MS Office очень чувствительны к тому, что их ресурсы не выпускаются (хотя большая часть моего опыта связана с Outlook).

Я бы не пытался обрабатывать исключения на основе COM таким способом, если это вообще возможно. Если вы хотите централизованное ведение журнала, посмотрите вместо этого Application.ThreadException (для приложения WinForms) и AppDomain.CurrentDomain.UnhandledException.

Внутри ваших функций вы можете вызывать Marshal.ReleaseComObject () в ваших блоках метода finally {}, чтобы убедиться, что Excel не скрывается при возникновении исключений.

0 голосов
/ 16 февраля 2009

Одна причина, по которой я чувствую, связана с тем, что делегат вызывает реальный код, который вызывает исключение в другом потоке. таким образом, исключение в другом потоке, которое было названо асинхронным, не будет перехвачено в текущем потоке, так как функция текущего потока в основном завершится до выполнения асинхронного вызова.

0 голосов
/ 21 октября 2008

Извиняюсь за поздний ответ - занятая неделя!

Вся идея перехвата исключений состоит не в том, чтобы «проглотить» их и отобразить сообщение об ошибке, а в том, чтобы восстановить, если возможно, ситуацию, а также очистить ресурсы.

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

Всегда ли это происходит?

Да, если это непредвиденное исключение и оно всегда отображается как .NET, происходящее из кода C # /. NET

создать простой метод, который просто генерирует исключение (throw new ApplicationException ();) и проверяет, не возникла ли у вас проблема?

Нет, выбрасывание наших собственных исключений прекрасно работает каждый раз. Только если сама среда выполнения генерирует исключение, мы получаем серьезные сбои.

вы не выпускаете COM-объекты MS Excel, которые вы неявно создаете при возникновении исключения

Это звучит правдоподобно. Слой VBA передает данные из Excel через COM и в .NET, поэтому он вполне может делать что-то необычное с владением ресурсами.

Если вы хотите централизованное ведение журнала, посмотрите вместо этого Application.ThreadException (для приложения WinForms) и AppDomain.CurrentDomain.UnhandledException.

Я не заглядывал в первое, но второе никогда бы не вызвали. Одной из моих первых попыток было поймать его на уровне AppDomain, предполагая, что по какой-то причине исключение на основе делегата проскальзывало по сети.

вы можете позвонить маршалу. ReleaseComObject ()

Интересно, я не знал об этой функции. Мы в основном игнорировали любой явный COM-код и ушли с самого минимума и надеемся (!), Что .NET CLR делает свое волшебство ...

Я обошел это сейчас, удалив делегатов, и все кажется счастливым. Просто нужно помнить, чтобы быть осторожными (или полностью избегать) делегатов и исключений в будущем Office + VBA + COM + CLR код: -)

0 голосов
/ 17 октября 2008

Примечание: Вся идея перехвата исключений состоит не в том, чтобы «проглотить» их и отобразить сообщение об ошибке, а в том, чтобы по возможности восстановить ситуацию и очистить ресурсы.

Лучше использовать try / catch везде, где вам нужно (т. Е. Вокруг кода, который может выдать), а затем вызывать общую функцию для отображения / регистрации проблемы.

Кроме того, если вы используете разные потоки для доступа к объектам Excel COM, может произойти много странных вещей.

Для правильного ответа на ваш вопрос необходима дополнительная информация:

  1. Всегда ли это происходит?
  2. Если нет, то, когда вы видите проблему, это управляемое исключение или одно исключение из объекта Excel?
  3. Можете ли вы создать простой метод, который просто генерирует исключение (throw new ApplicationException ();) и проверяет, не возникла ли у вас проблема?

Приветствия

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...