.NET 5 をお手軽に試したい
先日めでたく .NET 5がリリースされました。1.NET 5 では C# 9 がサポートされています。
早速試したいところですが手元のPCにインストールせず、少しだけ触りたいので Docker を使って使い捨ての .NET 5 開発環境を用意したいと思います。
Docker のインストール不要なブラウザで使えるクラウド上の使い捨て Docker 実行環境の Play with Docker2 上で試します。
環境
実行した際の Play with Docker の Linux 環境はAlpine Linux 3.12
、Docker のバージョンは19.03.11
です。
$ more /etc/issue
Welcome to Alpine Linux 3.12
Kernel \r on an \m (\l)
$ docker --version
Docker version 19.03.11, build 42e35e61f3
.NET 5 の開発環境を用意する
.NET 5 SDK の Docker image を実行します。
-it
オプションで標準入出力をシェルにつなげてそのまま .NET 5 SDK のコンテナに乗り込みます。
※--rm
オプションでコンテナ終了時にコンテナが自動的に削除されます3。
手元の PC で試す場合は不要なコンテナが残りません。
$ docker run -it --rm mcr.microsoft.com/dotnet/sdk:5.0
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:/#
.NET 5 がインストールされていることが確認できます。
root@e68a47087ad8:/# dotnet --version
5.0.100
Linux のディストリビューションは Debian なようです。
root@e68a47087ad8:/# more /etc/issue
Debian GNU/Linux 10 \n \l
C# 9(.NET 5)の新機能を試す
コンソールアプリを作成して C# 9 の新機能を試していきたいと思います。
root@e68a47087ad8:/# dotnet new console -o MyConsoleApp && cd MyConsoleApp
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.
プロジェクトが作成されました。
root@e68a47087ad8:/MyConsoleApp# ls -R
.:
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
ファイル編集したいところですが vim が入っていませんのでインストールしたいと思います。
まず、パッケージをアップデートします。
root@e68a47087ad8:/MyConsoleApp# apt update && apt upgrade
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.
vim をインストールします。
root@e68a47087ad8:/MyConsoleApp# apt 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) ...
準備ができましたので C# 9 のコードを試してみます。
詳細は参考にさせていただいた下記の記事をご覧ください。
C# 小ネタ:.NET 5.0 で使える C# 9.0 で気に入ってる機能紹介
トップレベルステートメント4
エントリポイントならクラス無しで直接コードを書けます。簡単なバッチなどで便利そうです。
root@e68a47087ad8:/MyConsoleApp# vim Program.cs
System.Console.WriteLine("Hello from top.");
ビルドします。(以降のサンプルでは省略します。)
root@e68a47087ad8:/MyConsoleApp# dotnet build
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
root@e68a47087ad8:/MyConsoleApp# dotnet run
Hello from top.
レコード型5
イミュータブルなオブジェクトを手軽に作成することができます。
またプロパティの値が一致していれば違う参照のレコード型でも==
がtrue
になります。
またこの記事では試していませんがwith
式を使って一部のプロパティだけ書き換えた新しいレコードを作成することができます。
値オブジェクトづくりがはかどりそうです。
root@e68a47087ad8:/MyConsoleApp# vim Program.cs
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}");
}
}
root@e68a47087ad8:/MyConsoleApp# dotnet run
money1: Money { amount = 10 }
money2: Money { amount = 10 }
money1 == money2: True
Target typed new6
型推論して明らかなときはnew
の型名を省略できます。
今まで右辺から推論するvar
はありましたがメンバー変数で使えませんでした。
また、引数や戻り値で型が明らかな場合でも型名を省略できるようです。
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());
}
}
root@e68a47087ad8:/MyConsoleApp# dotnet run
aaa
条件式の新機能7
詳しくは参考にさせていただいた下記記事を参照ください
条件式にor
,and
,not
が追加されています。
特徴として評価が1回なので副作用のある式でも使いやすいようです。
root@e68a47087ad8:/MyConsoleApp# vim Program.cs
using static System.Console;
int Add2AndPrint(int i)
{
var res = i + 2;
WriteLine(res);
return res;
}
WriteLine(Add2AndPrint(2) is >= 3 and <= 5);
object o = 10;
WriteLine(o is int i && ((i % 3, i % 5) is ((0, int _) or (int _, 0)) and not (0, 0)));
root@e68a47087ad8:/MyConsoleApp# dotnet run
4
True
True
おわり
後から気づいたのですが、ソースコードを変更するたびにdotnet build
しなくてもdotnet run
だけで勝手にビルドされました。便利です。
読んでいただきありがとうございました。
-
https://www.publickey1.jp/blog/20/net_51windowsmaclinuxweb.html ↩
-
https://qiita.com/okazuki/items/8043ea6f0095b3019cdf#%E3%83%88%E3%83%83%E3%83%97%E3%83%AC%E3%83%99%E3%83%AB%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88%E3%83%A1%E3%83%B3%E3%83%88 ↩
-
https://qiita.com/okazuki/items/8043ea6f0095b3019cdf#%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E5%9E%8B ↩
-
https://qiita.com/okazuki/items/8043ea6f0095b3019cdf#target-typed-new-%E5%BC%8F ↩
-
https://qiita.com/okazuki/items/8043ea6f0095b3019cdf#%E5%A4%A7%E3%81%AA%E3%82%8A%E5%B0%8F%E3%81%AA%E3%82%8A%E3%81%AE%E6%AF%94%E8%BC%83%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%AB ↩