5

(I've searched similar threads and couldn't find anything that addressed this particular issue, though there were several similar such as here and here.)

I'm evaluating performance of our app and I'm noticing that we're getting some IOExceptions "Cannot locate resource". I'm not sure exactly how many times it's happening (largely depends on how user uses the app), but it's at least a dozen or so.

I'm assuming that exceptions in general are performance expensive as are File I/O calls like File.Exists(). I know that it's always good practice to check if a file exists before you try and load it. My question is, how much performance gain would I see if I check if this particular file existed? (Again, ignore the "you should do this anyway", I'm just trying to get an understanding of performance).

Option 1:

try
{
    return (ResourceDictionary) Application.LoadComponent(uri);
}
catch (Exception)
{
    //If it's not there, don't do anything
}

This doesn't make an extra IO call, but sometimes throws and exception which is swallowed.

Option 2:

if(File.Exists(uri))
{
    return (ResourceDictionary) Application.LoadComponent(uri);
}


  • How do you know that it's "always a good practice"? - Gabe
  • Option two introduces a race condition. - asawyer
  • Option 2 has a race condition. Any IO operation could potentially fail even if you have previously checked that it. - Mike Zboray
  • You're right, it might not always be, but generally speaking you'd always want to check if the file exists. Several university assignments were docked points for not checking ;) - Devin
  • It's what you would call a exogenous exception. blogs.msdn.com/b/ericlippert/archive/2008/09/10/… - asawyer

3 답변


6

In general, if the file should exist (ie: it's part of your application's deployment), then I'd use the exception checking, and nothing else. This is because, in this case, the exception is truly an exceptional and unexpected circumstance.

If the file is something that is input by the user, checking for existence becomes potentialy meaningful. However, this still doesn't eliminate the need for exception handling, as the file could be deleted between the time you check and the time you open/use it. As such, you'd still need the exception handling - in which case you may want to still just use your first option code, but make sure the exception handling is clean enough to always provide a behavior, even if the file doesn't exist.


  • I agree with you. Unfortunately I think that the developer that implemented this didn't realize that it might not exist in certain situations. The file being loaded is deployed, but it's deployed only for certain assemblies, but this logic exists in a base class which might get invoked on assemblies which don't have that file, if that makes sense. - Devin
  • File.Exists throws an exception internally anyway, so the net result is the same. - rolls

1

I can't see there being a big performance difference between your two options. Most of the work is locating and reading the file so in both cases you have to do that. What might be useful is caching the result if you don't expect the user add/remove this file while the application is running. So you might do something like

private static Dictionary<Uri, ResourceDictionary> _uriToResources =
  new Dictionary<Uri, ResourceDictionary>();
public static ResourceDictionary GetResourceDictionary(Uri uri)
{
  ResourceDictionary resources;
  if (_uriToResources.TryGetValue(uri, out resources))
  {
    return resources;
  }

  try
  {
     resources = (ResourceDictionary)Application.LoadComponent(uri);
  }
  catch
  {
     // could prompt/alert the user here.
     resources = null; // or an appropriate default.
  }

  _uriToResources[uri] = resources;
  return resources;
}

This would prevent you from repetitively trying to load a resource that does not exist. Here I return a null object but it may be better to use some default as a fallback.


1

File.Exists does internally throw exceptions as well. So the performance will be very similar.

Here is the code from File.cs which contains the helper method which File.Exists calls.

 [SecurityCritical]
    private static bool InternalExistsHelper(string path, bool checkHost)
    {
      try
      {
        if (path == null || path.Length == 0)
          return false;
        path = Path.GetFullPathInternal(path);
        if (path.Length > 0 && Path.IsDirectorySeparator(path[path.Length - 1]))
          return false;
        FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, path, false, false);
        return File.InternalExists(path);
      }
      catch (ArgumentException ex)
      {
      }
      catch (NotSupportedException ex)
      {
      }
      catch (SecurityException ex)
      {
      }
      catch (IOException ex)
      {
      }
      catch (UnauthorizedAccessException ex)
      {
      }
      return false;
    }

Linked


Related

Latest