Confused with Uncle Bob explanation on handling Null objects in book Clean Code
I was reading Uncle Bob book today on Exception handling and what I could recollect from handing null values was that methods should not be handling null values because it clutters the code. I am a little confused with it. I have always thought that a method 开发者_如何学Goshould always make sure that it's dependencies are not null (unless they are injected in constructor and constructor assures of nullability). For example, if I have a method
public void SendMessage(IEmailSender emailSender, contactList list)
{
if(emailSender == null)
{
throw new ArgumentNullException("Failed to send
message.",MethodBase.GetCurrentMethod().GetParameters[0].Name);
}
if(list == null)
{
throw new ArgumentNullException("Failed to send
message.",MethodBase.GetCurrentMethod().GetParameters[1].Name);
}
// rest of code goes here
}
Am I missing something?
There are two perspectives:
On the one hand, with your approach you would always tell the caller what exactly he did wrong by calling your method. Which is great for the caller because he can fix it right away when he gets your exception. This would be true and valid if you where writing API code that is used by a third party.
On the other hand, if you call your method yourself, a reasonable argument to throw an exception is, because you want to be able to handle this situation with a catch block inside your calling code! If you have no reason to handle it somewhere, why throwing an exception at all? The only reason i see is, to have a detailed error logging by catching those exceptions in a GlobalExceptionHandler.
So you see we have two categories of exceptions here: The one for developers, to avoid wrong usage of APIs, and the other one to be used as the method's error-result.
If you are writing API code that will be used by others, your choice would be, not to listen to Bob ;-)
For those who did not read CleanCode, Bob is suggesting two things:
1.You should not write methods that return null (To avoid unnecessary checks afterwards). So Instead of writing this:
var myObject = GetObjectThatDoesSomthing();
if(myObject != null)
{
myObject.DoSomething();
}
... you should be able to write this:
var myObject = GetObjectThatDoesSomething();
myObject.DoSomething();
Cleaner.
2.You should not pass null to your methods to avoid unnecessary checks at the beginning of a method, like here:
public Point Add(Point p1, Point p2)
{
if(p1 == null) throw ArgumentException();
if(p2 == null) throw ArgumentException();
...
}
The point of these rules is: if you stick with it, you know that you dont have to write these null-checks and your code gets cleaner and easier to read. But at the moment you are using third party code, you are not able to tell if they have applied the same rules in their API, so you are starting to pre- or postcheck again. The same thing when you write an API for others: How do the consumers of your API know that you have coded with Bobs rules in mind...
I haven't read the book but I can only imagine that Uncle Bob is advocating the use of the Null Object Pattern in preference to explicit null reference handling.
for example, rather than
if(log != null)
log.Write("My log message");
You could instead create an ILogger
interface containing a Write
method and create two classes that implement this interface: a NullLogger
and a FileLogger
. The NullLogger
would have an empty body for the Write
method's implementation.
In my mind this is different to your explicit pre-condition validation that you have in your example
It depends what type of code are you writing. If your public method is designed to be used by the wide range of developers non familiar with usage it makes always sense to check parameters and throw a verbose exception.
If you are writing a private method which is only used from the same class or some internal called by another friendly class also written by you or by your collaborator it makes less sense to make paranoia null checks. Your injection design and tests must ensure your internas are not getting null values.
And if private/internal method parameters still get nulls it is anyway too late. Throwing ArgumentNull exception form a private/internal method does not help external user to fix the cause, so it makes no difference for him either to get ArgumentNull or NullReference exception.
精彩评论