(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);
}
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 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.
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;
}