Best practices: throwing exceptions from properties
When is it appropriate to throw an exception from within a property getter or setter? When is it not appropriate? Why? Links to external documents on the subject would be helpful... Google turned up surprisingly little.
Solution 1:
Microsoft has its recommendations on how to design properties at http://msdn.microsoft.com/en-us/library/ms229006.aspx
Essentially, they recommend that property getters be lightweight accessors that are always safe to call. They recommend redesigning getters to be methods if exceptions are something you need to throw. For setters they indicate that exceptions are an appropriate and acceptable error handling strategy.
For indexers, Microsoft indicates that it is acceptable for both getters and setters to throw exceptions. And in fact, many indexers in the .NET library do this. The most common exception being ArgumentOutOfRangeException
.
There are some pretty good reasons why you don't want to throw exceptions in property getters:
- Because properties "appear" to be fields, it is not always apparent that they can throw a (by-design) exception; whereas with methods, programmers are trained to expect and investigate whether exceptions are an expected consequence of invoking the method.
- Getters are used by a lot of .NET infrastructure, like serializers and databinding (in WinForms and WPF for example) - dealing with exceptions in such contexts can rapidly become problematic.
- Property getters are automatically evaluated by debuggers when you watch or inspect an object. An exception here can be confusing and slow down your debugging efforts. It's also undesirable to perform other expensive operations in properties (like accessing a database) for the same reasons.
- Properties are often used in a chaining convention:
obj.PropA.AnotherProp.YetAnother
- with this kind of syntax it becomes problematic to decide where to inject exception catch statements.
As a side note, one should be aware that just because a property is not designed to throw an exception, that doesn't mean it won't; it could easily be calling code that does. Even the simple act of allocating a new object (like a string) could result in exceptions. You should always write your code defensively and expect exceptions from anything you invoke.
Solution 2:
There's nothing wrong with throwing exceptions from setters. After all, what better way to indicate that the value is not valid for a given property?
For getters, it is generally frowned upon, and that can be explained pretty easily: a property getter, in general, reports the current state of an object; thus, the only case where it is reasonable for a getter to throw is when the state is invalid. But it is also generally considered to be a good idea to design your classes such that it is simply not possible to get an invalid object initially, or to put it into invalid state via normal means (i.e., always ensure full initialization in constructors, and try make methods exception-safe with respect to state validity and class invariants). So long as you stick to that rule, your property getters should never get into a situation where they have to report invalid state, and thus never throw.
There is one exception I know of, and it's actually a rather major one: any object implementing IDisposable
. Dispose
is specifically intended as a way to bring object into an invalid state, and there's even a special exception class, ObjectDisposedException
, to be used in that case. It is perfectly normal to throw ObjectDisposedException
from any class member, including property getters (and excluding Dispose
itself), after the object has been disposed.
Solution 3:
It is almost never appropriate on a getter, and sometimes appropriate on a setter.
The best resource for these sorts of questions is "Framework Design Guidelines" by Cwalina and Abrams; it's available as a bound book, and large portions of it are also available online.
From section 5.2: Property Design
AVOID throwing exceptions from property getters. Property getters should be simple operations and should not have preconditions. If a getter can throw an exception, it should probably be redesigned to be a method. Note that this rule does not apply to indexers, where we do expect exceptions as a result of validating the arguments.
Note that this guideline only applies to property getters. It is OK to throw an exception in a property setter.