Easily try C # 9 (.NET 5) on Docker

I want to try .NET 5 easily

The other day, .NET 5 has been released. [^ dotnet5] .NET 5 supports C # 9. I'd like to try it immediately, but I don't want to install it on my PC, but I want to touch it a little, so I'd like to use Docker to prepare a disposable .NET 5 development environment.

Install Docker Try it on Play with Docker [^ pwd], a disposable Docker execution environment on the cloud that can be used with browsers that do not need to be installed.

environment

The Linux environment of Play with Docker when executed is Alpine Linux 3.12, and the version of Docker is 19.03.11.

Welcome to Alpine Linux 3.12
Kernel \r on an \m (\l)
Docker version 19.03.11, build 42e35e61f3

Prepare a .NET 5 development environment

Run the .NET 5 SDK Docker image. Connect the standard I / O to the shell with the -it option and board the .NET 5 SDK container as it is.

Unable to find image 'mcr.microsoft.com/dotnet/sdk:5.0' locally
5.0: Pulling from dotnet/sdk
bb79b6b2107f: Pull complete 
97805e17b1a2: Pull complete 
48d36279ea43: Pull complete 
5d23a35fbf12: Pull complete 
982bc1066a1e: Pull complete 
6cc6e848c1f3: Pull complete 
df97eda6f03d: Pull complete 
7520ee234b82: Pull complete 
Digest: sha256:ac49854ff6dcc1a2916ffc0981503f571698458187f925da0c2f2b6a0bec8dee
Status: Downloaded newer image for mcr.microsoft.com/dotnet/sdk:5.0
root@e68a47087ad8:/# 

You can see that .NET 5 is installed.

5.0.100

The Linux distribution seems to be Debian.

Debian GNU/Linux 10 \n \l

Try out new features in C # 9 (.NET 5)

I would like to create a console app to try out the new features in C # 9.

Getting ready...
The template "Console Application" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on MyConsoleApp/MyConsoleApp.csproj...
  Determining projects to restore...
  Restored /MyConsoleApp/MyConsoleApp.csproj (in 89 ms).
Restore succeeded.

The project has been created.

.:
MyConsoleApp.csproj  Program.cs  obj

./obj:
MyConsoleApp.csproj.nuget.dgspec.json  MyConsoleApp.csproj.nuget.g.targets  project.nuget.cache
MyConsoleApp.csproj.nuget.g.props      project.assets.json

I want to edit the file, but vim is not included, so I would like to install it. First, update the package.

Get:1 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:2 http://deb.debian.org/debian buster InRelease [121 kB]       
Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Get:4 http://security.debian.org/debian-security buster/updates/main amd64 Packages [248 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 Packages [7906 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [7856 B]
Fetched 8401 kB in 1s (5711 kB/s)                         
Reading package lists... Done
Building dependency tree       
Reading state information... Done
1 package can be upgraded. Run 'apt list --upgradable' to see it.
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
  tzdata
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 264 kB of archives.
After this operation, 3072 B of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://deb.debian.org/debian buster-updates/main amd64 tzdata all 2020d-0+deb10u1 [264 kB]
Fetched 264 kB in 0s (24.0 MB/s)
debconf: delaying package configuration, since apt-utils is not installed
(Reading database ... 9877 files and directories currently installed.)
Preparing to unpack .../tzdata_2020d-0+deb10u1_all.deb ...
Unpacking tzdata (2020d-0+deb10u1) over (2020a-0+deb10u1) ...
Setting up tzdata (2020d-0+deb10u1) ...
debconf: unable to initialize frontend: Dialog
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76.)
debconf: falling back to frontend: Readline

Current default time zone: 'Etc/UTC'
Local time is now:      Sat Nov 14 16:16:39 UTC 2020.
Universal Time is now:  Sat Nov 14 16:16:39 UTC 2020.
Run 'dpkg-reconfigure tzdata' if you wish to change it.

Install vim.

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  libgpm2 vim-common vim-runtime xxd
Suggested packages:
  gpm ctags vim-doc vim-scripts
The following NEW packages will be installed:
  libgpm2 vim vim-common vim-runtime xxd
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 7425 kB of archives.
After this operation, 33.8 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://deb.debian.org/debian buster/main amd64 xxd amd64 2:8.1.0875-5 [140 kB]
Get:2 http://deb.debian.org/debian buster/main amd64 vim-common all 2:8.1.0875-5 [195 kB]
Get:3 http://deb.debian.org/debian buster/main amd64 libgpm2 amd64 1.20.7-5 [35.1 kB]
Get:4 http://deb.debian.org/debian buster/main amd64 vim-runtime all 2:8.1.0875-5 [5775 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 vim amd64 2:8.1.0875-5 [1280 kB]
Fetched 7425 kB in 0s (59.9 MB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package xxd.
(Reading database ... 9877 files and directories currently installed.)
Preparing to unpack .../xxd_2%3a8.1.0875-5_amd64.deb ...
Unpacking xxd (2:8.1.0875-5) ...
Selecting previously unselected package vim-common.
Preparing to unpack .../vim-common_2%3a8.1.0875-5_all.deb ...
Unpacking vim-common (2:8.1.0875-5) ...
Selecting previously unselected package libgpm2:amd64.
Preparing to unpack .../libgpm2_1.20.7-5_amd64.deb ...
Unpacking libgpm2:amd64 (1.20.7-5) ...
Selecting previously unselected package vim-runtime.
Preparing to unpack .../vim-runtime_2%3a8.1.0875-5_all.deb ...
Adding 'diversion of /usr/share/vim/vim81/doc/help.txt to /usr/share/vim/vim81/doc/help.txt.vim-tiny by vim-runtime'
Adding 'diversion of /usr/share/vim/vim81/doc/tags to /usr/share/vim/vim81/doc/tags.vim-tiny by vim-runtime'
Unpacking vim-runtime (2:8.1.0875-5) ...
Selecting previously unselected package vim.
Preparing to unpack .../vim_2%3a8.1.0875-5_amd64.deb ...
Unpacking vim (2:8.1.0875-5) ...
Setting up libgpm2:amd64 (1.20.7-5) ...
Setting up xxd (2:8.1.0875-5) ...
Setting up vim-common (2:8.1.0875-5) ...
Setting up vim-runtime (2:8.1.0875-5) ...
Setting up vim (2:8.1.0875-5) ...
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vim (vim) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vimdiff (vimdiff) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rvim (rvim) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/rview (rview) in auto mode
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/vi (vi) in auto mode
update-alternatives: warning: skip creation of /usr/share/man/da/man1/vi.1.gz because associated file /usr/share/man/da/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/de/man1/vi.1.gz because associated file /usr/share/man/de/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/fr/man1/vi.1.gz because associated file /usr/share/man/fr/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/it/man1/vi.1.gz because associated file /usr/share/man/it/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ja/man1/vi.1.gz because associated file /usr/share/man/ja/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/pl/man1/vi.1.gz because associated file /usr/share/man/pl/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ru/man1/vi.1.gz because associated file /usr/share/man/ru/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/man1/vi.1.gz because associated file /usr/share/man/man1/vim.1.gz (of link group vi) doesn't exist
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/view (view) in auto mode
update-alternatives: warning: skip creation of /usr/share/man/da/man1/view.1.gz because associated file /usr/share/man/da/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/de/man1/view.1.gz because associated file /usr/share/man/de/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/fr/man1/view.1.gz because associated file /usr/share/man/fr/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/it/man1/view.1.gz because associated file /usr/share/man/it/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ja/man1/view.1.gz because associated file /usr/share/man/ja/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/pl/man1/view.1.gz because associated file /usr/share/man/pl/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ru/man1/view.1.gz because associated file /usr/share/man/ru/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/man1/view.1.gz because associated file /usr/share/man/man1/vim.1.gz (of link group view) doesn't exist
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/ex (ex) in auto mode
update-alternatives: warning: skip creation of /usr/share/man/da/man1/ex.1.gz because associated file /usr/share/man/da/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/de/man1/ex.1.gz because associated file /usr/share/man/de/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/fr/man1/ex.1.gz because associated file /usr/share/man/fr/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/it/man1/ex.1.gz because associated file /usr/share/man/it/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ja/man1/ex.1.gz because associated file /usr/share/man/ja/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/pl/man1/ex.1.gz because associated file /usr/share/man/pl/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ru/man1/ex.1.gz because associated file /usr/share/man/ru/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/man1/ex.1.gz because associated file /usr/share/man/man1/vim.1.gz (of link group ex) doesn't exist
update-alternatives: using /usr/bin/vim.basic to provide /usr/bin/editor (editor) in auto mode
update-alternatives: warning: skip creation of /usr/share/man/da/man1/editor.1.gz because associated file /usr/share/man/da/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/de/man1/editor.1.gz because associated file /usr/share/man/de/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/fr/man1/editor.1.gz because associated file /usr/share/man/fr/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/it/man1/editor.1.gz because associated file /usr/share/man/it/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ja/man1/editor.1.gz because associated file /usr/share/man/ja/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/pl/man1/editor.1.gz because associated file /usr/share/man/pl/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ru/man1/editor.1.gz because associated file /usr/share/man/ru/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/man1/editor.1.gz because associated file /usr/share/man/man1/vim.1.gz (of link group editor) doesn't exist
Processing triggers for libc-bin (2.28-10) ...

Now that you're ready, let's try the C # 9 code. For details, please see the following article that I referred to.

** C # small story: Introducing favorite features in C # 9.0 that can be used with .NET 5.0 **

Toplevel statement [^ toplevelstatement]

At the entry point, you can write code directly without a class. It seems to be convenient for simple batches.

System.Console.WriteLine("Hello from top.");

Build. (Omitted in the following samples.)

Microsoft (R) Build Engine version 16.8.0+126527ff1 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  All projects are up-to-date for restore.
  MyConsoleApp -> /MyConsoleApp/bin/Debug/net5.0/MyConsoleApp.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.44
Hello from top.

Record type [^ record]

You can easily create immutable objects. Also, if the property values match, == will be true even for record types with different references. You can also use the with expression to create a new record with only some properties rewritten, which I haven't tried in this article.

Creating value objects seems to be quick.

using static System.Console;

record Money(decimal amount);

class Program  {
  static void Main() {
    var money1 = new Money(10);
    WriteLine($"money1: {Money}");
 
    var money2 = new Money(10);
    WriteLine($"money2: {money2}");

    WriteLine($"money1 == money2: {money1 == money2}");
  }
}
money1: Money { amount = 10 }
money2: Money { amount = 10 }
money1 == money2: True

Target typed new[1]

You can omit the new type name when it is obvious by type inference. Until now, there was a var inferred from the right side, but it could not be used in a member variable. Also, it seems that the type name can be omitted even if the type is clear in the argument or return value.

using System.Collections.Generic;
using System.Linq;

class Program {
  static readonly Dictionary<int, List<string>> _cache = new();

  static void Main() {
    _cache.Add(1, new() { "aaa" });

    System.Console.WriteLine(_cache[1].First());
  }
}
aaa

New feature of conditional expression [^ orandnot]

Or, and, not have been added to the conditional expression. As a feature, it is evaluated once, so it seems easy to use for comparing the return values of expressions with side effects. (= It is no longer necessary to store the results in temporary variables and then compare them so that side effects do not occur multiple times) Also, it seems that you can write it concisely together with pattern matching.

using static System.Console;

var x = 7;
WriteLine($"x is >= 5 and < 10: {x is >= 5 and < 10}");
WriteLine($"x is (<= 0 or 7 or <= 10) and not 15: {x is (<= 0 or 7 or <= 10) and not 15}");

object o = 2;
WriteLine($"o is int and >= 1: {o is int and >= 1}");
x is >= 5 and < 10: True
x is (<= 0 or 7 or <= 10) and not 15: True
o is int and >= 1: True

end

As I noticed later, every time I changed the source code, it was built by just dotnet run without dotnet build. Convenient. Thank you for reading.


  1. https://qiita.com/okazuki/items/8043ea6f0095b3019cdf#target-typed-new-%E5%BC%8F ↩︎

Recommended Posts

Easily try C # 9 (.NET 5) on Docker
Try Docker on Windows 10 Home
Try using Redmine on Mac docker
Try Docker on Windows Home (September 2020)
Try putting Docker in ubuntu on WSL
Try the Docker environment on AWS ECS
Redmine on Docker
Try running MPLS-VPN with FR Routing on Docker
Try running OSPF with FR Routing on Docker
Try DisplayLink on Ubuntu 20.04
Docker installation on CentOS 6
Try OpenLiteSpeed on CentOS8
Easily build Redmine on Windows using WSL2 and Docker
Install Docker on Manjaro
Try WildFly with Docker
M.S. docker on Windows
Docker installation on WSL2
Run phpunit on Docker
Launch Nuxt.js + Rails API on Docker and try CRUD operation
Try Hello World using plain Java on a Docker container
Try RabbitMQ + PHP on CentOS
Install Docker on Raspberry Pi
Install Docker on Windows 10 PRO
Run VS Code on Docker
Install Docker on Ubuntu Server 20.04
Run openvpn on Docker (windows)
Oracle Java 8 on Docker Ubuntu
Hosted Apicurio Studio on Docker
Install docker on AWS EC2
Try Spring Boot on Mac
Run mruby / c on PSoC 5
People using docker Try using docker-compose
(For myself) Try creating a C # environment with docker + code-server, cloud9