Null Or Empty Coalescing

code 0 comments suggest edit

In my last blog post, I wrote about the proper way to check for empty enumerations and proposed an IsNullOrEmpty method for collections which sparked a lot of discussion.

This post covers a similar issue, but from a different angle. A very long time ago, I wrote about my love for the null coalescing operator. However, over time, I’ve found it to be not quite as useful as it could be when dealing with strings. For example, here’s the code I might want to write:

public static void DoSomething(string argument) {
  var theArgument = argument ?? "defaultValue";
  Console.WriteLine(theArgument);
}

But here’s the code I actually end up writing:

public static void DoSomething(string argument) {
  var theArgument = argument;
  if(String.IsNullOrWhiteSpace(theArgument)) {
    theArgument = "defaultValue";
  }
  Console.WriteLine(theArgument);
}

The issue here is that I want to treat an argument that consists only of whitespace as if the argument is null and replace the value with my default value. This is something the null coalescing operator won’t help me with.

This lead me to jokingly propose a null or empty coalescing operator on Twitter with the syntax ???. This would allow me to write something like:

var s = argument ??? "default";

Of course, that doesn’t go far enough because wouldn’t I also need a null or whitespace coalescing operator???? ;)

Perhaps a better approach than the PERLification of C# is to write an extension method that normalizes string in such a way you can use the tried and true (and existing!) null coalescing operator.

Thus I present to you the AsNullIfEmpty and AsNullIfWhiteSpace methods!

Here’s my previous example refactored to use these methods.

public static void DoSomething(string argument) {
  var theArgument = argument.AsNullIfWhiteSpace() ?? "defaultValue";

  Console.WriteLine(theArgument);
}

You can also take the same approach with collections.

public static void DoSomething(IEnumerable<string> argument) {
  var theArgument = argument.AsNullIfEmpty() ?? new string[]{"default"};

  Console.WriteLine(theArgument.Count());
}

The following is the code for these simple methods.

public static class EnumerationExtensions {
  public static string AsNullIfEmpty(this string items) {
    if (String.IsNullOrEmpty(items)) {
      return null;
    }
    return items;
  }

  public static string AsNullIfWhiteSpace(this string items) {
    if (String.IsNullOrWhiteSpace(items)) {
      return null;
    }
    return items;
  }
        
  public static IEnumerable<T> AsNullIfEmpty<T>(this IEnumerable<T> items) {
    if (items == null || !items.Any()) {
      return null;
    }
    return items;
  }
}

Another approach that some commenters to my last post recommended is to write a Coalesce method. That’s also a pretty straightforward approach which I leave as an exercise to the reader. :)

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

33 responses

  1. Avatar for Abhishek
    Abhishek June 16th, 2010

    Naming convention seems incorrect. With the parameter taking single string, the name should be "item" and not "items".

  2. Avatar for Jinal
    Jinal June 16th, 2010

    Hi,
    I have confusion about this method.
    public static IEnumerable<T> AsNullIfEmpty<T>(this IEnumerable<T> items) {
    if (items == null || items.Any()) {
    return null;
    }
    return items;
    }
    In this condition should be like this.
    if (items == null || !items.Any())
    Otherwise if Enumerable has item then it return null.

  3. Avatar for Dino Viehland
    Dino Viehland June 16th, 2010

    This makes me think of Python rather than Perl and there's no need to be so cryptic. In Python you can do "a or b" where these get checked to see if they're "true" and then yield the 1st value which is true (and lazily evaluates, etc...). In Python "true" is defined as something like:
    None (null) is false
    Collections > 0 length are true, otherwise false (including strings)
    Primitives (int, float, etc...) are true if non-zero

    So you can always do "a or b" and get pretty reasonable results - and of course there's an "a and b" which yields the RHS if both are true as well.

  4. Avatar for Claus
    Claus June 16th, 2010

    Cool! Ironic thought that you didn't use the null coalescing operator? :)
    public static string AsNullIfWhiteSpace(this string item) {
    return String.IsNullOrWhiteSpace(item) ? null : item;
    }
    public static IEnumerable<T> AsNullIfEmpty<T>(this IEnumerable<T> items) {
    return (items == null || items.Any()) ? null : items;
    }

  5. Avatar for Claus
    Claus June 16th, 2010

    Ooops, there's a typo I think, in both your and my code:
    public static IEnumerable<T> AsNullIfEmpty<T>(this IEnumerable<T> items) {
    return (items == null || items.Any()) ? null : items;
    }
    Should be:
    public static IEnumerable<T> AsNullIfEmpty<T>(this IEnumerable<T> items) {
    return (items == null || !items.Any()) ? null : items;
    }
    to check if the items collection is null, or does NOT contain any elements.

  6. Avatar for Kim
    Kim June 16th, 2010

    great Phil! thanks!

  7. Avatar for cbp
    cbp June 16th, 2010

    Good idea, I've been wishing for something like this for a while.
    Here's an alternative though, which I prefer:
    public static string Coalesce(this string value, params string[] with)
    {
    if (with.Length == 0) return value;
    return string.IsNullOrEmpty(value)
    ? with[0].Coalesce(with.Skip(1).ToArray()) : value;
    }

    Which allows you to write something like:
    myStringA.Coalesce(myStringB, myStringC);

  8. Avatar for Damien Guard
    Damien Guard June 16th, 2010

    I tend to use the following LINQ pattern for choosing fallbacks/defaults:
    var item = new string[] { item1, item2, "SomeDefault }.First(s => !String.IsNullOrEmpty(s));
    [)amien

  9. Avatar for RichB
    RichB June 16th, 2010

    AsNullIfEmpty() reminds me of LINQ's DefaultIfEmpty(). Indeed, it may even be a better (homogeneous) name as the null coalescing operator only works on reference types and Default<T>(T) where T is a class will always be null anyway.

  10. Avatar for Jake Swenson
    Jake Swenson June 16th, 2010

    @Damien Guard I like that! Thanks!

  11. Avatar for Craig bovis
    Craig bovis June 16th, 2010

    What happens if the string argument is null though? Surely you'll get an exception since you're trying to run the asnullifwhitespace method on a null reference.

  12. Avatar for George Chakhidze
    George Chakhidze June 16th, 2010

    Here is the Coalesce implementation:

    public static T Coalesce<T>(params T[] args) where T : class
    {
    return args != null ? args.FirstOrDefault(item => item != null) : null;
    }
    public static Nullable<T> Coalesce<T>(params Nullable<T>[] args) where T : struct
    {
    return args != null ? args.FirstOrDefault(item => item.HasValue) : null;
    }

  13. Avatar for George Chakhidze
    George Chakhidze June 16th, 2010

    as extension method:

    public static T Coalesce<T>(this IEnumerable<T> items) where T : class
    {
    return items != null ? items.FirstOrDefault(item => item != null) : null;
    }
    public static Nullable<T> Coalesce<T>(this IEnumerable<Nullable<T>> items) where T : struct
    {
    return items != null ? items.FirstOrDefault(item => item.HasValue) : null;
    }

  14. Avatar for David S.
    David S. June 16th, 2010

    yesssssssssssssssssssssssssssssssssssss my brain feels good

  15. Avatar for Erlis Vidal
    Erlis Vidal June 16th, 2010

    @Craig: It will work, but this is confusing. It’s true that with this solution you type less, but you can confuse others. If you know that the call is performed to an extension method, then you know that the parameter could be null because that will be translated into
    StaticClass.StaticMethod( parameter )
    And this is totally valid, parameter could be null. But if you don’t know that the method is an extension one, you will be confused and probably add your own validations around this:

    X x = null;
    x.SomeMethod();

    You’ll expect this to throw an exception.
    I like the idea to use extension methods, but sometimes little details like this could cause some trouble.
    Have you consider using the extension proposed by Phil as a static method instead?
    something as simple as this:

    public static class MyConvert {
    ...
    public static string ToNullIfEmpty(string item) {
    return String.IsNullOrEmpty(items) ? null : item;
    }

    Usage:

    public static void DoSomething(string argument) {
    var theArgument = MyConvert.ToNullIfEmpty(argument) ?? "defaultValue";
    Console.WriteLine(theArgument);
    }


  16. Avatar for Andy Edinborough
    Andy Edinborough June 16th, 2010

    Isn't it simpler to just have an extension do it all?

    public static string NotEmpty(this string input, string otherwise) {
    return string.IsNullOrEmpty(input) ? otherwise : input;
    }

    So you would use it as:

    var theArgument = argument.NotEmpty("defaultValue");

  17. Avatar for Colin Wiseman
    Colin Wiseman June 16th, 2010

    var var var var var var var var var var var var var var var!!! Only use var when using Linq, otherwise stop being lazy (IMHO ;-)

  18. Avatar for James Hare
    James Hare June 16th, 2010

    @Colin: I used to feel the same way about var, but now I love it. It's just way to redundant to always have to write stuff like:
    SomeBigClassName myVar = new SomeBigClassName();

  19. Avatar for itchi
    itchi June 16th, 2010

    I'm disappointed there were no pictures with some subdued soccer/football innuendo. /insert Khano picture. red card!
    And my attempt to participate, a reply to Colin:
    var is not necessarily associated with LINQ nor is it a sign of being lazy. stackoverflow.com/.../use-of-var-keyword-in-c
    var should_i_use_var = answer ??? true;

  20. Avatar for tobi
    tobi June 16th, 2010

    this is my favorite string function:

    public static string NullOrWhitespaceToNullAndTrim(this string str)
    {
    if (string.IsNullOrEmpty(str))
    return null;
    var trim = str.Trim();
    if (trim.Length == 0)
    return null;
    return trim;
    }

  21. Avatar for Vince
    Vince June 17th, 2010

    As much as people like to say Extension methods can cause confusion, leads me to belive that some people's memory capacity is limited or non-existant.
    If you don't know if a method is an extension method, hover your mouse over the method and VS will show you. After that, next time you see that extension method, you'll remember!
    I think using extensions to check for nulls is a great idea.

  22. Avatar for Mauricio
    Mauricio June 17th, 2010

    I actually use such an operator in F# :

    let (<||>) a b = if String.IsNullOrWhiteSpace a then b else a
    let value = argument <||> "default"

    And since operators are regular functions and functions are regular variables I can scope it so I don't disturb outside code with my non-standard operators.

  23. Avatar for neronotte
    neronotte June 17th, 2010

    my very first extension method was this:
    public string OrIfNullOrEmpty(this string text, string defaultValue) {
    return String.IsNullOrEmpty(text) ? defaultValue : text;
    }
    that can be used this way:
    myString.OrIfNullOrEmpty("myDefaultValue");
    The same approach can be used for an "OrIfNullOrBlank" method... quick&easy!

  24. Avatar for James Nail
    James Nail June 17th, 2010

    Andy Edinborough's extension method (shown above in the comments) is pretty much exactly what I've been using... It's worked quite well for me.
    I've also used the same general approach (with generics) for handling null objects (if null, then use provided default value) -- although I'd like to figure a nice way to make it lazy (so that it doesn't evaluate my default value at all unless needed).

  25. Avatar for Noah Coad
    Noah Coad June 18th, 2010

    great bit of code, thanks for sharing!

  26. Avatar for patridge
    patridge June 20th, 2010

    @jrnail23,
    It may not be as pretty to call, but if your fallback value is too painful to evaluate every time, you can use an additional extension method taking a Func<string> (with a lambda calling syntax) so that your "otherwise" is not evaluated unless it is returned. I tweaked it with a hint of @neronotte's naming because it improved readability for me drastically.
    public static string IfEmptyUse(this string input, Func<string> otherwise) {
    return string.IsNullOrEmpty(input) ? otherwise() : input;
    }

    called this way
    var theArgument = argument.IfEmptyUse(_ => return "defaultValue");

  27. Avatar for NC
    NC June 21st, 2010

    Wow, fail developers here writing Java Syntax in C#.

  28. Avatar for Jessica
    Jessica June 22nd, 2010

    Seems like a lot of work when you already have the ?: ternary operator. Didn't know about that IsNullOrWhitespace function though.. useful!

  29. Avatar for cbp
    cbp June 22nd, 2010

    Just an update on a lot of the proposed methods above (including mine)...
    Be aware that with the following syntax, the second expression is never evaluated if the first expression is not null.
    var result = myNotNullString.ToNullIfEmpty()
    ?? AlternativeMethodDoesNotGetCalled();
    With some of the proposed extension methods above, all the alternatives get evaluated at the beginning regardless of which one is null:
    var result = myNotNullString
    .Coaelsce(ThisWillAlwaysBeEvaluated());
    This can lead to some unexpected results.

  30. Avatar for Mark Melville
    Mark Melville June 23rd, 2010

    I was thinking along the lines of George Chakhidze's implementation. Here's an idea of passing funcs that solves cbp's concern of not evaluating each one:
    public static string Coalesce(params Func<string>[] funcs)
    {
    var candidate = funcs.FirstOrDefault(s => !String.IsNullOrEmpty(s()));
    return candidate == null ? null : candidate();
    }
    called thusly:
    string test = Coalesce(ReturnsNonNullString, DoesNotGetCalled, () => "default value");

  31. Avatar for Arturo Guzman
    Arturo Guzman July 1st, 2010

    Decisions... decisions....
    +1 Andy Edinborough for the one function to rule them all.

  32. Avatar for Steve Calvert
    Steve Calvert July 6th, 2010

    Wrestling with C# this way makes me so jealous of javascript sometimes.
    var result = value || 'default';
    It's nice that 0, '', false, undefined, and null all evaluate to false.
    sigh...

  33. Avatar for Tuomas Hietanen
    Tuomas Hietanen July 6th, 2010

    Hi!
    Eric Lippert has a good blog-post about this:
    blogs.msdn.com/.../null-is-not-empty.aspx