tags:

views:

375

answers:

9

I have an application which tries to load some expected registry settings within its constructor.

What is the most appropriate .NET Exception from the BCL to throw if these (essential, non-defaultable) registry settings cannot be loaded?

For example:

 RegistryKey registryKey = Registry.LocalMachine.OpenSubkey("HKLM\Foo\Bar\Baz");

 // registryKey might be null!
 if (registryKey == null)
 {
     // What exception to throw?
     throw new ???Exception("Could not load settings from HKLM\foo\bar\baz.");
 }
A: 

I would probably throw an ApplicationException since this is specifically related to your application. Alternatively, you could throw a ConfigurationErrorsException, though this is usually associated with an error parsing an application configuration file, not reading the configuration from the registry.

The other potential exceptions that come to mind are ArgumentException or ArgumentNullException, but these have a connotation of being related to parameters that are passed into the method and are not, therefore, appropriate to my mind. It could easily lead someone using/modifying your code astray when trying to determine why it is not working.

In any case, a good, descriptive error message is probably the most effective way of communicating what the problem is.

EDIT: Note that throwing an exception on a null value doesn't mask any exceptions that would occur when attempting to read the registry value. I believe that any SecurityException that gets thrown when you attempt to read the value without sufficient privileges will still occur as long as you don't wrap it in a try/catch block.

tvanfosson
+1  A: 

I'd go with ArgumentException or ArgumentOutOfRangeException..

throw new ArgumentException("Could not find registry key: " + theKey);

Quoting MSDN:

The exception that is thrown when one of the arguments provided to a method is not valid.

...

IMO writing a proper exception message is more important.

chakrit
+7  A: 

actually, I wouldn't throw an exception here. I would have a default value, and then create the key using that default value.

If you MUST have a user-defined value, I'd use the ArgumentException (as that's fundamentally what you're missing, an argument for your constructor--where you store it is irrelevant to the type of exception you're trying to generate).

Stephen Wrighton
It's a LocalMachine entry. Therefore, the current user may not have the required permissions to create a registry key.
Kent Boogaart
if that's the case, then it should be stored as an application.configuration value as opposed to a registry entry.
Stephen Wrighton
+12  A: 

Why not create your custom exception?

public class KeyNotFoundException : RegistryException
{
    public KeyNotFoundException(string message)
        : base(message) { }
}
public class RegistryException : Exception
{
    public RegistryException(string message)
        : base(message) { }
}

....

if (registryKey == null)
{
    throw new KeyNotFoundException("Could not load settings from HKLM\foo\bar\baz.");
}

Also, instead of inheriting from Exception you could inherit from ApplicationException. This depends on the kind of failure you want your application to have in this situation.

bruno conde
If you're going to create KeyNotFoundException... then it should just need the key's name, the exception message should be created automatically... short of like ArgumentNullException
chakrit
This is probably only useful if you intend to catch exceptions of this particular type and do something useful. If you are just going to use the error message and exit, then there isn't much point in creating a new exception class.
tvanfosson
In addition to tvanfosson's observation, you also now have the problem of maintaining the exception hierarchy that you've just created. e.g. those exception classes are not serializable so won't travel across app-domain boundaries.
Daniel Fortunov
@ Daniel - Making an exception serializable is not hard to do, and if you do it in a custom base exception that you derive all of your other custom exceptions from, it is something you only need to do once (unless you add custom properties).
joseph.ferris
@tvanfosson - I would assume that this is a desktop application. If it is, this is the type of message that would be logged and probably quite helpful for troubleshooting. If the exception is just going to be swallowed, it shouldn't be an treated as an exception in the first place.
joseph.ferris
ApplicationException should not be used in new code. It is now only in the BCL for compatability. MS changed their minds about it when .NET 2 was released.
pipTheGeek
@pipTheGeek -- the thing that changed was that they indicate that you should not derive custom exceptions from ApplicationException, not that you should not use it. The ApplicationException class itself is not deprecated and can still be used, even in .Net 3.5.
tvanfosson
A: 

I think just Exception itself could do the job. If your message is descriptive enough, then it's all good. If you really want to be precise about it, then I'd agree with petr k. Just roll your own.

BFree
MSDN guidelines explicitly states never to throw just an System.Exception.
Seb Nilsson
Guidelines aren't strict rules. Sometimes just an Exception is enough.
chakrit
Depends on the shop. We explicitly enforce this guideline. It is a bad practice the gets peppered all over the code. An exception, by its definition, defines an exceptional case. You should know what exception you are handling. If it is defined, define it. It only take a few minutes.
joseph.ferris
Should have read "if it is not defined, define it." To take it one step further, you should always have a base exception that is derived that all of your custom exceptions will be derived from, so that it is obvious in a stack trace where the exception originated from.
joseph.ferris
The "let's create an error type for every possible error in the application" pattern. That's one I can live without. Please, just use the built-in exceptions unless you can recover from a specific error and need to differentiate it by type.
tvanfosson
I would rather have three or four custom exceptions per assembly than using an exception "just because it is there" approach any day. Repurposing exceptions is a very lazy practice that can lead to very confusing defects.
joseph.ferris
I will create new classes for ones that I can recover from to differentiate them from the ones I can't. I see no point in creating a new exception class for one that is unrecoverable when an existing exception with a suitable message will suffice.
tvanfosson
+2  A: 

It depends on why it failed. If it's a permissions issue, the I'd go with System.UnauthorizedAccess exception:

The exception that is thrown when the operating system denies access because of an I/O error or a specific type of security error.

I don't know if it matches the "specific type", but it is a security error, and access wasn't authorized.

On the other hand, if the item just doesn't exist then I'd thrown a FileNotFound exception. Of course, a registry key isn't a file, but FileNotFound is pretty well understood.

Joel Coehoorn
+2  A: 

Since this entry is as you put it an essential value, what is the impacts to your application if this value cannot be obtained? Do you need to hault operations or do you simply need to notify the application.

Also, there are a number of reasons that the value could be null

  • User doesn't have permission to read the key
  • The key doesn't exist

Does this impact the action you take when working with the application?

I think that these types of scenarios play into what exception to throw. Personally I would never throw just Exception, as it really is a "no-no" from a standard design practice.

If it is due to a user not having permissions, AND then not having this permission might cause future problems I would vote for an UnauthroizedAccess exception.

If the issue is not a critical issue, but you really need to know that the key isn't there I would strongly recommend the "KeyNotFoundException" implementation mentioned elsehwere.

When throwing an exception you want to make sure that the exception being thrown is descriptive and provides all needed information, thus why I think it depends on the root cause as well as the overall impacts to the application.

Mitchel Sellers
+1  A: 

I think that the best approach is to take a step back. If there is not a clear cut exception that describes what is happening, it takes only minutes to define one. Try to avoid repurposing exceptions because it "is close enough".

My recommendation is that you should create a base exception class which inherits from either Exception or ApplicationException. This will allow for you to easily identify, from your stack trace, whether the exception is a custom exception that you defined or whether it originated somewhere else. All of your custom exceptions should inherit from the base exception that you create.

Note: I am not going to recommend the use of either Exception or ApplicationException. There is enough debate in the community vs. Microsoft's documentation over which should be used and for what purpose. On a personal level, I choose Exception as my base exception.

If there is not a clearly predefined exception that matches your intent, going forward, derive a custom exception from your base exception. It definitely helps in tracing down the origin of a problem, makes them easier to handle (imagine that an existing framework exception was thrown in the block of code, but by the framework or another method), and just plain makes sense.

Keep in mind, you can have multiple exception hierarchies to group like exceptions together. For example, I can have MyBaseException which inherits either ApplicationException or Exception. I then can have a more generalized MyRegsitryException which inherits from MyBaseException. Then I can have specific exceptions, such as MyRegistryKeyNotFoundException or MyRegistryKeyPermissionException.

This allows you to catch a grouped exception on a higher level and reduce the number of catches that you might have that contain redundant handling mechanism. Combine this with isolating the scope of the exceptions to specific namespaces that would use them, and you have the start of a very clean exception handling scheme.

joseph.ferris
+2  A: 

To quote MSDN's "Design Guidelines for Developing Class Libraries"

ApplicationException

If you are designing an application that needs to create its own exceptions, you are advised to derive custom exceptions from the Exception class. It was originally thought that custom exceptions should derive from the ApplicationException class; however in practice this has not been found to add significant value. For more information, see Best Practices for Handling Exceptions.

Paul