2015-07-08 8 views
4

После прочтения this Eric Lippert Статья, я понимаю, что компилятор C# не нравится, если мы оставляем локальными переменными неинициализированные.Как обрабатывать неинициализированные локальные переменные

Когда я сталкивался с этой «проблемой» время от времени, я смотрел на некоторые из моих старых кодов и смог отсеять большую часть ситуации, где на самом деле не нужны неинициализированные (SomeClass obj = null) локальные переменные.

Но я столкнулся с ситуацией, когда я не знаю, как реорганизовать код.

public void DoSomething(string foo) { 

    SomeClass obj; // = null; 

    try { 
     obj = SomeClass.CreateItem(target); 
    } catch(CustomException ex) { 
     // notify UI of error 
    } 

    if (obj != null) { 
     // do something with `obj` 
    } 
} 

SomeClass.CreateItem может не работать из-за внешних факторов. Если это так, я хочу уведомить пользователя, если не хочу выполнить действие.

C# компилятор не хочет, чтобы оставить obj неинициализированным, поэтому я обычно назначить null к нему.

Это чувствует, как «взломать» сейчас и мой вопрос:

Есть недостаток дизайна в коде выше?

И если есть, как мне обращаться со ссылками во время компиляции, когда я не могу определить, будут ли они указывать на существующий объект во время выполнения?

+1

«Обоснование» компилятора заключается в том, что если в SomeClass.CreateItem есть исключение, obj останется неинициализированным при достижении теста «obj! = Null». Общий принцип заключается в том, что переменную не нужно инициализировать, если она обязательно назначается в коде, т. Е. Все условные ветви присваивают значение. – Graffito

ответ

2

Код // do something with obj`` должен находиться внутри блока try`.

Что вы пытаетесь сделать, это запустить код, который может или не может быть успешным, а затем запустить другой код , только если предыдущий код преуспел. Это, как правило, очень сильный знак того, что другой код является частью одного и того же логического блока, который зависит от того, что он не является исключением. Если есть исключение, строящее этот объект, вы хотите, чтобы этот код был пропущен, что является именно тем поведением, которое вы получаете, включив его в блок try.

+1

Что делать, если какая-то часть части «// сделать что-то» может также вызывать «CustomException»? Тогда я не могу определить, что пошло не так, поймав одного.По сути, у меня есть противоречивая конвенция, в которой говорится: «Держите свои блоки попыток максимально плотными» – MrPaulch

+0

@MrPaulch Вы действительно хотите сделать совершенно другую вещь, если что-то другое выдает такое же исключение? Если это так, то это признак того, что они не должны оба бросать одно и то же исключение. И я бы не сказал, что это хорошая идея, чтобы попытаться блокировать ваши попытки. Наоборот; когда вы видите очень плотные блоки 'try', это признак, что что-то не так. Обычно они должны охватывать все операции, представляющие некоторую единую логическую операцию. – Servy

+0

Ваша точка зрения о «разных» исключениях имеет смысл! Один из последних вопросов: Что мне делать, если мне нужно вернуть объект iff, если он существует, или null, если это не так? – MrPaulch

0

Вы можете реорганизовать это инкапсулировать весь код в Try/улова, связанных с этим объектом, и если вы действительно действительно нужно что-то делать, если он не работает, то вы можете использовать логическое значение, чтобы связать это с остальной частью вашего код:

public void DoSomething(string foo) 
    { 

     bool failedCreation = false; 

     try 
     { 
      SomeClass obj = SomeClass.CreateItem(target); 
     } 
     catch (CustomException ex) 
     { 
      // notify UI of error 
      failedCreation = true; 
     } 

     if (failedCreation) 
     { 
      // do other stuff. 
     } 
    } 

Но это не похоже на то, что вы имеете в виду. Я бы просто инкапсулировал все в try/catch и делал с ним.

9

Я бы реорганизовать код так:

private SomeClass TryToCreateItem() 
{ 
    try 
    { 
     return SomeClass.CreateItem(target); 
    } 
    catch(CustomException ex) 
    { 
     // notify UI of error 
    } 
    return null; 
} 

public void DoSomething(string foo) 
{ 
    SomeClass obj = TryToCreateItem(); 
    if (obj != null) { 
     // do something with `obj` 
    } 

"метод Extract" мой любимый рефакторинга.

+0

Не по той же причине, что вы бы рефакторировали «bool TryParse (string input, out int result)» или это другой сценарий, поскольку TryParse обычно имеет дело с (не-нулевыми) типами значений? – MrPaulch

+1

@MrPaulch: Вы поднимаете хороший момент; нуль здесь используется как сигнал о том, что операция потерпела неудачу. Если вам нужно различать три случая: fail/null, success/null и success/non-null, тогда вам понадобится дополнительный механизм. –

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