Чи можете ви вловити власний виняток у коді C #?


76

У коді C # ви можете зловити власний виняток, викинутий із глибини в якусь некеровану бібліотеку? Якщо так, чи потрібно щось робити по-іншому, щоб зловити його, або стандартна спроба ... зловити зрозуміти?

Відповіді:


35

Ви можете використовувати Win32Exception і використовувати його властивість NativeErrorCode для належної обробки.

// http://support.microsoft.com/kb/186550
const int ERROR_FILE_NOT_FOUND = 2;
const int ERROR_ACCESS_DENIED = 5;
const int ERROR_NO_APP_ASSOCIATED = 1155; 

void OpenFile(string filePath)
{
    Process process = new Process();

    try
    {
        // Calls native application registered for the file type
        // This may throw native exception
        process.StartInfo.FileName = filePath;
        process.StartInfo.Verb = "Open";
        process.StartInfo.CreateNoWindow = true;
        process.Start();
    }
    catch (Win32Exception e)
    {
        if (e.NativeErrorCode == ERROR_FILE_NOT_FOUND || 
            e.NativeErrorCode == ERROR_ACCESS_DENIED ||
            e.NativeErrorCode == ERROR_NO_APP_ASSOCIATED)
        {
            MessageBox.Show(this, e.Message, "Error", 
                    MessageBoxButtons.OK, 
                    MessageBoxIcon.Exclamation);
        }
    }
}

7
Я вважаю, що це не автоматично, а викидається лише тоді, коли ви використовуєте підпис P / Invoke, який його визначає. І це створюється на основі коду помилки Win32, а не винятку Win32.
Curt Hagenlocher

15

Зловити без () буде виявляти винятки, що не відповідають CLS, включаючи рідні винятки.

try
{

}
catch
{

}

Для отримання додаткової інформації див. Таке правило FxCop: http://msdn.microsoft.com/en-gb/bb264489.aspx


11
Так, це правда. Щойно виявив це сам після особливо прикрих кількох годин, проведених порівнянням файлів журналів та коду та думкою, що я їх втрачаю. Очевидне наступне питання, однак, чи можете ви визначити тип власного винятку з порожнього блоку catch? Чи можете ви записати що-небудь корисне для визначення джерела винятку?
Тайсон,

11

Рівень взаємодії між C # і власним кодом перетворить виняток у керовану форму, що дозволить його перехопити ваш код C #. Починаючи з .NET 2.0, catch (Exception)слід виявляти що-небудь, крім непоправної помилки.


3
У .NET 1.x можна створити виняток, який не походить від класу винятків, але ця можливість за замовчуванням вимкнена в 2.0
Curt Hagenlocher

4
У C ++ ви можете кидати будь-який об'єкт, тому для питань взаємодії корисно мати можливість ловити об'єкт, який не походить від винятку. Поширеним сценарієм є те, що програма C ++ видаватиме лише рядок (повідомлення про помилку).
MattDavey

5

Десь за допомогою .NET Reflector я бачив такий код:

try {
  ...
} catch(Exception e) {
  ...
} catch {
  ...
}

Хм, C # не дозволяє створювати виняток, що не походить від класу System.Exception. І, наскільки мені відомо, будь-яке кешування винятків за допомогою маршалера взаємодії обертається класом винятків, який успадковує System.Exception.

Отже, моє питання полягає в тому, чи можна вловити виняток, який не є System.Exception.


1
Можна випромінювати або створювати інший спосіб IL, який кидає довільний об'єкт. Компілятор C # не дозволяє вам це робити, але інші компілятори можуть, або, як я вже говорив, ви можете безпосередньо випромінювати IL. Оператор catch без типу захоплюватиме довільні об'єкти, а також об'єкти, що успадковують Exception.
технофіл

5

Це залежить від типу рідного винятку, про який ви говорите. Якщо ви маєте на увазі виняток SEH, то CLR зробить одне з двох.

  1. У випадку відомого коду помилки SEH він буде відображати його у відповідний виняток .Net (тобто OutOfMemoryException)
  2. У випадку, якщо неможливо відобразити (E_FAIL) або невідомий код, він просто викине екземпляр SEHException .

Обидва вони будуть спіймані простим блоком "catch (Exception)".

Іншим типом власного винятку, який може перейти границю власного / керованого, є винятки C ++. Я не впевнений, як вони відображаються / обробляються. Я припускаю, що оскільки Windows впроваджує винятки C ++ поверх SEH, вони просто відображаються однаково.


Windows implements C++ exceptions on top of SEH- здається, це справедливо лише для ВК?
Вовк

3

Майже, але не зовсім. Ви знайдете виняток з

try 
{
  ...
}
catch (Exception e)
{
  ...
}

але у вас все одно будуть потенційні проблеми. Згідно з MSDN , для того, щоб забезпечити виклик деструкторів викликів, вам доведеться ловити, як:

try
{
  ...
}
catch
{
  ...
}

Це єдиний спосіб забезпечити виклик деструктора винятків (хоча я не впевнений, чому). Але це залишає вам компроміс грубої сили проти можливого витоку пам’яті.

До речі, якщо ви використовуєте підхід (Виняток e), вам слід знати різні типи винятків, з якими ви можете зіткнутися. RuntimeWrappedException - це те, до чого буде відображено будь-який керований тип без винятку (для мов, які можуть створювати рядок), а інші - як OutOfMemoryException та AccessViolationException. COM Interop HRESULTS або винятки, крім E___FAIL, відображатимуться на COMException, і, нарешті, наприкінці ви отримаєте SEHException для E_FAIL або будь-яке інше некартоване виняток.

То що ти повинен робити? Найкращий вибір - не викидати виключення зі свого некерованого коду! Ха-ха. Насправді, якщо у вас є вибір, встановіть бар'єри та невдачі, які роблять вибір, який гірший, шанс витоку пам'яті під час обробки винятків або невідомість, яким типом є ваш виняток.


-1

Я вважаю, що звичайний спробу улову повинен зробити трюк.

Я стикаюся з подібною проблемою з винятком System.data, кидаючи вилучення sqlClient, яке не було зафіксовано, додавши try..catch до мого коду.


-2

Якщо ви використовуєте

try
{

}
catch(Exception ex)
{

}

він захопить ВСІ винятки, залежно від того, як ви викликаєте зовнішні бібліотеки, ви можете отримати виняток, пов’язаний із ком, який інкапсулює помилку, але помилку виявить.


Ви не можете зловити StackOverflow або OutOfMemoryException, хоча, незважаючи ні на що, правильно?
ядро

це закінчуючі помилки, які зупиняють роботу програми, тому так, ви не можете з ними працювати.
Мітчел Селлерс

7
Насправді це не зовсім правильно, це враховуватиме всі винятки, сумісні з CLS. C ++ / CLI та MC ++ - обидві мови, які можуть створювати винятки, що не відповідають CLS.
Peter Oehlert

1
Я згоден з Пітером, я працюю з некерованими бібліотеками DLL, і я не можу вловити деякі винятки.
Тілендор

20
Станом на момент написання цього коментаря, це запитання має 17 голосів „за” і 7 “прихильників”, тож це, очевидно, проблема, яка трапляється з людьми, і я думаю, що люди спробують простий блок catch, перш ніж вдаватися до SO. Я особисто бачив, як винятки вибухають прямо через конструкцію, яку ви пропонуєте, коли вони походять від некерованих залежностей. Я вважаю, що ця відповідь не правильна.
JohnFx
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.