2010-10-08 2 views
15

У меня есть метод, как ...Объявление метода всегда вызывает исключение?

int f() { 
    try { 
    int i = process(); 
    return i; 
    } catch(Exception ex) { 
    ThrowSpecificFault(ex); 
    } 
} 

Это приводит к ошибке компиляции, «не все пути кода возвращает значение». Но в моем случае ThrowSpecificFault() всегда будет выбрасывать (соответствующее) исключение. Поэтому я вынужден поставить положительную ценность в конце, но это уродливо.

Цель этого шаблона в первую очередь состоит в том, что «process()» - это вызов внешней веб-службы, но для перевода различных ожиданий интерфейса необходимо использовать различные исключения, например, ,

Любой чистый способ сделать это?

+1

Связано: [Есть ли стандартный атрибут «никогда не возвращается» для функций C#?] (Http://stackoverflow.com/questions/1999181/is-there-a-standard-never-returns-attribute-for-c -функции) –

ответ

47

Я предлагаю вам конвертировать ThrowSpecificFault(ex) в throw SpecificFault(ex); метод SpecificFault вернет исключающий объект, который будет выброшен, а не бросает его сам. Гораздо чище.

Это шаблон, рекомендованный Microsoft's guidelines (найти текст «Использовать методы построения исключений»).

+5

+1, это шаблон, рекомендованный в руководствах Microsoft. – Joe

+0

У вас есть ссылка? – noctonura

+2

Я делаю: http://msdn.microsoft.com/en-us/library/seyhszts.aspx; найдите текст «Использовать методы построения исключений». – CesarGon

3

No.

Представьте себе, если ThrowSpecificFault были определены в отдельном DLL. Если вы изменяете DLL, чтобы не генерировать исключение, тогда запустите свою программу, не перекомпилируя ее, что произойдет?

+3

Представьте, если метод Foo был определен в отдельной DLL.Если вы измените Foo, чтобы вернуть long вместо int, тогда запустите свою программу, которая вызывает Foo без перекомпиляции, что произойдет? *Ничего хорошего*. * * * * * Правильно изменить подпись метода во внешней библиотеке, а затем продолжать использовать ее без перекомпиляции. Вот почему у нас есть версии марок и т. Д. На сборках. –

+0

@ Эрик. Я считаю, что гипотетическая ситуация Слэкса не требует изменения подписи, поэтому это не так очевидно, как нарушение. – kvb

+2

@ kvb: предлагаемая функция, как я понимаю, заключается в том, чтобы зафиксировать тот факт, что метод никогда не возвращает * в своей сигнатуре *. –

8

Проблема в том, что если вы заходите в блок catch в f(), ваша функция никогда не вернет значение. Это приведет к ошибке, потому что вы объявили свою функцию как int, что означает, что вы сказали компилятору, что ваш метод вернет целое число.

Следующий код будет делать то, что вы ищете, и всегда возвращать целое число.

int f() { 
    int i = 0; 
    try { 
    i = process(); 

    } catch(Exception ex) { 
    ThrowSpecificFault(ex); 
    } 
    return i; 
} 

положить оператор возврата в конце вашей функции, и все будет в порядке.

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

+0

+1 ты бил меня минутой! –

1

Как насчет:

int f() { 
int i = -1; 
try { 
    i = process();  
} catch(Exception ex) { 
    ThrowSpecificFault(ex); 
} 
return i; 
} 
+0

Я оставляю это как ответ, но Роберт Грейнер избил меня. –

2

У вас есть три варианта:

Всегда возвращайте я, но предварительно объявить:

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); 
    } 
} 
0

Да.

Не ожидайте, чтобы ThrowSpecificFault() выбрал исключение.Попросите его вернуть исключение, а затем выбросите его здесь.

На самом деле это имеет смысл. Вы не используете исключения для «нормального» потока, поэтому, если вы каждый раз генерируете исключение, исключение становится правилом. Создать конкретное исключение в функции, и бросить его здесь, потому что это исключение из потока здесь ..

0

Я полагаю, вы могли бы сделать ThrowSpecificFault вернуть объект, а затем вы можете

return ThrowSpecificFault(ex)

В противном случае, вы можете переписать ThrowSpecificFault как конструктор для подтипа Exception, или вы можете просто сделать ThrowSpecificFault на фабрику, которая создает исключение, но не бросает его.

3

Вы можете сделать так:

catch (Exception ex) 
{ 
    Exception e = CreateSpecificFault(ex); 
    throw e; 
} 
0

В вас случае, но это Ваше знание не компилятор. Теперь можно сказать, что этот метод наверняка вызовет какое-то неприятное исключение.

Попробуйте

int f() { 
    try { 
    return process(); 
    } catch(Exception ex) { 
    ThrowSpecificFault(ex); 
    } 
    return -1; 
} 

Вы также можете использовать перекидной ключевое слово

int f() { 
    try { 
    return process(); 
    } catch(Exception ex) { 
    throw ThrowSpecificFault(ex); 
    } 
} 

Но тогда этот метод должен возвращать некоторое исключение, а не бросать его.

0

Используйте 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

7

Прямо сейчас Возвращаемый тип может быть типом, или «пустота» означает msgstr "нет типа возврата". Мы могли бы теоретически добавить второй специальный тип возврата «никогда», который имеет семантику, которую вы хотите. Конечная точка выражения, состоящая из вызова метода «никогда», будет считаться недостижимой, и поэтому она будет легальной в каждом контексте на C#, в которой «goto», «throw» или «return» является законным ,

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

Смежные вопросы