Як використовувати ключове слово в стилі Java в C #?


91

У Java throwsключове слово дозволяє методу заявити, що він не буде обробляти виняток самостійно, а скоріше перекинути його на викличний метод.

Чи є подібне ключове слово / атрибут у C #?

Якщо немає еквівалента, як можна досягти того самого (або подібного) ефекту?

Відповіді:


78

У Java ви повинні або обробити виняток, або позначити метод як такий, який може викликати його за допомогою throwsключового слова.

У C # немає цього ключового слова або еквівалентного ключового слова, як у C #, якщо ви не обробляєте виняток, воно буде спливати, доки його не зловлять або, якщо його не зловлять, припинить програму.

Якщо ви хочете впоратися з цим, то повторне кидання ви можете зробити наступне:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}

1
"це буде бульбашкою", чи означає це, що це еквівалентно всім методам, що мають пропозицію throws у Java?
Луїс Ріс,

1
@Louis RH - вид. Це означає, що виняток, якщо його не обробити, буде підніматися по ланцюжку викликів через кожну викличну функцію до обробки.
Оді

1
@Louis RH не повністю, це означало б, що для компіляції коду вам потрібно було вловити виняток принаймні у вас Main. Оскільки C # не знає перевірених винятків, вам потрібно їх зловити, інакше вони просто потраплять під час виконання та переривають ваш код.
Йоганнес Вахтер,

1
@jwatcher: основний метод також може мати застереження.
Луїс Ріс,

4
@AshishKamble - ага. Питання думки. Обробка винятків відрізняється в .NET. Не припускайте, що знаєте, що «краще».
Оді

107

Оператор запитує про еквівалент C # throwsречення Java, а не про throwключове слово. Це використовується в підписах методів на Java, щоб вказати, що перевірений виняток може бути створений.

У C # немає прямого еквівалента виключення, перевіреного Java. C # не має еквівалентного пункту підпису методу.

// Java - need to have throws clause if IOException not handled
public void readFile() throws java.io.IOException {
  ...not explicitly handling java.io.IOException...
}

перекладає на

// C# - no equivalent of throws clause exceptions are unchecked
public void ReadFile() 
{
  ...not explicitly handling System.IO.IOException...
}

30

Так, це стара тема, однак я часто знаходжу старі теми, коли шукаю відповіді, тому я вирішив додати щось корисне, що знайшов.

Якщо ви використовуєте Visual Studio 2012, є вбудований інструмент, який можна використовувати для забезпечення рівня "кидків" рівня IDE.

Якщо ви використовуєте коментарі до документації XML , як уже згадувалося вище, тоді ви можете використовувати тег <exception>, щоб вказати тип винятку, який створюється методом або класом, а також інформацію про те, коли і чому він викидається.

приклад:

    /// <summary>This method throws an exception.</summary>
    /// <param name="myPath">A path to a directory that will be zipped.</param>
    /// <exception cref="IOException">This exception is thrown if the archive already exists</exception>
    public void FooThrowsAnException (string myPath)
    {
        // This will throw an IO exception
        ZipFile.CreateFromDirectory(myPath);
    }

4
ОП, це ваша відповідь. Я здогадуюсь, але JAVA, throwsймовірно, нічого не означає для середовища виконання, крім інформативності для розробника. Подібним чином, те, на що вказав тут @mvanella, - це спосіб C # зробити абсолютно те саме. Я припускаю, ви вже знаєте, що ця "xml-документація" має більш важливу мету. Я знаю, що ця нитка стара.
Харі Любовац

Насправді Java не створює винятків, якщо це явно не вказано в throwsпункті або не викликано throwкомандою. Це означає, що якщо RunTimeException трапляється і не обробляється тим самим методом, де це відбувається, виконання на цьому зупиниться.
Педро Ліма

18

Ось відповідь на подібне запитання, яке я щойно знайшов на bytes.com :

Коротка відповідь - ні. У C # немає перевірених винятків. Дизайнер мови обговорює це рішення в цьому інтерв’ю:

http://www.artima.com/intv/handcuffs.html

Найближче, що ви можете отримати, - це використовувати теги у вашій XML-документації та розповсюджувати згенеровані NDoc документи разом із вашим кодом / збірками, щоб інші люди могли бачити, які винятки ви кидаєте (що саме MS робить у документації MSDN). Ви не можете розраховувати на те, що компілятор повідомляє вам про необроблені винятки, однак, як ви звикли до Java.


7

Ознайомившись із більшістю відповідей тут, я хотів би додати пару думок.

  1. Покладатися на коментарі до документації XML і сподіватися, що інші покладаються - поганий вибір. Більшість кодів C #, з якими я стикався, не документують методи повністю та узгоджено з коментарями до документації XML. І тоді є ще більша проблема, яка полягає у тому, що без перевірених винятків у C #, як ви можете задокументувати всі винятки, які створює ваш метод для того, щоб користувач вашого API знав, як обробляти їх усі окремо? Пам'ятайте, ви знаєте лише про тих, кого кидаєте за допомогою ключового слова throw у своїй реалізації. API, які ви використовуєте всередині вашої реалізації методу, можуть також видавати винятки, про які ви не знаєте, оскільки вони можуть не бути задокументованими, і ви не обробляєте їх у своїй реалізації, тому вони підірвуться перед абонентом вашого метод. Іншими словами,

  2. Андреас пов’язав інтерв’ю з Андерсом Хейлсбергом у відповідях тут, чому команда дизайнерів C # вирішила не перевіряти винятки. Остаточна відповідь на вихідне запитання прихована в цьому інтерв’ю:

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

Іншими словами, нікого не повинно цікавити, який виняток можна очікувати для певного API, оскільки ви завжди збираєтеся вловити їх усі скрізь. І якщо ви хочете по-справжньому піклуватися про певні винятки, як їх обробляти, вирішувати вам, а не тому, хто визначає підпис методу чимось на кшталт Java кидає ключове слово, змушуючи конкретну обробку винятків для користувача API.

-

Особисто я тут розірваний. Я згоден з Андерсом, що перевірка винятків не вирішує проблему без додавання нових, інших проблем. Як і в коментарях до документації XML, я рідко бачу код C # з усім, що загорнуто в блоки блоку try. Мені здається, що це справді ваш єдиний варіант і щось, що здається гарною практикою.


3

Насправді, не перевіривши винятки в C #, можна вважати хорошим чи поганим явищем.

Я сам вважаю це хорошим рішенням, оскільки перевірені винятки створюють такі проблеми:

  1. Технічні винятки просочуються до рівня бізнесу / домену, оскільки ви не можете належним чином обробити їх на низькому рівні.
  2. Вони належать до підпису методу, який не завжди грає добре з дизайном API.

Через це в більшості великих додатків ви часто бачите такий шаблон, коли відзначаються винятки:

try {
    // Some Code
} catch(SomeException ex){
    throw new RuntimeException(ex);
}

Що, по суті, означає емуляцію способу обробки C # /. NET усіх винятків.


Я не уявляю, як перевірені винятки змішуються з лямбдами!
Гейб

@Gabe: Я впевнений, що ти міг би придумати якусь концепцію, яка дозволяє їх змішувати, але, як я вже сказав, перевірені винятки в Java також переважно не є гарною практикою, особливо в більш складних додатках. Тож добре, що їх там немає в C #.
Йоханнес Вахтер,

3

Ви запитуєте про це:

Повторне кидання винятку

public void Method()
{
  try
  {
      int x = 0;
      int sum = 100/x;
  }
  catch(DivideByZeroException e)
  {
      throw;
  }
}

або

static void Main() 
    {
        string s = null;

        if (s == null) 
        {
            throw new ArgumentNullException();
        }

        Console.Write("The string s is null"); // not executed
    }

3
+1 за використання throw. За його використання трасування стека не загубиться.
Джузеппе Аккапуто

2

Існує деяка швидкоплинна схожість між .Net CodeContract EnsuresOnThrow<>та throwsдескриптором Java , оскільки обидва вони можуть сигналізувати абоненту як тип винятку, який може бути викликаний функцією або методом, хоча між двома також є великі відмінності:

  • EnsuresOnThrow<>виходить за рамки простої заяви про те, які винятки можна кинути, але також передбачає умови, за яких вони гарантовано будуть викинуті - це може бути досить обтяжливим кодом у викликаному методі, якщо умова виключення не є тривіальною для ідентифікації. Java throwsнадає вказівку, які винятки можуть бути кинуті (тобто IMO фокус у .Net знаходиться всередині методу, який контрактує на доведення throw, тоді як у Java фокус переходить до того, хто викликає, щоб визнати можливість винятку).
  • .Net CC не робить різниці між перевіреними та неперевіреними винятками, які має Java, хоча у розділі 2.2.2 керівництва CC зазначено

"використовувати виключні постумови лише для тих винятків, на які абонент повинен очікувати як частина API"

  • У .Net абонент може визначити, чи робити що-небудь за винятком (наприклад, відключаючи контракти). У Java абонент повинен щось зробити , навіть якщо він додає throwsдля того самого винятку на своєму інтерфейсі.

Код контрактів тут


0

Якщо метою методу c # є лише виняток (як каже тип повернення js), я б рекомендував просто повернути цей виняток. Див. Приклад нижче:

    public EntityNotFoundException GetEntityNotFoundException(Type entityType, object id)
    {
        return new EntityNotFoundException($"The object '{entityType.Name}' with given id '{id}' not found.");
    }

    public TEntity GetEntity<TEntity>(string id)
    {
        var entity = session.Get<TEntity>(id);
        if (entity == null)
            throw GetEntityNotFoundException(typeof(TEntity), id);
        return entity;
    }


-1

Для тих, хто цікавиться, вам навіть не потрібно визначати, що ви ловите, щоб передати це наступному методу. Якщо ви хочете, щоб усі ваші помилки оброблялися в одному основному потоці, ви можете просто вловити все і передати це так:

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}

Будь ласка, внесіть деякі зміни у відповідь. Я випадково натиснув -1. Я не можу його видалити, поки ви не внесете жодних змін.
проксимаб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.