C# Programming Practices – Is Using Nullable for Non-Value Types a Bad Practice?

cprogramming practices

After writing this question I found out that Nullable<T> has a type constraint of struct on T so you cannot actually use Nullable for
reference types. However, some good answers interpreted the questions
as 'if you could' or 'if you would write your own Nullable or
NonNullable type'. This interpretation has lead to some nice answers
so I've decided to not close or delete the question.

I know the nullable construct in C# was introduced to support null for value types. However, the language does not seem to have a problem with using nullable on other types. I wonder if this is a bad practice. I've come up with some arguments for both sides, but I can't decide.

Pros

  • Foo? x makes it exceptionally clear that a variable can be null.

Cons

  • If Foo is not a value type we create a struct with a reference type which is a bad practice.
  • Why wrap a variable that can already be null with more boilerplate code. Comments or naming can already indicate that the value can be null.
  • Not marking the object as nullable does not guarantee that it will not be null. So inconsistent use will lead to confusion.
  • Performance overhead? (Extremely neligible in most cases).
  • It makes the code slightly harder to read

With nullable

Foo? x;

// <snip>

x = null;

// <snip>

if(x.HasValue) { x.Value.Bar(); }

Without

Foo x; // Might be null

// <snip>

x = null;

// snip>

if(x != null) { x.Bar(); }

Best Answer

As others have said, this isn't possible, but there are a couple of easy constructs you can create yourself that achieve similar aims.

Maybe<T>

public struct Maybe<T> where T : class
{
   public bool HasValue { get; private set; }

   private readonly T _value;
   public T Value
   {
       get
       {
           if(!HasValue){throw new InvalidOperationException();}
           return _value;
       }
   }

   public Maybe(T value) : this()
   {
       if(value==null) { throw new ArgumentNullException("value"); }
       HasValue = true;
       _value = value;
   }
}

(This could also be implemented other ways, such as an IEnumerable<T> with the constraint that it has exactly 0 or 1 items)

NotNull<T>

public class NotNull<T> where T : class
{
    public readonly T Value;

    public NotNull(T value)
    {
        if(item == null){ throw new ArgumentNullException("value"); }
        Value = value;
    }
}

Maybe<T> essentially just reimplements Nullable<T> for reference types. It has similar advantages and disadvantages to the ones described in your post. It's probably only valuable if you have a convention throughout your project to use it for any value where null is a valid value.

NotNull<T> is likely to be more directly what you want, as MainMa stated. By passing around values wrapped in this type you can remove the need to check whether a value is null in a guard clause. However, there's no way to completely prevent a NotNull<T> from itself being null. You can't make it a struct because of the requirement of a default constructor, which would leave Value null.

(EDIT: As others have pointed out, in C# 6 you will be able to have a parameterless constructor for a struct, but it will not be used when initializing arrays or getting the result of default(T), so you still can't really rely on the guarantee that Value won't be null)

So while both of these potentially add some value in signalling whether null should be considered valid or not, they're both limited in that they require constant adherence to a convention, in addition to the boilerplate and readability issues. Whether the trade-off is worth it would be a matter of judgement, but remember that code contracts or other static analysis tools also exist as a possible alternative way of addressing this issue.