TIP

🔥 Make sure you star the repo (opens new window) to keep up to date with new tips and tricks.

💡 Learn more : The .NET runtime GitHub (opens new window).

📺 Watch the video : How to create faster and smarter apps with .NET 5 (opens new window).

# How to create faster and smarter apps with .NET 5

# .NET 5 is the next step to one .NET

.NET Core has been around for a while and lives next to the .NET Framework. The .NET Framework will continue to exist as many customers rely on it daily and .NET Core will be replaced by .NET 5, which brings a lot of improvements (opens new window), including performance improvements (opens new window), C# 9.0 (opens new window) and F# 5.0 (opens new window), single file applications (opens new window) and support for Windows ARM64 (opens new window).

In this post, we'll look at some of the improvements and new features of .NET 5.

# Prerequisites

If you want to follow along, you'll need the following:

# Single-File Apps and Trimming unused assemblies

.NET 5 has improved its deployment story. You can now publish your complete project to a single file (or a handful of them), even when you create a standalone application that includes the complete .NET 5 runtime. This reduces the payload of a deployment and makes it easier to move complete applications around.

(Just a handful of files for a self contained, single-file app)

Also, .NET 5 improved the trimming of unused assemblies. Previously in .NET Core, unused assemblies wouldn't be deployed to the final application payload. .NET 5 takes this further by also removing unused types and members from assemblies, thereby creating even smaller applications.

(Publish a .NET 5 console app)

# Top level statements in C# 9

Consider the following code for a simple console application:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            Console.ReadLine();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

With .NET 5, you can use C# 9, which supports top level statements. This means that, for simple applications, you don't need any boilerplate code. You can, for instance, turn the previous code into this:

System.Console.WriteLine("Hello World!");
Console.ReadLine();
1
2

And this still works. Top level statements are great for simple applications and especially for applications like Azure Functions.

(Output of console application)

# Performance improvements

.NET Core 1, 2 and 3 introduced incredible performance improvements over the .NET Framework and set a new industry standard. .NET 5 is even faster in every way. To see how much faster it is, we can run benchmarks to compare it to the .NET Framework 4.8 and .NET Core 3.1.

  1. Open a command prompt
  2. Create a new console application and navigate to it with the following commands:
mkdir Benchmarks
cd Benchmarks
dotnet new console
1
2
3
  1. Open the Benchmarks.csproj file and change it into this:
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <ServerGarbageCollection>true</ServerGarbageCollection>
    <TargetFrameworks>net5.0;netcoreapp3.1;net48</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="benchmarkdotnet" Version="0.12.1" />
  </ItemGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'net48' ">
    <PackageReference Include="System.Memory" Version="4.5.4" />
    <PackageReference Include="System.Text.Json" Version="4.7.2" />
    <Reference Include="System.Net.Http" />
  </ItemGroup>

</Project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  1. Replace the code in Program.cs with the following code, which includes some performance benchmarks. You can find more performance benchmarks and see how they are implemented in this blog post (opens new window):
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Running;
using System;
using System.Buffers.Text;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;

[MemoryDiagnoser]
public class Program
{
    static void Main(string[] args) => BenchmarkSwitcher.FromAssemblies(new[] { typeof(Program).Assembly }).Run(args);

    // BENCHMARKS GO HERE
    private string[] _array = new string[1000];

    [Benchmark]
    public void CovariantChecking()
    {
        string[] array = _array;
        for (int i = 0; i < array.Length; i++)
            array[i] = "default";
    }


    private C c1 = new C() { Value = 1 }, c2 = new C() { Value = 2 }, c3 = new C() { Value = 3 };

    [Benchmark]
    public int Compare() => Comparer<C>.Smallest(c1, c2, c3);

    class Comparer<T> where T : IComparable<T>
    {
        public static int Smallest(T t1, T t2, T t3) =>
            Compare(t1, t2) <= 0 ?
                (Compare(t1, t3) <= 0 ? 0 : 2) :
                (Compare(t2, t3) <= 0 ? 1 : 2);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static int Compare(T t1, T t2) => t1.CompareTo(t2);
    }

    class C : IComparable<C>
    {
        public int Value;
        public int CompareTo(C other) => other is null ? 1 : Value.CompareTo(other.Value);
    }

    private int _offset = 0;

    [Benchmark]
    public int ThrowHelpers()
    {
        var arr = new int[10];
        var s0 = new Span<int>(arr, _offset, 1);
        var s1 = new Span<int>(arr, _offset + 1, 1);
        var s2 = new Span<int>(arr, _offset + 2, 1);
        var s3 = new Span<int>(arr, _offset + 3, 1);
        var s4 = new Span<int>(arr, _offset + 4, 1);
        var s5 = new Span<int>(arr, _offset + 5, 1);
        return s0[0] + s1[0] + s2[0] + s3[0] + s4[0] + s5[0];
    }

    [Benchmark]
    public void GenericDictionaries()
    {
        for (int i = 0; i < 14; i++)
            GenericMethod<string>(i);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static object GenericMethod<T>(int level)
    {
        switch (level)
        {
            case 0: return typeof(T);
            case 1: return typeof(List<T>);
            case 2: return typeof(List<List<T>>);
            case 3: return typeof(List<List<List<T>>>);
            case 4: return typeof(List<List<List<List<T>>>>);
            case 5: return typeof(List<List<List<List<List<T>>>>>);
            case 6: return typeof(List<List<List<List<List<List<T>>>>>>);
            case 7: return typeof(List<List<List<List<List<List<List<T>>>>>>>);
            case 8: return typeof(List<List<List<List<List<List<List<List<T>>>>>>>>);
            case 9: return typeof(List<List<List<List<List<List<List<List<List<T>>>>>>>>>);
            case 10: return typeof(List<List<List<List<List<List<List<List<List<List<T>>>>>>>>>>);
            case 11: return typeof(List<List<List<List<List<List<List<List<List<List<List<T>>>>>>>>>>>);
            case 12: return typeof(List<List<List<List<List<List<List<List<List<List<List<List<T>>>>>>>>>>>>);
            default: return typeof(List<List<List<List<List<List<List<List<List<List<List<List<List<T>>>>>>>>>>>>>);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  1. Run the benchmark application with:
dotnet run -c Release -f net48 --runtimes net48 netcoreapp31 netcoreapp50 --filter ** --join
1

After running the benchmarks, the program will show summaries of each benchmark it ran:

(Benchmark results)

# Conclusion

.NET 5 (opens new window) is the next evolution of .NET Core and includes many improvements, including enhanced performance (opens new window), new language features in C# 9 (opens new window) and smaller applications (opens new window). Go and check it out!