Today I would like to share with you one super-simple but powerful function that I have been using in my C# code for a while.

Let me show a few code samples that have something in common:

foreach (var dir in Directories())
  Directory.GetParent(dir) ?? throw new SpecialException();
Action callback = () =>
  users.TryGetValue(user, out var info) ? Print(info) : LogError();
while (!reader.EndOfStream)
  type switch {
    Types.One => ReadOne(reader),
    Types.Another => ReadAnother(reader),
    _ => Skip(reader)
  };

What they have in common is that although they look like a perfectly normal C# code, in fact, all of them cannot be compiled successfully. In all these cases the compiler throws

error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

There are two ways to fix this error:

  • rewrite code to statement
  • use a "magic" function that converts expressions to statements

Rewriting is trivial, of course. The above code fragments could easily be fixed:

foreach (var dir in Directories())
  if (Directory.GetParent(dir) == null)
    throw new SpecialException();
Action callback = () => {
  if (users.TryGetValue(user, out var info))
    Print(info);
  else
    LogError();
};
while (!reader.EndOfStream)
  switch (type) {
    case Types.One:
      ReadOne(reader);
      break;
    case Types.Another:
      ReadAnother(reader);
      break;
    default:
      Skip(reader);
      break;
  }

But what the fun in that? Its like twice more code lines to do the same things. Not good 😐.

The "magic" function that helps me to write concise code is:

static object Void<T>(T value = default) => null;

It is simple but look how it can fix these code fragments:

foreach (var dir in Directories())
  Void(Directory.GetParent(dir) ?? throw new SpecialException());
Action callback = () =>
  Void(users.TryGetValue(user, out var info) ? Print(info) : LogError());
while (!reader.EndOfStream)
  Void(type switch {
    Types.One => ReadOne(reader),
    Types.Another => ReadAnother(reader),
    _ => Skip(reader)
  });

This function is a generic one, so it does not unbox value types. It also helps unify the return types of ternary operators and switch expressions.


Learn about Zombie Scrum, WaterScrum, FrAgile, and TrAgile, new features of C# 8, or how to debug memory leaks on macOS on Udemy.


Update: one of the redditors suggested using a discard instead of Void() to convert expressions to statements. It works this way:

foreach (var dir in Directories())
  _ = Directory.GetParent(dir) ?? throw new SpecialException();