Suppose you have this simple class (has no business meaning is valid only as example)

public class MyObject { public static MyObject NullValue = new MyObject() { Value = -100, Name = String.Empty }; public Int32 Value { get; set; } public String Name { get; set; } public string Greet() { return "Hey!! My value is " + Value; } }

It is a simple class with two properties and a method Greet(). It use the null object pattern, because it defines an object with Value=-100 and Name=String.Empty as the NullValue. But how this object works with LINQ? Try this code:

IEnumerable<MyObject> samples = new MyObject[] { new MyObject() {Value = 10, Name = "alkampfer"}, new MyObject() {Value = 11, Name = "guardian"} }; Console.WriteLine( samples.Where(o => o.Name == "alkampfer").SingleOrDefault().Greet()); Console.WriteLine( samples.Where(o => o.Name == "someother").SingleOrDefault().Greet());

Ooopps, this raise a NullReferenceException, because the second LINQ query searches for an object called “someother”, it does not find any object that satisfy the query, then the SingleOrDefault() returns null, and here it is the exception. The question is, “is there a way to make SingleOrDefault returns my null object instead of null?”. The answer is straightforward

public static class MyLinqExtension { public static MyObject SingleOrDefault(this IEnumerable<MyObject> source) { return System.Linq.Enumerable.SingleOrDefault(source) ?? MyObject.NullValue; } }

This extension method is more specific than the generic SingleOrDefault<TSource>(this IEnumerable<TSource> ) defined in the System.Linq.Enumerable extension class, so it gets called instead of the default one when the source contains MyObject and not general objects. The method use the base implementation of the SingleOrDefault, but with the use of the ?? operator, it changes null into your null object instance. Now if you run the sample again you will obtain.

Hey!! My value is 10 Hey!! My value is -100

And you can see that now the null object Greet() function is called.

alk.

Tags:

4 Responses to “LINQ, SingleOrDefault and NullObject”

  1. Great example. It sucks that we have to write our own overloads for the Default extensions. Maybe MS will fix this in the next version of LINQ.

    LINQ Exchange – Learn LINQ and Lambda Expressions

  2. Hey, thanks for th start. Its annoying to have to create null objects this way, so I thought I would extend it with reflection:

    public static TSource SingleOrEmpty(this IEnumerable source, Func predicate)
    {
    var myNullObject = (TSource)Activator.CreateInstance(typeof(TSource));
    var myResult = source.SingleOrDefault(predicate);
    return myResult == null ? myNullObject : myResult;
    }

  3. Not sure how to post code here, because that didnt work! I will try this:

    ” public static TSource SingleOrEmpty(this IEnumerable source, Func predicate)
    {
    var myNullObject = (TSource)Activator.CreateInstance(typeof(TSource));
    var myResult = source.SingleOrDefault(predicate);
    return myResult == null ? myNullObject : myResult;
    }”

  4. doesn’t this work:

    samples
    .Where(o => o.Name == “someother”)
    .DefaultIfEmpty(MyObject.NullValue)
    .Single()
    .Greet();