C# – Most Elegant Way to Write a Try Method in C# 7

c

I am writing a type of Queue implementation that has a TryDequeue method that uses a pattern similar to various .NET TryParse methods, where I return a boolean value if the action succeeded, and use an out parameter to return the actual dequeued value.

public bool TryDequeue(out Message message) => _innerQueue.TryDequeue(out message);

Now, I like to avoid out params whenever I can. C# 7 gives us out variable delcarations to make working with them easier, but I still consider out params more of a necessary evil than a useful tool.

The behaviour I want from this method is as follows:

  • If there is an item to dequeue, return it.
  • If there are no items to dequeue (the queue is empty), provide the caller with enough information to act appropriately.
  • Don't just return a null item if there are no items left.
  • Don't throw an exception if trying to dequeue from an empty queue.

Right now, a caller of this method would almost always use a pattern like the following (using C#7 out variable syntax):

if (myMessageQueue.TryDequeue(out Message dequeued))
    MyMessagingClass.SendMessage(dequeued)
else
    Console.WriteLine("No messages!"); // do other stuff

Which isn't the worst, all told. But I can't help but feel there might be nicer ways to do this (I'm totally willing to concede that there might not be). I hate how the caller has to break up it's flow with a conditional when all it wants to is get a value if one exists.

What are some other patterns that exist to accomplish this same "try" behaviour?

For context, this method may potentially be called in VB projects, so bonus points for something that works nice in both. This fact should carry very little weight, though.

Best Answer

Use an Option type, which is to say an object of a type that has two versions, typically called either "Some" (when a value is present) or "None" (when there isn't a value) ... Or occasionally they're called Just and Nothing. There are then functions in these types that let you access the value if it is present, test for presence, and most importantly a method that lets you apply a function that returns a further Option to the value if it's present (typically in C# this should be called FlatMap although in other languages it is often called Bind instead... The name is critical in C# because having s method of this name and type let's you use your Option objects in LINQ statements).

Additional features may include methods like IfPresent and IfNotPresent to invoke actions in the relevant conditions, and OrElse (which substitutes a default value when no value is present but is a no op otherwise), and so on.

Your example might then look something like:

myMessageQueue.TryDeque()
    .IfPresent( dequeued => MyMessagingClass.SendMessage(dequeued))
    .IfNotPresent (() =>  Console.WriteLine("No messages!")

This is the Option (or Maybe) monad pattern, and it is extremely useful. There are existing implementations (eg https://github.com/nlkl/Optional/blob/master/README.md) but it isn't hard to to your own either.

(You may wish to extend this pattern so that you return a description of the error cause instead of nothing when the method fails ... This is entirely achievable and is often called the Either monad; as the name implies you can use the same FlatMap pattern to make it easy to work with in that case, too)