Должен ли управляемый код возвращать ошибку или создавать исключения для неуправляемого кода? - PullRequest
5 голосов
/ 07 мая 2009

Я собираюсь предоставить сервис, написанный на C #, старому приложению C ++ с использованием COM Как лучше всего сообщать об ошибках неуправляемому клиенту? Выдает исключение или просто возвращает значение ошибки?

Спасибо, Stefano

Ответы [ 5 ]

10 голосов
/ 08 мая 2009

Вы должны бросить исключения. Исключения отображаются в HRESULTS платформой, а HRESULT - это стандартный способ возврата ошибок COM-клиентам, так что это путь.

Каждый тип исключения имеет свойство HResult. Когда управляемый код, вызываемый из COM-клиента, генерирует исключение, среда выполнения передает HResult COM-клиенту. Если вам нужны специфичные для приложения коды HRESULT, вы можете создать свои собственные типы исключений и установить свойство Exception.HResult .

Следует отметить, что информация стека вызовов будет потеряна, когда исключение будет выдано COM-клиенту. Поэтому может быть хорошей идеей регистрировать исключения перед распространением на COM-клиент.

Одна техника, которую я иногда использую, заключается в следующем: явная реализация интерфейса ComVisible для COM-клиентов, который регистрирует и перебрасывает исключения. COM-клиенты используют интерфейс ComVisible, который регистрирует исключения перед их распространением. Клиенты .NET используют конкретный класс и, как ожидается, сами примут меры для обработки исключений. Писать немного скучно, но это может пригодиться, когда вы впоследствии решите проблему.

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

Пример:

[
ComVisible(true),
GuidAttribute("..."),
Description("...")
]
public interface IMyComVisibleClass
{
    // Text from the Description attribute will be exported to the COM type library.

    [Description("...")]
    MyResult MyMethod(...);

    [Description("...")]
    MyOtherResult MyArrayMethod([In] ref int[] ids,...);
}
...
[
ComVisible(true),
GuidAttribute("..."),
ProgId("..."),
ClassInterface(ClassInterfaceType.None),
Description("...")
]
public class MyComVisibleClass : IMyComVisibleClass
{
    public MyResult MyMethod(...)
    {
        ... implementation without exception handling ...
    }

    public MyOtherResult MyArrayMethod(int[] ids,...)
    {
        ... input parameter does not use ref keyword for .NET clients ...
        ... implementation without exception handling ...
    }

    MyResult IMyComVisibleClass.MyMethod(...)
    {
        // intended for COM clients only
        try
        {
            return this.MyMethod(...);
        }
        catch(Exception ex)
        {
            ... log exception ...
            throw;   // Optionally wrap in a custom exception type
        }
    }

    MyOtherResult IMyComVisibleClass.MyArrayMethod(ref int[] ids, ...)
    {
        // intended for COM clients only
        try
        {
            // Array is passed without ref keyword
            return this.MyArrayMethod(ids, ...);
        }
        catch(Exception ex)
        {
            ... log exception ...
            throw;   // Optionally wrap in a custom exception type
        }
    }

}
3 голосов
/ 07 мая 2009

Я согласен с другими, что это не ответ «да или нет», не зная вашего проекта.

Это будет зависеть от ряда факторов, таких как:

  • Безопасность (т. Е. Что должен знать ваш клиент о вашем исключении)
  • Эффективность (т. Е. Время обработки критично)
  • Поддержка (т. Е. Можете ли вы изменить унаследованный код C ++ для анализа условий исключений)

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

Автор рекомендует один из двух подходов:

Или:

  • Вернуть документ об ошибке.

или

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

Лично я считаю, что вам следует избегать тесной связи службы C # с приложением C ++. Другими словами, напишите свой сервис на C #, чтобы теоретически его мог использовать любой потребитель. Аналогично, ваш код C ++ должен быть написан так, чтобы он не зависел от внутренней работы службы C #, поэтому изменения или дополнения в исключениях (или кодах ошибок) не нарушают потребителя.

3 голосов
/ 07 мая 2009

Если ваше COM-приложение поддерживает интерфейсы IErrorInfo при вызове в службу C # и является полностью внутренним проектом, то, вероятно, лучшим выбором будет выбрасывание исключений, поскольку оно собирает большую часть информации. Тем не менее, COM традиционно полагался на результаты HR в сообщении результатов статуса и может быть лучше, если услуга будет опубликована в других источниках.

РЕДАКТИРОВАТЬ: Мне больше нравится ответ Джо.

1 голос
/ 07 мая 2009

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

1 голос
/ 07 мая 2009

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

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

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