简体   繁体   中英

Try-Catch block with two catch clauses with similar code

I'm using the try-catch block with two catch clauses. I want to load an XML file from a specific path and I'm checking if the directory exists in the first clause to create the directory, and in the second if the file exists to create the file. However, I know that if the directory doesn't exist, the file will not either.

So I am thinking if there is a way to not duplicate the code. I know I can create a boolean variable and then check if its true and create the file but I thought there might be a nice, clean solution that I just don't know how to search for.

XmlDocument document = new XmlDocument();

try
{
    document.Load(folderPath + @"\XMLfile.xml"); // folderPath variable is assigned before depending on user input
}
catch(System.IO.DirectoryNotFoundException)
{
    // if folder doesn't exist then the file will not either
    System.IO.Directory.CreateDirectory(folderPath);
    document.LoadXml("<?xml version=\"1.0\"?> \n" +
                     "<elements> \n" +
                     "</elements>");
}
catch (System.IO.FileNotFoundException)
{
    // if folder exists then the file might as well, if not, creating the file's structure
    document.LoadXml("<?xml version=\"1.0\"?> \n" +
                     "<elements> \n" +
                     "</elements>");
}

Ideally I would like to know if there is a way to avoid duplicating the code but still keep both exceptions. Is a boolean variable for example createFile in both catch clauses the only way to do in a somewhat nice way?

How about

XmlDocument document = new XmlDocument();

try
{
   document.Load(folderPath + @"\XMLfile.xml");
}
catch (Exception e) when (e is DirectoryNotFoundException || e is FileNotFoundException)
{
    Directory.CreateDirectory(folderPath);
    document.LoadXml("<?xml version=\"1.0\"?> \n" +
                     "<elements> \n" +
                     "</elements>");
}

Directory.CreateDirectory(folderPath); does nothing if the directory already exists. So, it's safe to call it there.

If you are using C# 6 or above, you can use when keyword to filter out exception on specified criteria:

XmlDocument document = new XmlDocument();

try
{
    document.Load(folderPath + @"\XMLfile.xml"); // folderPath variable is assigned before depending on user input
}
catch (Exception ex) when (ex is System.IO.DirectoryNotFoundException || ex is System.IO.FileNotFoundException)
{
    // if folder doesn't exist then the file will not either
    System.IO.Directory.CreateDirectory(folderPath);
    document.LoadXml("<?xml version=\"1.0\"?> \n" +
                     "<elements> \n" +
                     "</elements>");
}

However, you don't have exactly the same catch blocks, so you might even consider leaving everything as is. Otherwise, you'll need to introduce another check inside the catch block to invoke CreateDirectory .

Check this thread . You will have basic folder picker and you don't have to scratch your head with try catch blocks. Depends mostly on your application. If it's something server sided, you should read something about Streams (FileStream, StreamReader, etc..) here

You are using exceptions to handle normal control flow. The errors you are catching should be handled without exceptions.

Nevertheless you still can get exceptions due to race conditions, so you still need exception handling.

Also you should consider adding additional handling for malformed xml.

public static XmlDocument LoadOrCreateXmlDocument(string folderPath)
{
    if (!Directory.Exists(folderPath))
    {
        Directory.CreateDirectory(folderPath);
    }

    string fileName = Path.Combine(folderPath + @"\XMLfile.xml");

    if (TryLoadXmlDocument(fileName, out var document))
    {
        return document;
    }

    XmlDocument newDocument = new XmlDocument();
    newDocument.LoadXml("<?xml version=\"1.0\"?> \n" +
                        "<elements> \n" +
                        "</elements>");

    return newDocument;
}

public static bool TryLoadXmlDocument(string fileName, out XmlDocument document)
{
    document = new XmlDocument();

    if (File.Exists(fileName))
    {
        try
        {
            document.Load(fileName);
            return true;
        }
        catch (FileNotFoundException)
        {
            return false;
        }
    }

    return false;
}

Try to avoid executing much code from catch. This is a recipe for bigger problems. Better is to use the different exceptions to determine what to do next and return this result at the end of the method.

So use the catch only to handle the exceptions and proceed with further action later, not from within the catch.

For example:

bool documentLoaded = LoadXML(); // Your code in this method
if (!documentLoaded)
  CreateXML();

Maybe it is better to use methods System.IO.Directory.Exists() and System.IO.Directory.Exists() instead of catching exceptions. So your code will be more clear.

XmlDocument document = new XmlDocument();

if (!System.IO.Directory.Exists(folderPath))
    System.IO.Directory.CreateDirectory(folderPath);

var filename = folderPath + @"\XMLfile.xml";

if (System.IO.File.Exists(filename);
    document.Load(filename);
else
    document.LoadXml("<?xml version=\"1.0\"?> \n" +
                     "<elements> \n" +
                     "</elements>");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM