область видимости при окружении инструкции ‘new’ с помощью try / catch в c#

#c# #.net #constructor #try-catch #scope

#c# #.net #конструктор #попробуйте-поймайте #область видимости

Вопрос:

Это вопрос о том, какова «наилучшая практика» для объявления новых переменных, и я уже несколько раз сталкивался с такой ситуацией. У меня есть класс, конструктор которого считывает конфигурационный файл, например:

 ConfigMgr config = new ConfigMgr(args[0]);
  

Конечно, если вы запускаете консольное приложение без этого аргумента, возникает исключение. Если я окружу эту строку try / catch следующим образом, я получаю сообщение об ошибке ‘Имя ‘config’ не существует в текущем контексте’. Понятно.

 try
{
    ConfigMgr config = new ConfigMgr(args[0]);
}
catch
{
    Console.WriteLine("Config file not specified or incorrect in format.  Exiting.");
    Console.ReadLine();
}

// Defaults
string aucomposingfile = config.getValue("aucomposingfile");
string nzcomposingfile = config.getValue("nzcomposingfile");
...etc
  

Я мог бы выделить часть, для которой требуется аргумент в конструкторе — создайте новую часть ConfigMgr вне блока try / catch, затем сделайте что-то вроде config.LoadFile() в try / catch. Но я не могу представить, что это то, что делают те, кто в курсе.

Есть мысли?

Спасибо!

Комментарии:

1. Почему вы думаете, что это неправильно… Я думаю, что все это делают

2. Спасибо всем за ваши комментарии. Я не уверен, какой из них отметить в качестве ответа, поскольку оба ответа объясняют это очень хорошо. Приветствуются любые предложения (является ли нижний ответ «первым»)? Оба получают мой положительный отзыв!

Ответ №1:

Нет причин, по которым вы не можете этого сделать:

 ConfigMgr config = null;
try
{
    config = new ConfigMgr(args[0]);
}
catch ( /* catch a specific exception!! */ ) 
{
    //log it:
    Console.WriteLine("Config file not specified or incorrect in format.  Exiting.");

    //escape from here, because you don't want to continue:
    throw;    
}

string aucomposingfile = config.getValue("aucomposingfile");
string nzcomposingfile = config.getValue("nzcomposingfile");
  

Конечно, возможно, более правильным способом может быть проверка аргументов командной строки перед попыткой их использования и выдача определенного исключения, если они не соответствуют вашим требованиям — вы зависите от них, поэтому сначала проверьте их. Это обеспечивает лучший поток кода, чем просто попытка использовать их и перехватывать исключение. Таким образом, ваш catch блок становится более сфокусированным на проблемах, более специфичных для файла конфигурации, вместо того, чтобы также обрабатывать проблемы с аргументами командной строки.

Комментарии:

1. Спасибо. Комментарий вокруг первой проверки также имеет большой смысл. Приветствия

Ответ №2:

Если вам нужно получить доступ к переменной не только в try блоке, вам нужно объявить и инициализировать переменную перед блоком. Достаточно простого объявления и инициализации в null.

 Foo foo = null;
try 
{
    foo = DoSomethingToGetFoo();
}
catch (SpecificException ex)
{
    // do whatever, foo is accessible but may require null-checking
}
finally 
{
    // ditto 
}

// still accessible
  

Очевидно, что объявление переменной во внешней области необходимо, если вы хотите получить к ней доступ в другом месте. Но инициализация также необходима, поскольку компилятор C # потребует доказательства того, что переменная была инициализирована, прежде чем разрешить вам ее использовать. Если «стандартный» инициализатор находится в области try , компилятор не может гарантировать, что он возникнет до того, как будет использован позже.

Для вашего собственного кода вы можете решить, может ли все, что вам нужно сделать с переменной, содержаться в try . Если это так, очевидно, ограничьте его область действия этим блоком. Но в некоторых ситуациях вам нужна более широкая область видимости. (Смотрите: расширение using для IDisposable объектов.)