Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Preventing null propagation

3 views
Skip to first unread message

Weeble

unread,
Apr 19, 2007, 1:28:14 PM4/19/07
to
Back in C++, I had a type that looked something like this (entering
from memory so this might not quite compile):

template <class T>
class NotNull
{
private:
T* value;
public:
NotNull(T* ptr)
:value(ptr)
{
if (ptr==0)
{
// Throw an exception here.
}
}
T& operator*()
{
return *value;
}
// ...
private:
// Private constructor prevents default initialisation:
NotNull() {}
};

There's a bit more to it that I've omitted there, but essentially it
behaves like a pointer except that it throws an exception if you try
to initialise it to null. This is really handy to use as a parameter
type. A method that takes these as parameters doesn't need to have a
bunch of null argument tests because it knows that it's simply not
possible for these to be null. (Sadly C++ references can end up null
through careless code, which is why this class is used rather than
references.) I've been trying to create some kind of analogue in C#,
because otherwise it seems necessary to test for null arguments in
virtually every method, since every single class reference could be
null.

For a start, I can't use a class for this because the reference to it
itself could be null. I've been looking at using a struct, and this
partially works. I can do this:

struct NotNull<T>
{
public T Value
{
get
{
if (value==null)
{
throw new NotNullException("An uninitialised NotNull
was accessed.");
}
return value;
}
}
public NotNull(T v)
{
if (v==null)
{
throw new NotNullException("A NotNull was initialised to
null.");
}
value = v;
}
private T value;
};

This looks like it will more-or-less work, but I don't like the fact
that the default constructor allows a null NotNull to exist in the
first place, and necessitates the null test in the get accessor. A
method that takes one of these as a parameter cannot be entirely
robust to bad usage unless it does the null argument testing that this
was supposed to avoid. E.g.:

void AddToMyCollection(NotNull<Widget> w)
{
AllocateSlot();
PutWidgetInSlot(w.Value);
}

Since the backup null test happens only when w.Value is accessed, an
exception could be thrown after the call to AllocateSlot() and
presumably leaves the collection in an invalid state. It's not
*likely*, because it would require the caller to do something like:

AddToMyCollection(NotNull());

...but I feel a bit uneasy that it's not as water-tight as the C++
solution was. Any suggestions? Is there a better way to do this?

Andy

unread,
Apr 19, 2007, 3:09:56 PM4/19/07
to

Don't apply what you know about C++ to C#. Syntactically they are
similar, but they are different languages. Generics != C++
templates.

It looks like you're trying to do some fancy check to make sure null
is not added to your collection. Instead, simply code your method to
ensure the parameter is null, and if it is, throw an
ArgumentNullException.

Weeble

unread,
Apr 23, 2007, 5:24:01 AM4/23/07
to
On 19 Apr, 20:09, Andy <a...@med-associates.com> wrote:
> Don't apply what you know about C++ to C#. Syntactically they are
> similar, but they are different languages. Generics != C++
> templates.

That's pretty clear to me. I tried to use them for numeric tasks and
found out that there's no way to use arithmetic operators on them. I
guess they really are only much use for collections.

> It looks like you're trying to do some fancy check to make sure null
> is not added to your collection. Instead, simply code your method to
> ensure the parameter is null, and if it is, throw an
> ArgumentNullException.

Thanks, but what I'm saying is that with this approach I could easily
have to start every public method with:

if (arg1==null)
{
throw new ArgumentNullException("arg1");
}
if (arg2==null)
{
throw new ArgumentNullException("arg2");
}
if (arg3==null)
{
throw new ArgumentNullException("arg3");
}

-OR-

if (arg1==null || arg2==null || arg3==null)
{
throw new ArgumentNullException("Something was null! Um, not sure
what. Sorry.");
}

I was hoping there was a solution (like in C++) where I can make sure
these arguments can't be null even before the method is entered.
Microsoft's guidelines say never to throw NullReferenceException, but
they don't seem to provide any good way of ensuring this other than
mountains of null-checking code. :(

0 new messages