I started out with C# since then I’ve learned other languages and one of my favorites is Golang.
When I was reading the release notes from C# 8 I saw the new using
declaration and through it was awesome… I also realized it could be misused to give C# the defer
keyword from Golang.
Whats defer
in Golang do?
defer
in Golang lets you define a function that will get run when the code block exits.
The example below will print:
hello world
Code: Try it out here
package main import "fmt" func main() { defer fmt.Println("world") fmt.Println("hello") }
I’m a big fan of this approach as I think it’s clearer to read than the standard try finally
pattern as it lets you put the cleanup code directly below the code which is making the mess like:
f := createTempFile("/tmp/defer.txt") defer deleteTempFile(f) writeFile(f) // here the `deleteTempFile` method gets called
How can we do this in C# 8 with the new using
syntax?
Well now because using var x = new thing()
exists you can write a simple class called defer
which runs a function when the current method exits, just like in golang
The interesting thing is that as a using
statement generates a try finally
under the covers these defer functions will still run if an exception is thrown.
The example below will print:
Hello World! Defer 2 Defer 1 Exception thrown: It's all one wrong
Code:
using System; | |
namespace deferdotnet | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
try | |
{ | |
DoStuff(); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine($"Exception thrown: {e.Message}"); | |
} | |
} | |
private static void DoStuff() | |
{ | |
using var d = new Defer(() => Console.WriteLine("Defer 1")); | |
using var f = new Defer(() => Console.WriteLine("Defer 2")); | |
Console.WriteLine("Hello World!"); | |
throw new Exception("It's all one wrong"); | |
} | |
} | |
// Do the `defer` magic | |
public class Defer : IDisposable | |
{ | |
private Action deferFunc { get; } | |
public Defer(Action deferFunc) | |
{ | |
this.deferFunc = deferFunc; | |
} | |
public void Dispose() | |
{ | |
deferFunc(); | |
} | |
} | |
} |
Should you do this? Well that’s kinda up to you, I don’t think it’s super nasty but I’ve not used this in anger so probably worth testing out a bit before going all out.