C# Wishlist: Null-Safe Dereferencing

During tests of a web application I came across a runtime error cause by the line:

var startUrl = Request.UrlReferrer.AbsoluteUri;

From within the application, the line works fine. However, if you paste the current URL into the address bar and hit Enter, it will cause a NullReferenceException. The obvious solution is to rewrite as

string startUrl = null;
if (Request.UrlReferrer != null)
    startUrl = Request.UrlReferrer.AbsoluteUri;

Suddenly I *knew* I wanted that null-safe dereferencing operator everybody is talking about:

Personally I prefer the ?. notation to -> or ??? I found elsewhere:

var startUrl = Request?.UrlReferrer?.AbsoluteUri;

This answer on SO illustrates a solution that is currently possible, but a bit verbose for my taste:

R NotNull<T, R>(this T src, Func<T, R> f)
      where T : class
      where R : class 
{
    return src != null ? f(src) : null;
}

The class constraint on R is not necessary if you replace null with default(R):

R NotNull<T, R>(this T src, Func<T, R> f)
      where T : class 
{
    return src != null ? f(src) : default(R); 
}
Advertisements

3 Responses to C# Wishlist: Null-Safe Dereferencing

  1. Alex D says:

    Your code doesn’t handle Nullable types, and returns bogus value types. A correct implementation can handle reference and nullable types on the left-hand side, and returns either reference or nullable types.

    public static TOut
    NullSafe(
    this TIn obj,
    Func memberAction ) where TIn : class where TOut : class
    {
    return !ReferenceEquals(obj, null) ? memberAction(obj) : null;
    }

    public static TOut
    NullSafe(
    this TIn? obj,
    Func memberAction ) where TIn : struct where TOut : class
    {
    return obj.HasValue ? memberAction(obj.Value) : null;
    }

    // If the return type of the lambda is not a nullable type but a value type
    // you should write a cast to nullable in the lambda

    public static TOut?
    NullSafe(
    this TIn obj,
    Func memberAction ) where TIn : class where TOut : struct
    {
    return !ReferenceEquals(obj, null) ? memberAction(obj) : null;
    }

    public static TOut?
    NullSafe(
    this TIn? obj,
    Func memberAction ) where TIn : struct where TOut : struct
    {
    return obj.HasValue ? memberAction(obj.Value) : (TOut?)null;
    }

    // Or use the following functions
    // Unfortunately, they are named differently because the compiler doesn’t allow
    // overloads that differ only in their generic type constraints

    public static TOut?
    NullSafeV(
    this TIn obj,
    Func memberAction ) where TIn : class where TOut : struct
    {
    return !ReferenceEquals(obj, null) ? memberAction(obj) : (TOut?)null;
    }

    public static TOut?
    NullSafeV(
    this TIn? obj,
    Func memberAction ) where TIn : struct where TOut : struct
    {
    return obj.HasValue ? memberAction(obj.Value) : (TOut?)null;
    }

  2. […] Alex D commented on one of my C# Wishlist posts providing more elaborate code on this […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: