A real answer to your question has to deal with other questions that really only you can answer:
- What is the intended usage of your base class?
- Is your
base.DoSomething(someProp)
supposed to be called first?
- How does the base class handle the null parameter?
- Is null a valid value? In some cases it is, so throwing exceptions would be wrong.
After that I will provide some guidelines that will help when debugging:
You don't always have to throw exceptions
Providing default values can be a good way to keep the system stable, particularly in cases where the parameter might intentionally be null. In those cases it might be better to simply return immediately. Exceptions are costly, and they are often overused.
Sometimes you can do just fine with Debug.Assert()
to make it painfully obvious that something is wrong with the development build, which also gives the programmer the option to step in to the code with the debugger with the current stack. In the production build those checks go away, which can speed up the runtime--just be careful that the assertions don't have side effects you are depending on at run time.
Throw the Appropriate Exception
When you test a parameter and find it is null, you should throw new System.ArgumentNullException(nameof(parameter));
. This helps weed out accidental NullReferenceException
s from the things you checked for.
When parameters need more restrictions than simply existing (i.e. must be a positive number greater than 0, etc.) then throw the appropriate ArgumentException
that helps the user understand what is wrong.
Providing the name of the parameter to the ArgumentNullException
greatly expedites debugging--particularly when there are multiple parameters. The exception generates an easy to read message that includes the name of the parameter you provided, and a stack trace leading to the method that was called. Anything you can do to minimize time in a debugger will help you fix problems faster.
Make sure the parameter is not null before you access it
Every programmer is responsible to make sure that the parameter is valid before they do something with it. If you make it known that your base class is intended to be called first and it handles the null parameters, that still doesn't excuse the programmers who create subclasses from checking for null themselves if they violate that expectation.
Design for debugging
Do everything you can to ensure your code is as easy to debug and maintain as you can. The fact of the matter is that the hardest part of fixing bugs is finding where they happen in the first place. Often this is a trade-off between throwing exceptions and doing the best it can when the parameter provided is null.
I personally believe that subclassing is over-used, and can lead to unpredictable use cases because the clients of the code can have access to certain class state and do things that were never intended to begin with. If you use subclassing, then make the extension points abstract
. If composition can get you what you want, it may be a better and more predictable pattern to extend the base functionalities.
Make extension points abstract
instead of virtual
You see this pattern all over the place in the WinForms API. You have the method that promises to do something, like updating and redrawing. The base class has a pure abstract
method with the prefix Do
in front like this:
public abstract class MyBaseClass
{
public void UpdateSomething(ClassA parameter)
{
if (parameter == null) throw new ArgumentNullException(nameof(parameter));
DoUpdateSomething(parameter);
}
protected abstract void DoUpdateSomething(ClassA parameter);
}
This approach allows you to do all your sanity checks in the wrapper method, and only call the subclass implementation when everything is valid. This is going to be the only way you can ensure that the proper checks are made in the right order and give users of your base class the confidence that they are using it correctly.
ArgumentNullException
.