2015-12-31 3 views
-2

Мне нужно использовать значение переменной, инициализированной внутри блока try. У меня есть этот базовый кодИспользование переменной снаружи Try-Catch

Customer customer = null; 
try 
{ 
    customer = new Customer(....); 
} 
catch (Exception){} 
string customerCode = customer.Code; 

Если не исключение, клиент perfecly можно использовать, но если есть исключение, клиент не инициализирован, он возвращает нуль

Я проверил, что клиент ВСЕГДА инициализирует правильно Вставить блок. ВНУТРИ Идеально подходит даже в случае исключения. Но мне это нужно для последующего использования.

Любой способ ВСЛЕДСТВИЕ сохранить клиента? :)

EDIT:

Как предполагается, это был псевдокод. Как я могу прочитать, похоже, что использование исключений в конструкторах - идея BAD. Это часть моего REAL-кода для моего конструктора.

public class DirectDebitRemmitanceReject 
{ 
    int numberOfTransactions; 
    decimal controlSum; 
    List<DirectDebitTransactionReject> directDebitTransactionRejects; 

    public DirectDebitRemmitanceReject(
     int numberOfTransactions, 
     decimal controlSum, 
     List<DirectDebitTransactionReject> directDebitTransactionRejects) 
    { 
     this.numberOfTransactions = numberOfTransactions; 
     this.controlSum = controlSum; 
     this.directDebitTransactionRejects = directDebitTransactionRejects; 

     if (TheProvidedNumberOfTransactionsIsWrong()) ChangeNumberOfTransactionsAndRiseException(); 
     if (TheProvidedControlSumIsWrong()) ChangeControlSumAndRiseException(); 
    } 

    private bool TheProvidedNumberOfTransactionsIsWrong() 
    { 
     return (numberOfTransactions != directDebitTransactionRejects.Count) 
    } 

    private bool TheProvidedControlSumIsWrong() 
    { 
     return (controlSum !=directDebitTransactionRejects.Select(ddRemmitanceReject => ddRemmitanceReject.Amount).Sum();) 
    } 

    private void ChangeNumberOfTransactionsAndRiseException() 
    { 
     ...... 
     ...... 
     throw new ArgumentException(exceptionMessage, "numberOfTransactions") 

    private void ChangeControlSumAndRiseException() 
    { 
     ...... 
     ...... 
     throw new ArgumentException(exceptionMessage, "controlSum") 
    } 
} 

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

Дело в том, что я хотел, чтобы конструктор ALLWAYS возвращал действительный (конгруэнтный) DirectDebitRemmitanceReject, но желал, чтобы тот же самый конструктор поднял исключение, если был указан неправильный номерOfTransactions или controlSum. NumberOfTransactions и controlSum не следует изменять позже, только читать.

В моих тестах, это хорошо работает

[TestMethod] 
    [ExpectedException(typeof(System.ArgumentException))] 
    public void IfTheProvidedControlSumInARemmitanceRejectIsWorgAnExceptionIsThrown() 
    { 
     try 
     { 
      DirectDebitRemmitanceReject directDebitRemmitanceReject = new DirectDebitRemmitanceReject(
       originalDirectDebitRemmitance1MessageID, 
       2, 
       100, 
       directDebitTransactionRejectsList1); 
     } 
     catch (System.ArgumentException e) 
     { 
      Assert.AreEqual("controlSum", e.ParamName); 
      Assert.AreEqual("The Control Sum is wrong. Provided: 100. Expected: 150. Initialized with expected value", e.GetMessageWithoutParamName()); 
      throw; 
     } 
    } 

    [TestMethod] 
    public void IfTheProvidedControlSumInARemmitanceRejectIsWorgItIsCorrected() 
    { 
     try 
     { 
      DirectDebitRemmitanceReject directDebitRemmitanceReject = new DirectDebitRemmitanceReject(
       originalDirectDebitRemmitance1MessageID, 
       2, 
       100, 
       directDebitTransactionRejectsList1); 
      Assert.AreEqual(150, directDebitRemmitanceReject.ControlSum); 
     } 
     catch (ArgumentException) { } 
    } 

Но я могу, т утверждающего directDebitRemmitanceReject.ControlSum вне блока «попробовать»

Итак ... я попробовать другой ПОДХОД (удалить исключение изнутри конструктора) или есть другое обходное решение?

Спасибо! :)

(Извините за ЭКСТЕНСИВНОГО редактирования) :(

+3

Это означает, что попытка не выполнила это утверждение. Переменные не теряют свое значение после блока try. Вероятно, у вас было исключение. Если вы разместите свой фактический код, мы, вероятно, сможем помочь. Судя по внешнему виду этого кода (тем более, что конструктор не должен генерировать исключение), я предполагаю, что это псевдокод. – dman2306

+1

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

+0

Если вам всегда нужен клиент, почему бы не отказаться от 'try'-'catch'? –

ответ

7

Ваш пример является прекрасной иллюстрацией того, почему написание

catch (Exception){} 

это очень плохая практика.

Когда вы ловите исключение , вы должны что-то сделать с этим. Если вы не знаете, что делать с исключением в конкретном методе вашего кода, не поймайте исключение в этом методе.

Если вам всегда нужен клиент, даже если его извлечение вызывает исключение, добавить код к catch блоку установить customer переменные в какой-то объект по умолчанию:

try { 
    ... 
} catch (Exception) { 
    customer = Customer.Unknown; 
} 

Это предполагает, что Customer обладает свойством Unknown типа Customer с некоторым поведением по умолчанию.

Комментарий: Необходимо предупредить верхний уровень моего кода.Просто, когда я создаю экземпляр, создайте его, но предоставьте аргументы, где это неправильно. Не могли бы вы порекомендовать мне лучший подход?

сделать фабрику для проверки пользователей при создании их:

class CustomerCreationResult { 
    public Customer Customer() { get; set; } 
    public CustomerCreationError Error() { get; set; } 
} 

class CustomerFactory { 
    public CustomerCreationResult CreateCustomer(String name, int age) { ... } 
} 

Теперь вы можете создать своих клиентов следующим образом:

var r = myCustomerFactory.CreateCustomer(name, age); 
if (r.getError() != null) { 
    ... // Present the error 
} 
Customer customer = r.Customer; 
... 
+0

Извините. Я использовал псевдокод, не объясняя реального поведения моего конструктора. Я отредактировал свой пример и добавил его. Я хотел использовать исключение для SIGNAL, во время инициализации произошла ошибка аргумента, даже когда конструктор решает ее. Может быть, исключение - не лучший способ справиться с этим. Любое предложение? Благодаря! – Kaikus

+0

@Kaikus Исключения должны использоваться для ситуаций, не подлежащих восстановлению. Если вы хотите предупредить пользователя о возможной ошибке, используйте другой механизм для сообщения вашего предупреждения. – dasblinkenlight

+0

Необходимо предупредить верхний уровень моего кода. Просто, когда я создаю экземпляр, создайте его, но предоставьте аргументы, где это неправильно. Не могли бы вы посоветовать мне лучший подход? Благодаря! – Kaikus

0

Если клиент всегда инициализируется правильно, то почему у вас это в блоке try?

Если вы хотите сохранить его при возникновении исключения, либо переместите инициализацию клиента за пределы блока try, либо используйте try/catch для небольших фрагментов кода.

, например:

Customer customer = null; 
try 
{ 
    //in this block do the stuff that is unlikely to cause exceptions 
    customer = new Customer(...); 

    try 
    { 
     //stuff that is likely to cause exceptions 
    } 
    catch(Exception e) 
    { 
     //handle likely errors 
    } 
catch (Exception e) 
{ 
    //handle the unusual errors 
} 
+1

* Если клиент всегда инициализирует правильно, то почему у вас есть это в блоке try? * Почему у вас вообще есть обработка исключений? Для обработки * исключений *. Это один раз, когда он не работает. –

+0

* Если вы хотите сохранить его, когда возникает исключение ... *, это невозможно. Если конструктор не работает, у вас нет экземпляра вообще. –

+1

Теоретически любой вызов 'new' может завершиться сбоем с помощью' OutOfMemoryException', поэтому никогда не существует способа гарантировать 100% -ную инициализацию _allways_. Обычно, как только вы удаляете исключение OOM, для которого все готово, но точка может возникнуть на этой линии, и, следовательно, 'try' /' catch' не является 100% глупым. – dman2306

-1

Я думаю, что «ответ dasblinkenlight это очень хорошо, но для простейших целей if будет достаточно:

string customerCode = ""; 
if (customer!=null) 
{ 
    customerCode = customer.Code; 
} 

И вы действительно должны проверить исключение ..

+0

Я не уверен, что это значит или как он решает проблему? – dman2306

+0

Он избегает исключения NullReferenceException самым простым способом ... –

+0

Я не помню его вопроса, говорящего о каком-либо 'NullReferenceException', он спросил, почему это null. – dman2306

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