7

I want to do this

var path = HttpContext.Current.Request.ApplicationPath;

If any of the Properties along the way is null, i want path to be null, or "" would be better.

Is there an elegant way to do this without Ternaries?

ideally i would like this behavior (without the horrible performance and ugliness) string path;

try
{
    path = HttpContext.Current.Request.ApplicationPath;
}
catch
{
    path = null;
}

Thank you

AK_
  • 7,981
  • 7
  • 46
  • 78

4 Answers4

11

[EDIT]

C# 6 got released a while ago and it shipped with null-propagating operator ?., which would simplify your case to:

var path = HttpContext?.Current?.Request?.ApplicationPath

For historical reasons, answer for previous language versions can be found below.


I guess you're looking for Groovy's safe dereferencing operator ?., and you're not the first. From the linked topic, the solution I personally like best is this one (that one looks quite nice too). Then you can just do:

var path = HttpContext.IfNotNull(x => x.Current).IfNotNull(x => x.Request).IfNotNull(x => x.ApplicationPath);

You can always shorten the function name a little bit. This will return null if any of the objects in the expression is null, ApplicationPath otherwise. For value types, you'd have to perform one null check at the end. Anyway, there's no other way so far, unless you want to check against null on every level.

Here's the extension method used above:

    public static class Extensions
    {
    // safe null-check.
    public static TOut IfNotNull<TIn, TOut>(this TIn v, Func<TIn, TOut> f) 
            where TIn : class  
            where TOut: class 
            { 
                    if (v == null) return null; 
                    return f(v); 
            }       
    }
Community
  • 1
  • 1
Patryk Ćwiek
  • 14,078
  • 3
  • 55
  • 76
  • any sensible way to override an operator to do this? – AK_ May 30 '12 at 12:14
  • @AK_ Nope, you can't just define your brand own operator, and overriding... That would be nasty in this case :) .NET team is aware of the 'requests' made for this kind of functionality, but AFAIK it won't ship in C# 5 --> [here](https://connect.microsoft.com/VisualStudio/feedback/details/192177/a-bit-more-c-syntactic-sugar-for-nulls) and [here](https://connect.microsoft.com/VisualStudio/feedback/details/432830/new-c-operator-for-cascaded-testing-of-nullable-results) – Patryk Ćwiek May 30 '12 at 12:15
  • (Continued, bah, timeout on edits) I can't see a way to override this functionality as an operator, considering it accepts a lambda expression - I don't know if that's possible, but even if it was, it would be ugly :). Moreover overloading an existing operator for an arbitrary type (if it even was possible) would reveal a brand new field for collisions and unexpected WTFs. – Patryk Ćwiek May 30 '12 at 12:26
  • Added the extension method you've used in your example. Nice solution! – Matt Sep 12 '12 at 09:11
  • Love it! Added the extension method to our framework library as well. – Timo Kosig Dec 11 '13 at 11:39
4

UPDATE (November 2014)

C# 6 contains something called the Null Propagation Operator, which means that there is language support for this. Your example can be written as follows in C# 6:

var path = HttpContext?.Current?.Request?.ApplicationPath;

If any of the parts contains null, the complete expression will return null.


You can write something like this:

string value = NullHelpers.GetValueOrNull(
    () => HttpContext.Current.Request.ApplicationPath);

The simplest way to implement this NullHelpers.GetValueOrNull is probably something like this:

public static T GetValueOrNull<T>(Func<T> valueProvider) 
    where T : class
{
    try
    {
        return valueProvider();
    }
    catch (NullReferenceException)
    {
        return null;
    }
}

But by far the coolest way to solve this is by using Expression trees:

public static T GetValueOrNull<T>(
    Expression<Func<T>> valueProvider) 
    where T : class
{
    var expression = (MemberExpression)
        ((MemberExpression)valueProvider.Body).Expression;

    var members = new List<MemberExpression>();

    while (expression != null)
    {
        members.Add(expression);

        expression = 
            (MemberExpression)expression.Expression;
    }

    members.Reverse();

    foreach (var member in members)
    {
        var func = Expression.Lambda<Func<object>>(member).Compile();

        if (func() == null)
        {
            return null;
        }
    }

    return valueProvider.Compile()();
}

This is also the slowest way to do things, since each call will do one or multiple JIT compiler invocations, but...

It is still cool ;-)

Steven
  • 166,672
  • 24
  • 332
  • 435
2

The shortest and most performant path is to perform the null check against every level. For reuse you can wrap that code up into a helper function or perhaps an extension method. This will let you safely access it via that function, but still consistently perform the null check.

Example:

public void DoSomething()
{
  // Get the path, which may be null, using the extension method
  var contextPath = HttpContext.Current.RequestPath;
}


public static class HttpContextExtensions
{
  public static string RequestPath(this HttpContext context)
  {
    if (context == null || context.Request == null)
    {
      return default(string);
    }

    return context.Request.ApplicationPath;
  }
}
STW
  • 44,917
  • 17
  • 105
  • 161
  • It's short because it encapsulates the checks in a reusable method; meaning that any time you want to get the value it's only a single method call. It's better than trying to consistently perform the same null checks in many locations, and also simpler. – STW May 30 '12 at 12:42
2

In May 2012, when you asked the question, I didn't see a simpler solution than the try ... catch you've provided. The only alternative - checking each part against null with "if" or "?" looked uglier (but is possibly a bit faster).

Either you had to write:

path = HttpContext!=null 
    ? (HttpContext.Current!=null 
            ? (HttpContext.Current.Request!=null 
                    ?(HttpContext.Current.Request.ApplicationPath!=null 
                            ? HttpContext.Current.Request.ApplicationPath 
                            : null) 
                    : null) 
            : null) 
    : null;

or:

if (HttpContext == null || HttpContext.Current == null 
    || HttpContext.Current.Request == null 
    || HttpContext.Current.Request.ApplicationPath  == null)
    path = null;
else
    path = HttpContext.Current.Request.ApplicationPath;

both are doing it without exception handling. Note that both are using "shortcuts" to abort the check if any null value is found.


Update (December 2017): Since C# Version 6 and higher, there is a better solution available, the so called Elvis-Operator (also known as null-coalescing operator ?. and x?[i] for arrays), which you can use. The example above

path = HttpContext!=null 
    ? (HttpContext.Current!=null 
            ? (HttpContext.Current.Request!=null 
                    ?(HttpContext.Current.Request.ApplicationPath!=null 
                            ? HttpContext.Current.Request.ApplicationPath 
                            : null) 
                    : null) 
            : null) 
    : null;

looks much nicer this way:

path = HttpContext?.Current?.Request?.ApplicationPath;

which does exactly the same and is IMHO much more than "just" syntactical sugar. Combined with an appended ?? value you can easily replace null by some other value, e.g.

path = (HttpContext?.Current?.Request?.ApplicationPath) ?? "";

This makes the path variable empty if no non-null value can be obtained.

Matt
  • 25,467
  • 18
  • 120
  • 187