Объявить метод всегда выдает исключение?
У меня есть такой метод, как...
int f() {
try {
int i = process();
return i;
} catch(Exception ex) {
ThrowSpecificFault(ex);
}
}
Это приводит к ошибке компилятора, "не все пути кода возвращают значение". Но в моем случае ThrowSpecificFault() всегда будет выбрасывать (соответствующее) исключение. Поэтому я вынужден поставить положительное значение в конце, но это уродливо.
Цель этого шаблона в первую очередь состоит в том, что "process()" - это вызов внешней веб-службы, но для перевода различных ожиданий интерфейса требуется перевести множество различных исключений (например, фасад-шаблон).
Какой-нибудь более чистый способ сделать это?
Ответы
Ответ 1
Я предлагаю вам преобразовать ThrowSpecificFault(ex)
в throw SpecificFault(ex)
; метод SpecificFault
возвращает объект исключения, который нужно выбросить, а не бросать его сам. Гораздо чище.
Это шаблон, рекомендованный Руководства Microsoft (найдите текст "Использовать методы построения исключений" ).
Ответ 2
Проблема здесь в том, что если вы войдете в блок catch
в f()
, ваша функция никогда не вернет значение. Это приведет к ошибке, потому что вы объявили свою функцию как int
, что означает, что вы сказали компилятору, что ваш метод вернет целое число.
Следующий код будет делать то, что вы ищете, и всегда возвращать целое число.
int f() {
int i = 0;
try {
i = process();
} catch(Exception ex) {
ThrowSpecificFault(ex);
}
return i;
}
поставьте оператор return в конце вашей функции, и все будет в порядке.
Всегда полезно обеспечить, чтобы ваш метод всегда возвращал значение независимо от пути выполнения вашего приложения.
Ответ 3
В настоящее время тип возвращаемого типа может быть типом, или "void", что означает "тип возврата". Мы могли бы теоретически добавить второй специальный тип возврата "никогда" , который имеет семантику, которую вы хотите. Конечная точка выражения, состоящая из вызова метода "никогда" , будет считаться недостижимой, и поэтому она будет легальной в каждом контексте на С#, в которой "goto", "throw" или "return" является законным,
Весьма маловероятно, что это будет добавлено к системе типов сейчас, через десять лет. В следующий раз, когда вы создаете систему типов с нуля, не забудьте включить тип "никогда" .
Ответ 4
Нет.
Представьте, если ThrowSpecificFault
были определены в отдельной DLL.
Если вы измените DLL, чтобы не генерировать исключение, тогда запустите свою программу, не перекомпилируя ее, что произойдет?
Ответ 5
Вы можете сделать следующее:
catch (Exception ex)
{
Exception e = CreateSpecificFault(ex);
throw e;
}
Ответ 6
У вас есть три варианта:
Всегда возвращайте i, но предварительно объявляйте его:
int f() {
int i = 0; // or some other meaningful default
try {
i = process();
} catch(Exception ex) {
ThrowSpecificFault(ex);
}
return i;
}
Вернуть исключение из метода и выбросить его:
int f() {
try {
int i = process();
return i;
} catch(Exception ex) {
throw GenerateSpecificFaultException(ex);
}
}
Или создайте собственный класс исключений и бросьте это:
int f() {
try {
int i = process();
return i;
} catch(Exception ex) {
throw new SpecificFault(ex);
}
}
Ответ 7
Как насчет:
int f() {
int i = -1;
try {
i = process();
} catch(Exception ex) {
ThrowSpecificFault(ex);
}
return i;
}
Ответ 8
Да.
Не ожидайте, что ThrowSpecificFault() выкинет исключение. Попросите его вернуть исключение, а затем выбросите его здесь.
На самом деле это тоже имеет смысл. Вы не используете исключения для "нормального" потока, поэтому, если вы каждый раз генерируете исключение, исключение становится правилом. Создайте конкретное исключение в функции и выбросите его здесь, потому что это исключение для потока здесь.
Ответ 9
Я полагаю, вы могли бы заставить ThrowSpecificFault вернуть объект, а затем вы могли бы
return ThrowSpecificFault(ex)
В противном случае вы можете переписать ThrowSpecificFault как конструктор для подтипа Exception или просто сделать ThrowSpecificFault в factory, который создает исключение, но не бросает его.
Ответ 10
В вашем случае, но это ваши знания не компилятора. Теперь можно сказать, что этот метод наверняка вызовет какое-то неприятное исключение.
Попробуйте это
int f() {
try {
return process();
} catch(Exception ex) {
ThrowSpecificFault(ex);
}
return -1;
}
Вы также можете использовать ключевое слово throw
int f() {
try {
return process();
} catch(Exception ex) {
throw ThrowSpecificFault(ex);
}
}
Но тогда этот метод должен возвращать некоторое исключение, а не бросать его.
Ответ 11
Используйте Unity.Interception для очистки кода. С обработкой перехвата ваш код может выглядеть так:
int f()
{
// no need to try-catch any more, here or anywhere else...
int i = process();
return i;
}
Все, что вам нужно сделать на следующем шаге, - это определить обработчик перехвата, который вы можете настроить для обработки исключений. Используя этот обработчик, вы можете обрабатывать все исключения, внесенные в ваше приложение. Поверхность заключается в том, что вам больше не нужно выделять весь код с помощью блоков try-catch.
public class MyCallHandler : ICallHandler, IDisposable
{
public IMethodReturn Invoke(IMethodInvocation input,
GetNextHandlerDelegate getNext)
{
// call the method
var methodReturn = getNext().Invoke(input, getNext);
// check if an exception was raised.
if (methodReturn.Exception != null)
{
// take the original exception and raise a new (correct) one...
CreateSpecificFault(methodReturn.Exception);
// set the original exception to null to avoid throwing yet another
// exception
methodReturn.Exception = null;
}
// complete the invoke...
return methodReturn;
}
}
Регистрация класса в обработчике может выполняться через файл конфигурации или программно. Код довольно прост. После регистрации вы создаете объекты с помощью Unity, например:
var objectToUse = myUnityContainer.Resolve<MyObjectToUse>();
Подробнее о Unity.Interception:
http://msdn.microsoft.com/en-us/library/ff646991.aspx