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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.