avoiding null reference exceptions
Solution 1:
When a null reference exception is displayed to the user, this indicates a defect in the code resulting from an error on the part of the developer. Here are some ideas on how to prevent these errors.
My top recommendation for people who care about software quality, and are also using the.net programming platform, is to install and use Microsoft code contracts ( http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx ). It includes capabilities to do run-time checking and static verification. The essential capability to build these contracts into your code is being included in the 4.0 version of the.net framework. If you are interested in code quality, and it sounds like you are, you may really enjoy using Microsoft code contracts.
With Microsoft code contracts, you can guard your method from null values by adding preconditions like this "Contract.Requires(customer != null);". Adding a precondition like this is equivalent to the practice recommended by many others in their comments above. Prior to code contracts, I would have recommended you do something like this
if (customer == null) {throw new ArgumentNullException("customer");}
Now I recommend
Contract.Requires(customer != null);
You can then enable the run-time checking system which will catch these defects as early as possible, leading you towards diagnosis and correction of the defective code. But don't let me give you the impression that code contracts are simply a fancy way to replace argument null exceptions. They are much more powerful than that. With Microsoft code contracts, you can also run the static checker, and ask it to investigate possible sites in your code where null reference exceptions might occur. The static checker requires a bit more experience to use easily. I would not recommend it first for beginners. But feel free to try it out and see for yourself.
RESEARCH ON THE PREVALENCE OF NULL REFERENCE ERRORS
There has been some debate in this thread on whether null reference errors are a significant problem. A long-winded answer is below. For people who don't want to wade through that, I will summarize.
- Microsoft's leading researchers in program correctness on the Spec# and code contracts projects believe it is a problem worth addressing.
- Dr. Bertrand Meyer and the team of software engineers at ISE, who developed and support the Eiffel programming language, also believe it is a problem worth addressing.
- In my own commercial experience developing ordinary software, I have seen null reference errors often enough, that I would like to address the problem in my own products and practices.
For years, Microsoft has invested in research designed to improve software quality. One of their efforts was the Spec# project. One of the most exciting developments in my opinion with the.net 4.0 framework, is the introduction of Microsoft code contracts, which is an outgrowth of the earlier work done by the Spec# research team.
Regarding your remark "the vast majority of errors in code are null reference exceptions", I believe it is the qualifier "the vast majority" that will cause some disagreements. The phrase "Vast majority" suggests that perhaps 70-90% of faults have a null reference exception as the root cause. This seems far too high to me. I prefer to quote from the research of the Microsoft Spec#. In their article The Spec# programming system: An overview, by Mike Barnett, K. Rustan M. Leino, and Wolfram Schulte. In CASSIS 2004, LNCS vol. 3362, Springer, 2004, they wrote
1.0 Non-Null Types Many errors in modern programs manifest themselves as null-dereference errors, suggesting the importance of a programming language providing the ability to discriminate between expressions that may evaluate to null and those that are sure not to (for some experimental evidence, see [24, 22]). In fact, we would like to eradicate all null dereference errors.
This is a likely source for people at Microsoft who are familiar with this research. This article is available at the Spec# site.
I've copied references 22 and 24 below, and included the ISBN for your convenience.
Manuel Fahndrich and K. Rustan M. Leino. Declaring and checking non-null types in an object-oriented language. In Proceedings of the 2003 ACM Conference on Object-Oriented Programming, Systems, Languages, and Applications, OOPSLA 2003, volume 38, number 11 in SIGPLAN Notices, pages 302–312. ACM, November 2003. isbn = {1-58113-712-5},
Cormac Flanagan, K. Rustan M. Leino, Mark Lillibridge, Greg Nelson, James B. Saxe, and Raymie Stata. Extended static checking for Java. In Proceedings of the 2002 ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI), volume 37, number 5 in SIGPLAN Notices, pages 234–245. ACM, May 2002.
I reviewed these references. The first reference indicates some experiments they did reviewing their own code for possible null reference defects. Not only did they find several, but in many cases, the identification of a potential null reference indicated a broader problem with the design.
The second reference does not provide any specific evidence for the assertion that null reference errors are problem. But the authors do state that in their experience, these null reference errors are significant source of software defects. The paper then proceeds to explain how they try to eradicate these defects.
I also remembered seeing something about this in an announcement from ISE on a recent release of Eiffel. They refer to this issue as "void safety", and like so many things inspired or developed by Dr. Bertrand Meyer, they have an eloquent and educational description of the problem and how they go about preventing it in their language and tools. I recommend you read their article http://doc.eiffel.com/book/method/void-safety-background-definition-and-tools to learn more.
If you want to learn more about Microsoft code contracts, there are tons of articles that have arisen recently. You can also check my blog at http: SLASH SLASH codecontracts.info which is primarily devoted to conversations about software quality through the use of programming with contracts.
Solution 2:
In addition to the above (Null Objects, Empty Collections), there are some general techniques, namely Resource Acquisition is Initialization (RAII) from C++ and Design By Contract from Eiffel. These boil down to:
- Initialize variables with valid values.
- If a variable can be null, then either check for null and treat it as a special case or expect a null reference exception (and deal with that). Assertions can be used to test for contract violations in development builds.
I've seen a lot of code that looks like this:
if ((value != null) && (value.getProperty() != null) && ... && (...doSomethingUseful())
A lot of the time this is completely unnecessary and most of the tests could be removed with stricter initialization and tighter contract definitions.
If this is a problem in your code base then it is necessary to understand in each case what the null represents:
- If the null represents an empty collection, use an empty collection.
- If the null represents an exceptional case, throw an Exception.
- If the null represents an accidentally uninitialized value, explicitly initialize it.
- If the null represents a legitimate value, test for it - or even better use a NullObject that performs a null op.
In practice this standard of clarity at the design level is non-trivial and requires effort and self-discipline to apply consistently to your code base.
Solution 3:
You don't.
Or rather, there's nothing special to do to try to 'prevent' NREs in C#. For the most part an NRE is just some type of logic error. You can firewall these off at interface boundaries by checking parameters and having lots of code like
void Foo(Something x) {
if (x==null)
throw new ArgumentNullException("x");
...
}
all over the place (much of the .Net Framework does this), so that when you do screw up, you get a slightly more informative diagnostic (the stack trace is even more valuable, though, and an NRE provides that too). But you still just end up with an exception.
(Aside: Exceptions like these - NullReferenceException, ArgumentNullException, ArgumentException, ... - typically should not be caught by the program, but rather just means "developer of this code, there is a bug, please fix it". I refer to these as a 'design time' exceptions; contrast these with true 'run time' exceptions that happen as a result of the run time environment (e.g. FileNotFound) and are intended to potentially be caught and handled by the program.)
But at the end of the day, you just have to code it right.
Ideally the majority of NREs would never happen because 'null' is a nonsensical value for many types/variables, and ideally the static type system would disallow 'null' as a value for those particular types/variables. Then the compiler would prevent you from introducing this type of accidental error (ruling out certain classes of errors are what compilers and type systems are best at). This is where certain languages and type systems excel.
But without those features, you just test your code to ensure you don't have code paths with this type of error (or possibly use some outside tools that can do extra analysis for you).
Solution 4:
You can easily check for a null reference before it causes an exception, but usually that is not the real problem, so you would just end up throwing an exception anyway as the code can't really continue without any data.
Often the main problem isn't the fact that you have a null reference, but that you got a null reference in the first place. If a reference is not supposed to be null, you shouldn't get past the point where the reference is initialised without having a proper reference.