#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
объектов.)