Как использовать ключевое слово throws в стиле 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 - вроде как. Это означает, что исключение, если оно не обработано, будет подниматься по цепочке вызовов через каждую вызывающую функцию до тех пор, пока не будет обработано.
Oded
1
@Louis RH не полностью, это означало бы, что вам нужно было поймать исключение, по крайней мере, в вашем Main, чтобы скомпилировать код. Поскольку C # не знает проверенных исключений, вы должны их поймать, иначе они просто появятся во время выполнения и прервут ваш код.
Йоханнес Вахтер,
1
@jwatcher: у основного метода также может быть предложение throw.
Луи Рис,
4
@AshishKamble - а. Основное мнение. В .NET обработка исключений отличается . Не думайте, что знаете, что «лучше».
Oded
109

Оп просим о C # эквивалента в Java throwsстатей - а не 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...
}
serg10
источник
30

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

Если вы используете 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-документация» имеет более важное назначение. Я знаю, что эта ветка старая.
Hari Lubovac
Фактически, 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 # решила не использовать проверенные исключения. Окончательный ответ на исходный вопрос скрыт в этом интервью:

Программисты защищают свой код, написав повсюду try finally, поэтому они будут корректно отступать, если произойдет исключение, но на самом деле они не заинтересованы в обработке исключений.

Другими словами, никого не должно интересовать, какого рода исключение можно ожидать для конкретного API, поскольку вы всегда будете ловить их все повсюду. И если вы действительно хотите заботиться о конкретных исключениях, то как их обрабатывать зависит от вас, а не от кого-то, кто определяет сигнатуру метода с помощью чего-то вроде ключевого слова Java throws, вынуждая пользователя API обрабатывать определенные исключения.

-

Лично я тут рвусь. Я согласен с Андерсом в том, что проверка исключений не решает проблему без добавления новых, других проблем. Как и в случае с комментариями XML-документации, я редко вижу код C #, в котором все заключено в блоки try finally. Мне кажется, что это действительно ваш единственный вариант и что-то вроде хорошей практики.

Тобиас
источник
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 не делает различий между исключениями Checked и Unchecked, которые есть в Java, хотя в разделе 2.2.2 руководства CC упоминается, что

"использовать исключительные постусловия только для тех исключений, которые вызывающий должен ожидать как часть API"

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

Руководство по кодовым контрактам здесь

StuartLC
источник
0

Если цель метода С # состоит в том, чтобы генерировать исключение (как говорит тип возврата 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. Я не могу удалить его, пока вы не внесете никаких изменений.
проксимаб