cv.cm

コーディング · プログラミング言語

C#入門チュートリアル(初心者向け)

約11分で読めます

結論

C#はMicrosoftが開発した静的型付けのオブジェクト指向言語で、Windows、macOS、Linuxで動く無料のクロスプラットフォーム実行環境 .NET 上で動作します。.NET SDKをインストールして dotnet new console と dotnet run を実行すると、"Hello, World!" が表示されます。クラスとレコード、List<T> や Dictionary<K, V> などのジェネリックコレクション、LINQクエリ、async/await、パターンマッチング、例外処理が中心的な内容です。

JSONフォーマッタを開く

C#とは何か、何に使われるか

C#(「シーシャープ」と読みます)は、Anders Hejlsbergが率いるチームがMicrosoftで設計し、2002年に最初のバージョンが公開されました。Ecma(ECMA-334)によって標準化されており、.NETとともにオープンに開発されています。WebのAPIやサイト(ASP.NET Core)、Windowsのデスクトップアプリ、クロスプラットフォームのモバイル・デスクトップアプリ(.NET MAUI)、クラウドサービス、ゲームで使われ、UnityエンジンもゲームスクリプトにC#を使っています。構文はC系なので、Java、C++、JavaScriptの開発者にも馴染みやすい言語です。

.NETのインストールと Hello, world の実行

dot.netから.NET SDKをダウンロードし、dotnet --version で確認します。コンソールプロジェクトを作成して実行します。

dotnet new console -o HelloApp
cd HelloApp
dotnet run
# Hello, World!

テンプレートは Program.cs を作成します。トップレベルステートメントを使うため、小さなプログラムならクラスも Main メソッドも不要です。

Console.WriteLine("Hello, World!");

変数と基本の型

すべての変数には静的な型があります。var を使うと値からコンパイラが型を推論します。値型(数値、bool、struct)はデータを直接保持し、参照型(string、クラス、配列)はオブジェクトを参照します。

型例備考
intint n = 42;32ビット整数
longlong big = 10_000_000_000;64ビット整数
doubledouble x = 3.14;64ビット浮動小数点数
decimaldecimal price = 19.99m;10進数。金額の計算に向く
boolbool ok = true;true または false
charchar c = 'A';UTF-16コード単位
stringstring s = "hi";変更できない文字列
var name = "Ada";
int count = 7;
double avg = count / 2.0;
Console.WriteLine($"{name} has {count} items, avg {avg}");  // Ada has 7 items, avg 3.5
Console.WriteLine(count / 2);                              // 3 (integer division)
Console.WriteLine(int.Parse("12") + 1);                    // 13
string? nickname = null;   // ? marks a nullable reference
Console.WriteLine(nickname ?? "none");                     // none

$"..." は文字列補間です。新しいプロジェクトではnull許容参照型が有効になっており、null の可能性がある値をチェックなしで使うとコンパイラが警告します。

制御構文とメソッド

int score = 72;
if (score >= 90) Console.WriteLine("A");
else if (score >= 70) Console.WriteLine("B");   // B
else Console.WriteLine("C");

for (int i = 0; i < 3; i++) Console.Write($"{Square(i)} ");  // 0 1 4
Console.WriteLine();

foreach (var fruit in new[] { "apple", "pear" }) Console.WriteLine(fruit);

string day = "SAT";
string kind = day switch
{
    "SAT" or "SUN" => "weekend",
    _ => "weekday",
};
Console.WriteLine(kind);   // weekend
Console.WriteLine(Greet("Lin"));                // Hello, Lin!

static int Square(int x) => x * x;
static string Greet(string name, string greeting = "Hello") => $"{greeting}, {name}!";

switch 式と or パターンは、C#のパターンマッチングの一部です。メソッドには、引数のデフォルト値、名前付き引数(Greet(name: "Lin"))、=> を使った式形式の本体を持たせられます。

クラス、プロパティ、レコード

クラスは、フィールド、プロパティ(get と set のロジックを持つフィールド)、メソッドを持ちます。record は、等価性が値に基づく型で、不変のデータに最適です。

var acc = new Account("Ann");
acc.Deposit(50);
Console.WriteLine($"{acc.Owner}: {acc.Balance}");   // Ann: 50

var p1 = new Point(3, 4);
var p2 = p1 with { Y = 5 };                         // copy with one change
Console.WriteLine(p1);                              // Point { X = 3, Y = 4 }
Console.WriteLine(p1 == new Point(3, 4));           // True

public class Account
{
    public string Owner { get; }
    public decimal Balance { get; private set; }

    public Account(string owner) => Owner = owner;

    public void Deposit(decimal amount)
    {
        if (amount <= 0) throw new ArgumentException("amount must be positive");
        Balance += amount;
    }
}

public record Point(int X, int Y);

型の宣言は、同じファイルではトップレベルステートメントの後に置く必要があります。クラスは単一継承(class Savings : Account)で、インターフェースはいくつでも実装できます。

コレクションとLINQ

System.Collections.Generic のジェネリックコレクションは、日常的に使うデータ構造です。LINQ(Language Integrated Query)は、すべてのコレクションに Where、Select、OrderBy、GroupBy などのメソッドを追加します。

var nums = new List<int> { 3, 1, 2, 5 };
nums.Add(4);
nums.Sort();
Console.WriteLine(string.Join(", ", nums));      // 1, 2, 3, 4, 5

var ages = new Dictionary<string, int> { ["ann"] = 31, ["bob"] = 25 };
ages["cy"] = 40;
if (ages.TryGetValue("bob", out int bobAge)) Console.WriteLine(bobAge);  // 25

var evenSquares = nums.Where(n => n % 2 == 0).Select(n => n * n).ToList();
Console.WriteLine(string.Join(" ", evenSquares)); // 4 16

var oldest = ages.OrderByDescending(kv => kv.Value).First();
Console.WriteLine(oldest.Key);                    // cy

そのほかのよく使うコレクションには、重複のない要素を保持する HashSet<T>、Queue<T>、Stack<T>、int[] のような固定長配列があります。

特徴的な機能:asyncとawait

C#は、のちに多くの言語が採用した async/await モデルを導入しました。async メソッドは Task を返し、Webリクエストやファイル読み込みのような時間のかかる処理を、スレッドをブロックせずに await できます。

using System.Net.Http;

using var http = new HttpClient();
var sizes = await Task.WhenAll(
    GetLengthAsync(http, "https://example.com"),
    GetLengthAsync(http, "https://example.org"));
Console.WriteLine($"downloaded {sizes.Sum()} characters");

static async Task<int> GetLengthAsync(HttpClient http, string url)
{
    string html = await http.GetStringAsync(url);
    return html.Length;
}

Task.WhenAll は両方のリクエストを同時に実行し、両方の完了を待ちます。using var 宣言は、スコープの終わりで HttpClient を破棄します。

例外処理

エラーは例外として扱われます。具体的な型から先に catch し、後始末には finally や using を使います。TryParse パターンを使うと、不正になりやすい入力で例外を避けられます。

try
{
    int age = int.Parse("abc");
}
catch (FormatException ex)
{
    Console.WriteLine($"not a number: {ex.Message}");
}
finally
{
    Console.WriteLine("done");
}

if (!int.TryParse("41", out int parsed)) parsed = 0;
Console.WriteLine(parsed);   // 41

小さな完成プログラム:単語の出現頻度

コンソールプロジェクトの Program.cs をこのコードに置き換え、dotnet run -- notes.txt を実行します。

using System.Text.RegularExpressions;

if (args.Length != 1)
{
    Console.Error.WriteLine("usage: dotnet run -- FILE");
    return 1;
}

try
{
    string text = File.ReadAllText(args[0]).ToLowerInvariant();
    var top = Regex.Matches(text, "[a-z']+")
        .GroupBy(m => m.Value)
        .Select(g => (Word: g.Key, Count: g.Count()))
        .OrderByDescending(t => t.Count)
        .Take(5);

    foreach (var (word, count) in top)
        Console.WriteLine($"{count,5}  {word}");
    return 0;
}
catch (FileNotFoundException)
{
    Console.Error.WriteLine($"file not found: {args[0]}");
    return 1;
}

トップレベルステートメントでは、コマンドライン引数 args を読み、終了コードを返せます。新しいプロジェクトでは、暗黙的なusingにより System.IO、System.Linq、System.Collections.Generic が自動的にインポートされます。

初心者がよくやる間違い

  • 金額に double を使う。2進数の丸め誤差を避けるには decimal を使います。
  • null許容の警告を無視する。実行時に NullReferenceException になります。
  • 同じリストに対する foreach の中で List<T> を変更し、InvalidOperationException が発生する。
  • 長時間動くアプリで、リクエストごとに新しい HttpClient を作る。1つのインスタンスを再利用するか、IHttpClientFactory を使います。
  • LINQのクエリが遅延実行されることを忘れる。ToList() を呼ばない限り、列挙のたびにクエリが再実行されます。

次のステップ

Microsoft Learnには、言語のツアーやインタラクティブなチュートリアルを含む、公式のC#ドキュメントがあります。続いて、WebのAPI向けにASP.NET Core、データベース向けにEntity Framework Core、ゲーム向けにUnityを学び、テストにはxUnitまたはNUnitを使いましょう。エディタは、Visual Studio、C# Dev Kitを入れたVS Code、JetBrains Riderがよく使われます。

よくある質問

C#はWindows専用ですか?

いいえ。現代の.NETはWindows、macOS、Linuxで動作し、C#アプリはLinuxサーバーやコンテナにデプロイできます。WPFやWindows Formsなど、一部のデスクトップUIフレームワークだけがWindows専用です。

C#と.NETの違いは何ですか?

C#はプログラミング言語です。.NETは、C#のコードをコンパイルして実行するランタイムとライブラリです(F#やVisual Basicも対象です)。

C#はJavaに似ていますか?

はい、多くの点で似ています。どちらも静的型付けでガベージコレクションを持つ、C系の構文のオブジェクト指向言語です。C#にはプロパティ、LINQ、async/await、値型の構造体、レコードなどの機能が加わっています。

C#はゲーム開発に向いていますか?

はい。最も広く使われているゲームエンジンの一つであるUnityはゲームスクリプトにC#を使い、GodotエンジンもC#をサポートしています。

コーディング講座の一覧