16

I'm wondering if there is any approach to implement generic null object pattern in C#. The generic null object is the subclass of all the reference types, just like Nothing in Scala. It seems like

public class Nothing<T> : T where T : class

But it can't compile and I've no idea how to implement the methods of T to provide default behavior or throw an exception. Here are some thinkings:

  1. Use reflection?
  2. Use expression tree when creating Nothing<T>? It maybe looks like Moq. And another question comes: Is it OK to use mock framework/library in product codes?
  3. Use dynamic types?

I KNOW maybe I should implement particular null object for particular type. I'm just curious to know if there is any solution.

Any suggestion? Thanks.

Kirin Yao
  • 1,606
  • 2
  • 14
  • 21
  • This might be useful: http://stackoverflow.com/questions/2522928/how-can-i-implement-the-null-object-design-pattern-in-a-generic-form – Maarten Jul 05 '12 at 07:40

5 Answers5

11

With generics, you can't define inheritance from T. If your intent is to use if(x is Nothing<Foo>), then that just isn't going to work. Not least, you'd need to think about abstract types, sealed types, and non-default constructors. However, you could do something like:

public class Nothing<T> where T : class, new()
{
    public static readonly T Instance = new T();
}

However, IMO that fails most of the key features of a null-object; in particular, you could easily end up with someone doing:

Nothing<Foo>.Instance.SomeProp = "abc";

(perhaps accidentally, after passing an object 3 levels down)

Frankly, I think you should just check for null.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks. I don't intend to use `if(x is Nothing – Kirin Yao Jul 05 '12 at 08:09
  • 1
    @KirinYao you would have to do that on a per-type basis then, or use extension methods (which then has separate issues with polymorphism) – Marc Gravell Jul 05 '12 at 08:12
  • What about the 2nd solution I mentioned? Can I use expression tree to mock the behavior like Moq? Is that good to use mock frameworks in product code? – Kirin Yao Jul 05 '12 at 08:33
  • @Kirin - So, you want `GetX()` to return a `Nothing` instead of `null`. This is pretty similar to mocking an item, but defaulting to methods and properties that return `Nothing<>` again and again. (personally, I don't think that's a very good idea. You may return a null object of a specific implementation, but doing so generally for all class... seems risky.) – Kobi Jul 05 '12 at 08:40
8

How about this?

public class Nothing<T> where T : class
{
     public static implicit operator T(Nothing<T> nothing)
     {
          // your logic here
     }
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
1

Since there are sealed classes you can't make such inheritance in generic case. Many classes are not expected to be derived from, so it may not be good idea if it would work.

Using implicit operator as suggested by @abatishchev sounds like a possible approach.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
1

I use something like this in my projects:

public interface IOptional<T> : IEnumerable<T> { }
public interface IMandatory<T> : IEnumerable<T> { }

Two interface derived from IEnumerable for compatibility with LINQ

public class Some<T> : IOptional<T>
{
    private readonly IEnumerable<T> _element;
    public Some(T element)
        : this(new T[1] { element })
    {

    }
    public Some()
        : this(new T[0])
    {}
    private Some(T[] element)
    {
        _element = element;
    }
    public IEnumerator<T> GetEnumerator()
    {
        return _element.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

public class Just<T> : IMandatory<T>
{
    private readonly T _element;

    public Just(T element)
    {
        _element = element;
    }
    public IEnumerator<T> GetEnumerator()
    {
        yield return _element;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Implementation of classes Just and Some

Notice: Implementation of this classes is very similar, but it has one diference. Class Just derived from interface IMandatory and has only one constructor, which guarantees that instance of class Just always has a value inside.

public static class LinqExtensions
{
    public static IMandatory<TOutput> Match<TInput, TOutput>(
        this IEnumerable<TInput> maybe,
        Func<TInput, TOutput> some, Func<TOutput> nothing)
    {
        if (maybe.Any())
        {
            return new Just<TOutput>(
                        some(
                            maybe.First()
                        )
                    );
        }
        else
        {
            return new Just<TOutput>(
                        nothing()
                    );
        }
    }
    public static T Fold<T>(this IMandatory<T> maybe)
    {
        return maybe.First();
    }
}

Some extensions for practicality

Notice: Extension method Match required two functions and return IMandatory, after this, extension method Fold use .First() without any check.

Now we can use full power of LINQ and write code similar this one (I mean monads .SelectMany())

var five = new Just<int>(5);
var @null = new Some<int>();

Console.WriteLine(
            five
                .SelectMany(f => @null.Select(n => f * n))
                .Match(
                    some: r => $"Result: {r}",
                    nothing: () => "Ups"
                )
                .Fold()
        );
giokoguashvili
  • 2,013
  • 3
  • 18
  • 37
  • I took this idea from Zoran Horvat [post](http://www.codinghelmet.com/?path=howto/reduce-cyclomatic-complexity-option-functional-type) – giokoguashvili Jun 27 '17 at 21:08
0

How about the already existing implementation of Nullable in the .NET Framework? http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx

thmsn
  • 1,976
  • 1
  • 18
  • 25