サンプルコード
C# のサンプルコード一覧
C# で「○○するには」を解決するコードサンプル。73 件。
他の言語から探す
2つの日付の差を求めるには
`DateTime` 同士を引くと `TimeSpan` が返る。`Days` は日数部分だけを整数で返すのに対し、`TotalHours` や `TotalDays` は端数を含む小数を返す。`Days` と `TotalDays` は名前が似ていて意味が違うため、丸めたいのか総量が欲しいのかで選び分ける。
配列を条件で絞り込むには
LINQ で絞り込みを担うのは `Where` で、`Filter` という名前のメソッドは無い。戻り値は遅延評価される `IEnumerable` なので、結果を配列やリストとして固定したいなら `ToArray` や `ToList` を呼ぶ。
環境変数を削除するには
`Environment.SetEnvironmentVariable` に `null` を渡すと変数が削除される。空文字の扱いは版で違い、.NET 9 以降は空文字のまま変数が残るが、.NET 8 までは削除になる。どの版でも消したいときは `null` を渡す。
QRコードを生成するには
`QRCodeGenerator.CreateQrCode` で誤り訂正レベルを指定してデータを作り、`PngByteQRCode` に渡すと PNG のバイト列が得られる。`GetGraphic(10)` の 10 は 1 モジュールのピクセル数で、描画用のネイティブライブラリを足さなくても Linux のコンテナで動いた。
ディレクトリ内のファイル一覧を取得するには
`EnumerateFiles` はファイルだけを返すため、ディレクトリを除く判定は要らない。`GetFiles` と違って結果を配列に溜めずに列挙するので、項目数が多いディレクトリでも先頭から処理を始められる。
ネストしたJSONから値を取り出すには
`JsonNode` のインデクサはキーが無いと `null` を返すので、`?.` で繋いで最後に `??` で既定値を与える。`JsonNode` から `int?` や `string?` への明示的キャストが用意されており、型が合わなければ実行時に例外になる。
乱数のシードを固定して同じ結果を再現するには
`new Random(seed)` のようにシードを渡して生成器を作る。`Next(1, 101)` の上限 101 は含まれないので、1〜100 の値になる。
HTTPリクエストにヘッダーを付けるには
毎回同じヘッダーは HttpClient の DefaultRequestHeaders に、そのリクエストだけのヘッダーは HttpRequestMessage の Headers に置く。User-Agent や Accept は型付きのコレクションになっているため、文字列をそのまま入れずに ParseAdd を通す。
配列からランダムに1つ選ぶには
`Random.Shared.Next(長さ)` で 0 以上長さ未満の添字を作る。.NET 8 以降の `GetItems` は、重複を許して複数の要素を選ぶときに使える。`Next(0)` は例外にならず 0 を返すため、空の配列では添字の範囲外で初めて失敗する。
ランダムな文字列を生成するには
`RandomNumberGenerator.GetString` は文字集合と長さを渡すだけで、暗号用途向けの乱数から偏りなく文字列を作る。.NET 8 で追加されたメソッドで、それ以前の版では自分で `GetInt32` を呼んで 1 文字ずつ選ぶ。`System.Random` はトークンに向かない。
環境変数を設定するには
SetEnvironmentVariable は第 3 引数を省くと Process スコープになる。Windows では EnvironmentVariableTarget.User や Machine を指定してレジストリへ永続化できるが、その場合も既に起動しているプロセスには伝わらない。Unix 系では Process 以外のスコープが存在しないため、User や Machine を指定しても何も起きない。
UUIDを生成するには
.NET では `Guid.NewGuid()` がバージョン 4 の UUID を返す。`ToString("N")` でハイフンなしの文字列になり、`Guid.Parse` で文字列から戻せる。バージョン 7 を作る `Guid.CreateVersion7` は .NET 8 には無く、コンパイルエラー(CS0117)になる。
範囲を指定して乱数を得るには
`Random.Shared` は .NET 6 以降で使えるスレッドセーフな共有インスタンスで、`Next(min, max)` は上限を含まないので `max + 1` を渡す。暗号用途には `RandomNumberGenerator.GetInt32` を使う。
配列をランダムに並べ替えるには
.NET 8 で追加された `Random.Shuffle` は、配列を直接並べ替える。元を変えない新しい配列がほしいときは、`OrderBy` にランダムな値をキーとして渡す方法がある。
.env ファイルを読み込むには
DotNetEnv の `Env.Load` は読み込んだ値をプロセスの環境変数へ設定するため、以後は `Environment.GetEnvironmentVariable` で取り出せる。指定したファイルが無くても例外にならず、そのまま処理が進む。他の言語と違い、既存の環境変数を .env の値で上書きする(`PORT=1111` を付けて起動しても 8080 が出力された)。上書きしたくないときは `Env.NoClobber().Load()` を使う。ASP.NET Core では appsettings.json と環境変数を束ねる構成システムが標準で用意されているので、.env を使うのはコンソールアプリや開発時に限るとよい。
文字列のSHA-256ハッシュ値を求めるには
`SHA256.HashData` にバイト配列を渡すと、32 バイトのハッシュ値が返る。`Convert.ToHexString` で 16 進数の文字列にできるが、結果は大文字になるため、他の言語や `sha256sum` の出力と比べるときは `ToLowerInvariant` で小文字にそろえる。
文字列が含まれるか調べるには
`string.Contains(string)` は序数比較で、既定では大文字小文字を区別する。無視したいときは第2引数に `StringComparison.OrdinalIgnoreCase` を渡す。`IndexOf(string)` は既定がカルチャ依存の比較になるため、実行環境のロケールで結果が変わらないよう `StringComparison.Ordinal` を明示するのが安全である。
日付をJSON文字列にするには
`System.Text.Json` は `DateTimeOffset` と `DateTime` を追加設定なしで ISO 8601 の文字列にする。オフセットを残したいなら `DateTimeOffset` を選ぶ。`DateTime` は `Kind` によって出力が変わり、`Unspecified` ではオフセットも `Z` も付かない。
日付文字列を日付型にするには
`DateTime.Parse` は既定で実行環境のカルチャに従うため、同じ文字列でも動く PC によって結果が変わる。書式が決まっているなら `ParseExact` に `CultureInfo.InvariantCulture` を渡して固定する。失敗を例外にしたくない場面では `TryParseExact` を使い、戻り値の `bool` で成否を判定する。
配列から重複を除くには
LINQ の `Distinct` は列挙順を保ったまま重複を除き、元の配列は変更しない。`int` や `string` は既定の等値比較で判定されるため、そのまま渡せば期待どおりに動く。
正規表現の特殊文字をエスケープするには
`Regex.Escape` は `.` や `(` などの特殊文字と、`#`・空白の前に `\` を付ける。不正なパターンを `Regex.IsMatch` などに渡すと `ArgumentException`(実体は派生クラスの `RegexParseException`)になるので、外から来た文字列は先に通す。置換文字列の `$0` は展開されるため、そのまま入れたいときは `$$` に重ねるか、関数で返す。
文字列の前後の空白を除去するには
`string.Trim` は引数なしで前後の空白を落とし、`char` を渡すとその文字の集合を除去する。Python や Go と同じく集合として扱われるので、`"banana".Trim('b', 'a')` は `"nan"` になる。接頭辞だけを外したいときは `StartsWith` で確かめてから `Substring` で切るか、`TrimStart` ではなく明示的に処理する。
ホームディレクトリのパスを取得するには
`Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)` は Linux で `HOME` を優先し、無ければ passwd のホームを返す。既定ではそのフォルダが実在しないと空文字を返すので、パスだけが欲しいときは `SpecialFolderOption.DoNotVerify` を渡す。ファイル API の `Directory.Exists("~")` は展開せず `False` になる。
HTTP POSTでJSONを送るには
`System.Net.Http.Json` の `PostAsJsonAsync` を使うと、シリアライズと `Content-Type` の付与を任せられる。`HttpClient` を `static` フィールドで使い回すのは、リクエストごとに生成して破棄すると `TIME_WAIT` のソケットが積み上がって `SocketException` に至るためである。既定のプロパティ名は camelCase へ変換されるので、`title` / `body` / `userId` として送られる。
ファイルを読み込むには
File.ReadAllText はファイル全体を読み込んで文字列として返す。エンコーディングを省略しても UTF-8 として扱われるが、意図を明示するために引数で渡しておくと環境差で迷わない。UTF-8 として正しくないバイトは例外にならず置換文字(U+FFFD)に置き換わるので、Shift_JIS のファイルを読んでもエラーは出ずに文字化けする。
整数を2進数や16進数の文字列にするには
`Convert.ToString(n, 2)` で 2・8・10・16 進数の文字列にし、`Convert.ToInt32(text, 16)` で戻す。`n.ToString("X4")` のような書式指定なら 4 桁にそろえた大文字の 16 進数になる。基数に使えるのは 2・8・10・16 だけで、負の数は 32 ビットの 2 の補数で出力される。
JSONをパースするには
System.Text.Json は既定でプロパティ名の大文字小文字を区別する。camelCase の JSON を受け取るときに PropertyNameCaseInsensitive を有効にしないと、例外にもならず Name は null、Age は 0 のまま返る。
オブジェクトをJSON文字列にするには
`System.Text.Json` の既定のエンコーダは非 ASCII 文字を \uXXXX へ逃がし、「山田」は \u5C71\u7530 になる。日本語をそのまま出したいときは `UnsafeRelaxedJsonEscaping` を指定する。`WriteIndented` を true にすると整形出力になる。キー名は既定でプロパティ名のまま `Name` `Tags` `Active` で出力され、`PropertyNamingPolicy = JsonNamingPolicy.CamelCase` を指定すると `name` `tags` `active` になる。
JSONをファイルに保存するには
JsonSerializer.Serialize で文字列を作り、File.WriteAllText で一時ファイルに書いてから File.Move(overwrite: true)で置き換える。既定のエンコーダは日本語を \u4E88 のように、& を \u0026 にエスケープし、プロパティ名も Name のまま出すので、人が読む設定ファイルなら Encoder と PropertyNamingPolicy を指定する。File.WriteAllText にエンコーディングを渡さなければ BOM なしの UTF-8 で書かれる。
バイト列を16進数の文字列にするには
`Convert.ToHexString` と `Convert.FromHexString` で往復できる。`ToHexString` は大文字で返すため、小文字にしたいときは `ToLowerInvariant` を通す。不正な文字や奇数桁は `FormatException` になる。
配列を文字列に連結するには
string.Join にはジェネリックな IEnumerable<T> を取るオーバーロードがあり、各要素の ToString が呼ばれるため数値配列も変換なしで連結できる。LINQ の Select を挟めば加工と連結を 1 行で書ける。
文字列を分割するには
`string.Split` は区切りを文字列として扱い、正規表現は解釈しない。`count` を渡すと返す要素数の上限になり、あふれた分は最後の要素へまとめて残る。連続する空白で空文字が混ざるのを避けたいときは `StringSplitOptions.RemoveEmptyEntries` を指定する。
文字列をUTF-8のバイト列にするには
`Encoding.UTF8.GetBytes` でバイト列にし、`Encoding.UTF8.GetString` で戻す。`string.Length` は UTF-16 の単位数なので、絵文字を 1 文字と数えるには `EnumerateRunes` を使う。既定のデコーダーは壊れたバイト列を U+FFFD に置き換え、例外にしたいときは `new UTF8Encoding(false, true)` を使う。
文字列をBase64にするには
Convert.ToBase64String はバイト配列を受け取るので、文字列は先に Encoding.UTF8.GetBytes で変換する。URL セーフ版の専用の型(System.Buffers.Text.Base64Url)は .NET 8 では使えずコンパイルエラーになるため、+ と / を置き換え、末尾の = を TrimEnd で取り除いて作る。
ファイルの文字コードを変換するには
Encoding.GetEncoding(932) を使う前に、CodePagesEncodingProvider の登録が要る。登録しないと NotSupportedException(No data is available for encoding 932)になる。書き出しは new UTF8Encoding(false) で BOM を付けない UTF-8 にしている。
HTMLの特殊文字をエスケープするには
System.Net.WebUtility.HtmlEncode が標準で用意されており、HtmlDecode で元に戻せる。引用符は " と ' に変換される。é や © のような ASCII の範囲外の一部の文字も é や © の数値参照に変換されるが、日本語はそのまま残る。
HTTP GETリクエストを送るには
HttpClient は static フィールドとして 1 つ作り回すのが定石である。リクエストごとに new して using で破棄すると、TIME_WAIT のソケットが積み上がって SocketException に至るためである。GitHub API は User-Agent が無いリクエストを 403 で弾くが、HttpClient は既定で User-Agent を送らないため、静的コンストラクタで DefaultRequestHeaders に明示している。EnsureSuccessStatusCode() は 4xx / 5xx を例外に変える。
文字列をURLエンコードするには
Uri.EscapeDataString はスペースを %20 にし、WebUtility.UrlEncode は + にする。クエリの値には、% 形式で統一して変換する EscapeDataString を選ぶと、受け側との食い違いが起きにくい。
日付を書式付きの文字列にするには
ToString に書式文字列を渡すのが基本形だが、区切り文字の / は実行環境のカルチャに応じて置き換えられる。ファイル名や API の入力に使う文字列なら CultureInfo.InvariantCulture を明示して固定する。
文字列の長さを取得するには
string.Length は UTF-16 の char 単位数を返すため、絵文字は 2 と数えられる。コードポイントの数は EnumerateRunes で、見た目の 1 文字は StringInfo.LengthInTextElements で数える。バイト数は Encoding.UTF8.GetByteCount で求める。
ファイルが存在するか調べるには
File.Exists は対象がディレクトリのときや権限が無いときも例外を投げず false を返す。FileInfo.Exists も同じ挙動なので、判定できなかったのか本当に無いのかを区別したい場合は、実際に開いたときの例外(FileNotFoundException か UnauthorizedAccessException)で確かめる。
UNIXタイムスタンプを日付に変換するには
DateTimeOffset.FromUnixTimeSeconds は UTC(オフセット +00:00)の値を返し、ToOffset で固定のオフセットへ、TimeZoneInfo.ConvertTime で夏時間のある地域へ変換できる。ミリ秒は FromUnixTimeMilliseconds で渡す。秒の引数にミリ秒の値を渡すと、9999 年を超えるため ArgumentOutOfRangeException になる。
配列に要素が含まれるか調べるには
配列には LINQ の Contains が使え、List<T> には自前の Contains がある。文字列は既定で大文字小文字を区別するので、無視したいときは StringComparer.OrdinalIgnoreCase を渡す。条件で探すなら List の Exists か LINQ の Any を使う。
現在時刻を取得するには
DateTime は Kind プロパティでローカルか UTC かを区別するだけで、UTC からのオフセットそのものは保持しない。時差を含めて正確に記録したいなら DateTimeOffset を使うほうが安全である。
ディレクトリを作成するには
Directory.CreateDirectory は途中のディレクトリを含めてまとめて作り、既にあっても例外にならない。親が無いと失敗する単体版や、既にあると失敗する版が無いので、そうしたい場面では先に Directory.Exists で調べる。
環境変数を読むには
Environment.GetEnvironmentVariable は未設定のとき null を返す。?? 演算子で既定値を与えると未設定でも安全に扱える。ユーザー単位やマシン単位を指定する第 2 引数の EnvironmentVariableTarget は Windows の仕組みで、Linux では Process 以外を指定すると、変数があっても null が返る。
配列をソートするには
Array.Sort は配列をその場で昇順に並べ替える破壊的メソッドである。元の配列を保ちたいときは LINQ の OrderBy / OrderByDescending を使うと新しい列を返す。キー指定も OrderBy(x => x.Field) で書ける。
数値をゼロ埋めするには
書式指定子 D5 とカスタム書式 00000 は、どちらも 42 を 00042 にする。D5 の 5 は符号を除いた数字の桁数を表すので、-42 は -0042 ではなく -00042 になる。PadLeft は文字列として左を埋めるだけなので、負の数には使わない。
数値を指定した範囲に収めるには
Math.Clamp は int・double・decimal など数値の型ごとにオーバーロードがあり、値を下限と上限の間に収めて返す。下限が上限より大きいと ArgumentException になり、メッセージは '10' cannot be greater than 0. になる。
文字列を置換するには
String.Replace は正規表現を使わないリテラルの全置換で、置換後の新しい文字列を返す。最初の 1 回だけ置換するオーバーロードは無いため、IndexOf で位置を調べて Substring で組み立てる。IndexOf(string) は既定でカルチャを考慮して比較するので、文字どおりに探すときは StringComparison.Ordinal を渡す。
数値を3桁区切りにするには
書式指定子 N0 は小数部なしの 3 桁区切りで、N2 なら小数第 2 位まで出し、カスタム書式 #,0 でも同じ区切りになる。どれもカルチャの区切り文字を使うため、カルチャを省略すると実行環境の設定に従い、de-DE では 1.234.567 になる。文字列補間で書式化するときは、string.Create に CultureInfo を渡すとカルチャを固定できる。
整数の割り算で商と余りを求めるには
整数どうしの / は商を 0 の側へ切り捨て、% の余りは割られる数と同じ符号になる。Math.DivRem は .NET 6 以降で商と余りをタプルで返すので、分解して受け取れる。0 以上の余りが欲しいときは、割る数を足してからもう一度 % を取る。整数を 0 で割ると DivideByZeroException が投げられるが、double の割り算なら例外にはならず、17.0 / 0 は Infinity になる。
小数を指定桁で丸めるには
Math.Round は第 2 引数で桁数を指定でき、既定ではちょうど真ん中の値を偶数の側へ寄せるため Math.Round(2.5) は 2 になる。四捨五入にしたいときは MidpointRounding.AwayFromZero を渡すが、double の 1.005 は内部で 1.00499… なのでそれでも 1 になる。金額のように 10 進で正確に丸めたい値は decimal(1.005m)で持つと、指定どおり 1.01 になる。Console.WriteLine は実行環境のカルチャで書式化するので、de-DE では 3.14 が 3,14 と表示される。
環境変数を真偽値として読むには
bool.TryParse は大文字小文字と前後の空白を無視して "true" と "false" を受け付けるが、"1" や "yes" では false を返して失敗する。TryParse で解釈できなかった値だけを switch で追加判定すると、標準の表記と慣用の表記を両方扱える。
パスからファイル名を取り出すには
Path.GetFileName は最後の区切り文字より後ろを返す文字列操作で、末尾に / が付いたパスでは空文字になる。ディレクトリのパスを受け取る場面では、Path.TrimEndingDirectorySeparator(.NET Core 3.0 以降)で末尾の区切り文字を落としてから渡す。拡張子を除いた名前は GetFileNameWithoutExtension で得られる。Linux では \ が区切り文字として扱われないため、Windows 形式のパスは全体が 1 つの名前として返る。
ファイルに書き込むには
File.WriteAllText はファイルの作成・書き込み・クローズをまとめて行い、既存ファイルは上書きする。末尾に足したいときは File.AppendAllText を使い、ファイルが無ければ作られる。エンコーディングを省略すると BOM なしの UTF-8 で書かれ、Encoding.UTF8 を渡すと、ファイルを先頭から書くときに BOM(EF BB BF の 3 バイト)が付くので、ほかのツールで読むファイルでは省略する。
HTTPでファイルをダウンロードするには
GetAsync は既定で本文をすべて読み込んでから返るので、HttpCompletionOption.ResponseHeadersRead を渡してヘッダーを受け取った時点で制御を戻させ、ReadAsStreamAsync のストリームを CopyToAsync でファイルへ写す。GetAsync は 404 でも例外を投げないため、EnsureSuccessStatusCode で失敗を例外に変えてから保存する。HttpClient は static フィールドで 1 つを使い回す。
正規表現で大文字小文字を区別せずに一致させるには
RegexOptions.IgnoreCase を引数に渡すか、パターンの先頭に (?i) と書く。IgnoreCase は現在のカルチャの規則で比較するため、ロケールに左右されたくない処理では RegexOptions.CultureInvariant を併せて指定する。
配列の最大値と最小値を求めるには
LINQ の Max と Min で最大値と最小値が求まり、ラムダを渡せばキーの最大値になる。最大のキーを持つ要素そのものが欲しいときは .NET 6 で追加された MaxBy を使う。int のような値型の空の配列に Max を呼ぶと InvalidOperationException になるため、DefaultIfEmpty で既定値を補ってから呼ぶ。
親ディレクトリのパスを取得するには
Path.GetDirectoryName は最後の区切り文字より前を返す文字列操作で、末尾に / が付いたパスではそのディレクトリ自身が返り、ルートでは null を返す。末尾の区切り文字は Path.TrimEndingDirectorySeparator(.NET Core 3.0 以降)で落としてから渡す。Directory.GetParent は相対パスをカレントディレクトリ基準で解釈し、絶対パスの DirectoryInfo を返す点が異なる。
相対パスを絶対パスにするには
Path.GetFullPath はカレントディレクトリを基準に .. や . を取り除いた絶対パスを返し、ファイルの存在は確かめない。カレントディレクトリはプロセス全体で共有される状態なので、ライブラリの中では基準ディレクトリを渡す 2 引数版(.NET Core 2.1 以降)を使うほうが安全である。
ファイルの拡張子を取り出すには
Path.GetExtension はドット付きで返し、拡張子が無ければ空文字を返す。Go と同じく、.bashrc のようにドットで始まる名前は名前全体が拡張子になる。比較に StringComparison.OrdinalIgnoreCase を使うと、ToLower で新しい文字列を作らずに大文字小文字を無視できる。
パスを連結するには
Path.Combine は途中の要素が絶対パスだとそこから組み立て直し、Path.Join(.NET Core 3.0 以降)は区切り文字を補ってつなぐだけで前の部分を残す。外から受け取った名前をつなぐ場面では、どちらの挙動を期待しているのかを決めてから選ぶ。
日付に日数を足すには
DateTime は値型で、AddDays は新しい DateTime を返す。戻り値を捨てると元の変数は変わらないので、Java と同じく結果を代入して使う。負の数を渡せば日数を引ける。AddMonths は存在しない日付を月末に丸めるため、1 月 31 日の 1 か月後は 2 月 28 日になる。
ファイルをコピーするには
File.Copy は 2 引数版が宛先の存在を許さず、上書きするかどうかを 3 引数版で明示させる設計になっている。親ディレクトリは作られず、無いまま呼ぶと DirectoryNotFoundException になるので、必要なら Directory.CreateDirectory を先に呼ぶ。
文字列を数値に変換するには
int.Parse は失敗すると例外を投げるのに対し、int.TryParse は成否を bool で返し、値は out パラメータへ入れる。ユーザー入力のように失敗が想定される場面では TryParse を使うと例外処理を書かずに済む。小数の解析は実行環境のロケールで区切り文字の解釈が変わるので、CultureInfo.InvariantCulture を明示する。
2つのJSONをマージするには
System.Text.Json の JsonNode は追加の依存なしで木構造を組み替えられる。JsonNode は 1 つの親にしか属せないため、別の木へ移すときは DeepClone を通してから代入する。
環境変数の一覧を取得するには
Environment.GetEnvironmentVariables は非ジェネリックの IDictionary を返すので、Cast<DictionaryEntry> で LINQ に載せてから並べ替える。Windows では名前の大文字小文字が区別されないため、比較子も OrdinalIgnoreCase に揃える。
正規表現に一致する部分をすべて取り出すには
Regex.Matches は一致した Match をまとめて返し、各 Match の Groups[1] が丸括弧の中身になる。MatchCollection は IEnumerable なので、LINQ をそのままつないで必要な形に変換できる。
HTTPリクエストにタイムアウトを設定するには
HttpClient.Timeout はそのインスタンスの全リクエストに効く既定値で、リクエストごとに短くしたいときは CancellationTokenSource の期限を渡す。どちらの経路でも投げられるのは TaskCanceledException なので、InnerException が TimeoutException かどうかで理由を見分ける。
正規表現で部分文字列を取り出すには
Match.Groups は名前でも番号でも引ける。存在しない名前を渡しても例外にはならず、Success が false で Value が空文字のグループが返るため、必要なら Success を確認する。Match.Success が false のときは全体として一致していない。
文字列が正規表現に一致するか調べるには
Regex.IsMatch は真偽値を返す静的メソッドで、既定では部分一致を見る。全体一致にしたいときは ^ と $ を明示する。同じパターンを何度も使うなら RegexOptions.Compiled を付けた Regex インスタンスを使い回すと、毎回の解析を避けられる。
正規表現で置換するには
Regex.Replace は既定で全件を置き換える。件数を絞りたいときは静的メソッドではなく Regex インスタンスの Replace に count を渡す。置換文字列の中では $1 で後方参照でき、MatchEvaluator を渡すと一致ごとに結果を組み立てられる。