Работе с COM-исключений / занят кодов


Этот код записывает в Excel с помощью com-интерфейса. Общий вопрос заключается в том, что любая обработка исключений для обработки "Excel-это занят" исключение. Это происходит, если информация передается в Excel быстрее, чем он может справиться - например. задержки при загрузке книги/создан, или пользователь играет с полосами прокрутки (есть веские причины за то, что позволил этому случиться).

Это, пожалуй, единственный пример, который я знаю, что это проще и чище, чем на VB6 в C#! На VB6 на ошибки будет использоваться. Затем обработчик ошибки могут привести к ошибке в большинстве случаев. Но если код ошибки "занят", то он будет спать в короткий промежуток времени (обычно за полсекунды) и потом снова попробовать с "резюме". Не поймите меня неправильно, по ошибке, как правило, грязнее, чем на C#'ы попробовать...поймать и легче произвести ужасный код, однако, это один из примеров, где в VB6 на ошибок работает лучше. Длинной последовательности в Excel звонки могут быть перехвачены с одним обработчиком. "Продолжить", затем вышлем управления обратно к той черте, где "занято" произошло - это позволяет избежать дублирования вызовов или пропущенных вызовов.

Решение у меня в C# создать цикл while с флагом. Флаг указывает повторения цикла необходимо из-за "занятых" возвращение из Excel. См. ниже код.

Есть более простой, более элегантный способ сделать это? Основная проблема заключается в том, что этого требует метод для каждого типа вызова в формате Excel. Чтобы избежать слишком много повторяющихся Excel вызывает в напряженный сценарий, содержание каждого метода атомной или близкой к атомно - напр. "написать это форматированное значение"; "применить форматирование к строке". Это приводит к большим количеством методов. И/или методов с большим количеством параметров (в примере ниже-один единственный вариант формата, но может быть и больше - цветов, десятичных точек и т. д.).

private void WriteDoubleValue(Excel.Worksheet sh, int x, int y, double lfval, bool bBold)
{
    bool bNotSuccess = true;
    while (bNotSuccess)
    {
        try
        {
            ((Excel.Range)sh.Cells[y,x]).set_Value(Missing.Value, lfval);
            ((Excel.Range)sh.Cells[y, x]).Font.Bold = bBold;
            bNotSuccess = false;
        }

        catch (System.Runtime.InteropServices.COMException e)
        {
            if ((e.ErrorCode & 0xFFFF) == 0xC472)
            {   // Excel is busy
                Thread.Sleep(500); // Wait, and...
                bNotSuccess = true;  // ...try again
            }
            else
            {   // Re-throw!
                throw e;
            }
        }
    }
}


9881
6
задан 3 февраля 2011 в 02:02 Источник Поделиться
Комментарии
2 ответа

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

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

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

Я также рекомендую сделать типа bool переменная положительна (т. е. успех вместо notSuccess). Таким образом людям не придется выполнять двойное отрицание в голову при чтении таких вещей, как notSuccess = ложные (который будет изменен на успех = истина).

С этими предложениями код может выглядеть так:

private void TryUntilSuccess(Action action)
{
bool success = false;
while (!success)
{
try
{
action();
success = true;
}

catch (System.Runtime.InteropServices.COMException e)
{
if ((e.ErrorCode & 0xFFFF) == 0xC472)
{ // Excel is busy
Thread.Sleep(500); // Wait, and...
success = false; // ...try again
}
else
{ // Re-throw!
throw e;
}
}
}
}

Вы могли бы затем реализовать WriteDoubleValue и все способы, как это с призывом TryUntilSuccess такой:

TryUntilSuccess( () =>
{
((Excel.Range)sh.Cells[y,x]).set_Value(Missing.Value, lfval);
((Excel.Range)sh.Cells[y, x]).Font.Bold = bBold;
});

7
ответ дан 3 февраля 2011 в 03:02 Источник Поделиться

При повторной генерации исключения не указать на исключение или выбросить новое исключение со старым как внутреннее исключение, иначе вы замените трассировку стека исключений с линии броска в catch блок, который будет препятствовать вам увидеть, какие строки в блоке try вызвала исключение. Я предполагаю, что вы используете это во многих местах? Я рефакторингу проверить ошибки, но код sepp2k это способствует повышению уровня повторного использования рисунка в целом. До сих пор, а вот немного более эффективной и короче осуществления контроля петли себя в случае, если вы более комфортно с ним. Гибрид двух, вероятно, ваш лучший ставку.

private void WriteDoubleValue(Excel.Worksheet sh, int x, int y, double lfval, bool bBold)
{
bool retry = false;
do
{
try
{
((Excel.Range)sh.Cells[y,x]).set_Value(Missing.Value, lfval);
((Excel.Range)sh.Cells[y, x]).Font.Bold = bBold;
retry = false;
}
catch (System.Runtime.InteropServices.COMException e)
{
if (retry = e.ShouldRetry())
{ // Excel is busy
Thread.Sleep(500); // Wait, and...
}
else throw;
//calling throw without a param *rethrows*
//which is important to preserve the stack trace
}
} while (retry);
}

private void ShouldRetry(this COMException e) {
return ((e.ErrorCode & 0xFFFF) == 0xC472);
}

3
ответ дан 3 февраля 2011 в 05:02 Источник Поделиться