объявить метод всегда выдает исключение? - PullRequest
22 голосов
/ 08 октября 2010

У меня есть метод как ...

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

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

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

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

Ответы [ 11 ]

55 голосов
/ 08 октября 2010

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

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

9 голосов
/ 08 октября 2010

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

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

8 голосов
/ 08 октября 2010

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

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

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

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

поместите оператор return в конец вашей функции, и все будет в порядке.

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

4 голосов
/ 08 октября 2010

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

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}
3 голосов
/ 08 октября 2010

номер

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

2 голосов
/ 08 октября 2010

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

Всегда возвращать 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);
    }
}

Или создайте пользовательский класс Exception и добавьте его:

int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw new SpecificFault(ex);
    }
}
1 голос
/ 08 октября 2010

Как насчет:

int f() {
 int i = -1;
 try {
   i = process();       
 } catch(Exception ex) {
   ThrowSpecificFault(ex);
 }
 return i;
}
0 голосов
/ 08 октября 2010

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

0 голосов
/ 08 октября 2010

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

Попробуйте это

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

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

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

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

0 голосов
/ 08 октября 2010

Полагаю, вы можете заставить ThrowSpecificFault возвращать объект, а затем вы можете

return ThrowSpecificFault(ex)

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

...