Try C# on Arch Linux

きっかけ
TypeScriptに飽きて、そろそろ別の言語を学んでみたくなったのでとりあえずC/C#/C++あたり学ぼうよとなって学ぶことに。
忘れないように色々メモっておく。
実行環境
- OS: EndeavourOS (Arch)
- Shell: bash
- エディタ: VSCode
- .NET Ver: 9.0.105
参考用
初期設定なり
チュートリアル
dotnet build
シングルバイナリアプリケーションを作る上で参考にした
RIDs (win-x64
, linux-x64
など)
EditorConfig

.NET SDKインストール
sudo pacman -S dotnet-sdk
(VSCode) 以下の拡張機能をいれる
- C# Dev Kit (C# + .NET Install Tool)
- VS Sharper for C#
- vscode-solution-explorer

pj作成
dotnet new console -o "ProjectName"
コンソール上で動くものを作ってみようかな。

実行
dotnet run
これだけ。
ビルド
一つのバイナリファイルにまとめたいので、ちょっといじる
RuntimeIdentifier
の箇所はWindowsであればwin-x64
などにすること。詳しくはKnown RIDsへ
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<ImplicitUsings>enable</ImplicitUsings>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
そしてビルド
dotnet publish
成果物は/bin/Release/net9.0/linux-x64/publish
にあった。
しっかり動いてる。

フォーマッタが欲しいのでインストール。
dotnet tool install -g dotnet-format
設定は.editorconfig
で書く。拡張機能としてEditorConfig for VS Code
を入れれば編集時に保管とhighlightが効く。

dotnet format
とdotnet-format
があるので実行時間を比べる
dotnet format
time dotnet format cstry.csproj
real 0m9.388s
user 0m8.768s
sys 0m0.435s
dotnet-format
time dotnet-format cstry.csproj
ワークスペース '.../try-csharp/cstry/cstry.csproj' でコード ファイルを書式設定します。
コード ファイル '.../try-csharp/cstry/Program.cs' が書式設定されました。
2608 ミリ秒で書式設定が完了します。
real 0m3.740s
user 0m3.598s
sys 0m0.217s
結構違う。

ちょっとややこしくて苦しんでいるのが、dotnet newしたときに.csproj
と.sln
の2つが生成されるせいで
$ dotnet format
Unhandled exception: System.IO.FileNotFoundException: MSBuild のプロジェクト ファイルとソリューション ファイルの両方が '/home/r64/workspace/try-csharp/cstry/' で見つかりました。使用するファイルを <workspace> 引数で指定してください。
となる問題。
めんどくさいな...

チュートリアル通りに、電卓を作る
// Declare variables and then initialize to zero.
int num1 = 0; int num2 = 0;
// Display title as the C# console calculator app.
Console.WriteLine("Console Calculator in C#\r");
Console.WriteLine("------------------------\n");
// Ask the user to type the first number.
Console.WriteLine("Type a number, and then press Enter");
num1 = Convert.ToInt32(Console.ReadLine());
// Ask the user to type the second number.
Console.WriteLine("Type another number, and then press Enter");
num2 = Convert.ToInt32(Console.ReadLine());
// Ask the user to choose an option.
Console.WriteLine("Choose an option from the following list:");
Console.WriteLine("\ta - Add");
Console.WriteLine("\ts - Subtract");
Console.WriteLine("\tm - Multiply");
Console.WriteLine("\td - Divide");
Console.Write("Your option? ");
// Use a switch statement to do the math.
switch (Console.ReadLine())
{
case "a":
Console.WriteLine($"Your result: {num1} + {num2} = " + (num1 + num2));
break;
case "s":
Console.WriteLine($"Your result: {num1} - {num2} = " + (num1 - num2));
break;
case "m":
Console.WriteLine($"Your result: {num1} * {num2} = " + (num1 * num2));
break;
case "d":
Console.WriteLine($"Your result: {num1} / {num2} = " + (num1 / num2));
break;
}
// Wait for the user to respond before closing.
Console.Write("Press any key to close the Calculator console app...");
Console.ReadKey();
異なる箇所もあるが、構文は大体JavaScriptと似ている印象。switch case文辺りはほぼそっくりだろう

Discord Bot w/C#
好きなものを作るのが一番覚えやすいので、DiscordのBotを作りながら覚えていく。
Discord.NETを使うのがよさそうだ。nugetから落とせる。
Docs: https://docs.discordnet.dev/guides/getting_started/installing.html

Init & add Discord.Net pkg
dotnet new console && dotnet add package Discord.Net

Docsを参考にコーディング
using Discord;
using Discord.WebSocket;
public class Program
{
private static DiscordSocketClient? _client;
public static async Task Main()
{
_client = new DiscordSocketClient();
_client.Log += Log;
var token = "token";
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();
// Block this task until the program is closed.
await Task.Delay(-1);
}
private static Task Log(LogMessage msg)
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}
}

ただ、このままだとtokenがハードコーディングされててghなどに公開すると大変な事になるのでconfig.json
に記述させたものを使うようにする。
- var token = "token";
+ var jsonContent = File.ReadAllText("config.json");
+ var config = JsonConvert.DeserializeObject<ConfigClass>(jsonContent);
+ var token = config!.Token;
ConfigClassはこんな感じで。
public class ConfigClass {
public string? Token {get; set;}
}
こっちの方がいいかも?
public class ConfigClass {
public required string Token {get; set;}
}

C#入門としてこんなものもみつけたのでここに。