This is a question of what the 'best practice' is for declaring new variables, and I've seen this situation a few times now. I have a class whose constructor reads a config file, eg:
ConfigMgr config = new ConfigMgr(args[0]);
Of course, if you run the console app without that argument, an exception results. If I surround that line with a try/catch as follows, I get the error 'The name 'config' does not exist in the current context'. Understandable.
try
{
Config开发者_如何学运维Mgr 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
I could separate out the part that requires the argument in the constructor - do the new ConfigMgr part outside the try/catch block, then do something like config.LoadFile() in the try/catch. But I can't imagine that's what those in the know do.
Any thoughts?
Thanks!
There is no reason why you cannot do this:
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");
Of course the arguably more correct way may be to check the command line arguments before attempting to use them, and throw a specific exception if they don't meet your requirements - you depend on them, so verify them first. This has a better code flow than just trying to use them and catching an exception. This way your catch
block becomes more focused on problems more specific to the config file, rather than handling issues with the command line arguments as well.
If you need to access a variable in more than just a try
block, you need to declare and initialize the variable before the block. Simply declaring and initializing to null is sufficient.
Foo foo = null;
try
{
foo = DoSomethingToGetFoo();
}
catch (SpecificException ex)
{
// do whatever, foo is accessible but may require null-checking
}
finally
{
// ditto
}
// still accessible
Obviously, declaring the variable in an outer scope is necessary if you wish to access it elsewhere. But initializing is also necessary, as the C# compiler will require proof that a variable has been initialized prior to allowing you to use it. If the "standard" initializer is in the scope of the try
, the compiler cannot guarantee that it will have occured prior to being used later.
For your own code, you can decide if everything you need to do with a variable can be contained within the try
. If so, obviously limit its scope to that block. But in some situations, you need a broader scope. (See: the expansion of using
for IDisposable
objects.)
精彩评论