Exploring some C# 8 features in a practical example

Manuel Riezebosch
Oct 4 · 3 min read

I’m delighted with the way Unmockable evolved from a red-green-refactor perspective. It’s packed with principles and patterns, but I think not over-engineered (yet). If you haven’t seen it, please check it out!

I was at the talk of Mads Torgensen (lead designer C#) at #TechoramaNL, and he inspired me to try out some new features.


Switch expressions

The ArgMatcherFactory creates a new argument matcher when the incoming type matches the Arg class. This class has two placeholder methods for which are specific matchers created, and an InvalidOperationException is thrown otherwise.

public static IArgumentMatcher? Create(Expression arg) => 
arg switch
{
MethodCallExpression call
when call.Method.DeclaringType == typeof(Arg) =>
call.Method.Name switch
{
nameof(Arg.Ignore) =>
(IArgumentMatcher)new IgnoreArgument(),
nameof(Arg.Where) =>
new LambdaArgument(call.Arguments.Single()),
_ =>
throw new InvalidOperationException()
},
_ => null
};

Compared to the original code I think it looks pretty neat and expressive.

public static IArgumentMatcher Create(Expression arg)
{
if (arg is MethodCallExpression call &&
call.Method.DeclaringType == typeof(Arg))
{
switch (call.Method.Name)
{
case "Ignore":
return new IgnoreArgument();
case "Equals":
return new EqualsArgument(call.Arguments[0]);
default:
throw new NotImplementedException();
}
}

return null;
}

Score: +1. Great feature, expressions everywhere ❤.

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#switch-expressions

Nullable reference types

This is probably the most outstanding feature of C# 8 and at the same time, the least appealing from a semantic perspective. It took me a while to understand what the compiler was telling me because it only tells you what could be wrong. But after I figured out, I think my source code improved immensely.

One small example on the default Equals method and the IEquatable<CollectionArgument> overload:

public bool Equals(CollectionArgument? other) => 
other != null && _collection.SequenceEqual(other._collection);

public override bool Equals(object obj) =>
Equals(obj as CollectionArgument);

In my original code, the type check was only performed on the Equals(object) method so the Equals(CollectionArgument could indeed be null.

public bool Equals(CollectionArgument other) => 
_collection.SequenceEqual(other._collection);
public override bool Equals(object obj) =>
obj is CollectionArgument other && Equals(other);

The null-check did not satisfy the compiler immediately. It looks like I had to add the ? to the parameter type to instruct the compiler I was aware the value could indeed be null and I’m taking care of that.

In my case, I could probably have come away with the null-forgiving !. operator, but in the end, I’m happy with the improved safeguards.

Score: +infinite. The impact of this feature is unmeasurable.

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#nullable-reference-types

Default interface members

Unfortunately, or luckily, this feature is only available if you target the newer runtime. Something I didn’t want to do yet because I want to support netstandard1.3 and the lowest runtime possible.

I was refactoring the ResultContext and at some point, almost all of the INextResult implementations shared a common implementation, so it felt like an almost perfect fit for default implementation. Almost since I have control over the source and the interface is not exposed to the outside world.

After several hard resets, I ended up with a significant refactor where the complete context disappeared and the INextResult evolved into IResult with a slimmer interface and specific implementations. Big props to Pim Elshoff for showing me a glimpse of DDD on Value Objects and Entities.

Score: unknown. I haven’t decided yet.

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#default-interface-members

Async enumerable

I’m very eager to try this one out, but unfortunately, there isn’t a single async method exposed in this framework. Luckily there are a lot in another framework I’m involved in, so stay tuned.

Score: +1. Superficial, but I’m sure we needed this.


This is it for the new features I’m most interested in. If I haven’t told you yet, checkout Unmockable. Not only the source but also the package.

Happy coding!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade