C#は、Microsoftが開発したオブジェクト指向プログラミング言語であり、現在のソフトウェア開発シーンにおいて欠かせない存在となっています。

デスクトップアプリからWebサービス、Unityを用いたゲーム開発まで、その応用範囲は驚くほど広域です。

本記事では、C#をこれから学ぶ初心者の方はもちろん、最新の仕様を再確認したい中級者の方に向けて、基本文法から最新機能までを網羅的に解説していきます。

C#とはどのような言語か

C#は、C言語やC++の流れを汲みつつ、Javaの影響も受けて誕生したプログラミング言語です。

.NET(ドットネット)プラットフォーム上で動作することを前提に設計されており、堅牢な型システムとモダンな文法を兼ね備えています。

かつてはWindows専用のイメージが強かったC#ですが、現在はオープンソース化された「.NET」により、Windows、macOS、Linuxといったマルチプラットフォームでの動作が当たり前となりました。

また、強力なメモリ管理機能(ガベージコレクション)を備えているため、開発者はメモリの解放を意識することなく、ロジックの実装に集中できるのが大きなメリットです。

C#プログラムの基本構造

C#のプログラムは、いくつかの階層構造によって構成されています。

最もシンプルなプログラムを通じて、その構成要素を確認してみましょう。

プログラムの最小構成

現代のC#(C# 9.0以降)では、「トップレベルステートメント」という機能により、クラスやメソッドの定義を省略して記述を開始できるようになりました。

しかし、大規模な開発では依然として従来の構造が重要です。

C#
using System;

namespace HelloWorldApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // コンソールにメッセージを表示
            Console.WriteLine("Hello, C# World!");
        }
    }
}
実行結果
Hello, C# World!

各構成要素の役割

  1. using指令using System; のように記述し、他のライブラリや名前空間を利用することを宣言します。
  2. 名前空間(namespace)
    プログラムを整理するための「フォルダ」のような役割を果たします。名前の衝突を防ぐために使用されます。
  3. クラス(class)
    C#のプログラムはすべてクラスの中に記述されます。オブジェクト指向の基本単位です。
  4. Mainメソッド
    プログラムが実行された際に、最初に呼び出されるエントリーポイントです。

変数とデータ型

プログラム内でデータを一時的に保存するための箱が「変数」です。

C#は「静的型付け言語」であり、変数を使用する際には、その変数がどのような種類のデータ(型)を扱うかを明確にする必要があります。

基本的なデータ型

C#には多くの組み込み型が存在します。

主要なものを以下の表にまとめました。

カテゴリ型名説明
整数int32ビット符号付き整数123
長整数long64ビット符号付き整数1234567890L
浮動小数点double倍精度浮動小数点数3.1415
高精度小数decimal金銭計算用の高精度小数100.50m
真偽値bool真 (true) または 偽 (false)true
文字char1つのUnicode文字‘A’
文字列string文字の並び“こんにちは”

変数の宣言と初期化

変数は、型名 変数名 = 値; という形式で宣言します。

C#
int age = 25;
string name = "田中太郎";
double height = 175.5;
bool isStudent = false;

Console.WriteLine($"{name}さんは{age}歳です。");

型推論 (var)

C# 3.0から導入された var キーワードを使用すると、コンパイラが右辺の値を基に型を自動的に判別してくれます。

これを型推論と呼びます。

C#
var message = "Hello"; // string型と見なされる
var count = 10;        // int型と見なされる

注意点として、varはローカル変数にのみ使用可能であり、宣言と同時に初期化する必要があります。

コードの可読性を高めるために、型が明らかな場合(new演算子を使用する場合など)に積極的に使われます。

演算子

計算や条件の比較を行うために使用されるのが演算子です。

算術演算子

数値の計算に使用します。

  • +(加算)
  • -(減算)
  • *(乗算)
  • /(除算)
  • %(剰余:あまり)

比較演算子と論理演算子

条件分岐で頻繁に使用されます。

  • ==(等しい)
  • !=(等しくない)
  • &&(かつ:AND)
  • ||(または:OR)
  • !(否定:NOT)

制御構文

プログラムの流れを制御するための構文です。

条件によって処理を分けたり、同じ処理を繰り返したりします。

条件分岐 (if, switch)

if文

最も基本的な条件分岐です。

C#
int score = 85;

if (score >= 90)
{
    Console.WriteLine("優秀です");
}
else if (score >= 70)
{
    Console.WriteLine("合格です");
}
else
{
    Console.WriteLine("不合格です");
}

switch文

特定の変数の値に応じて分岐させる場合に適しています。

最新のC#では、より簡潔な「switch式」も利用可能です。

C#
string day = "Monday";

// 従来のswitch文
switch (day)
{
    case "Monday":
        Console.WriteLine("週の始まりです");
        break;
    case "Friday":
        Console.WriteLine("週末まであと少しです");
        break;
    default:
        Console.WriteLine("通常の日です");
        break;
}

// モダンなswitch式
string message = day switch
{
    "Monday" => "月曜日",
    "Friday" => "金曜日",
    _ => "その他の日" // デフォルトケース
};

繰り返し処理 (for, foreach, while)

for文

回数を指定して繰り返す場合に適しています。

C#
for (int i = 0; i < 5; i++)
{
    Console.WriteLine($"ループ回数: {i}");
}

foreach文

配列やリストの全要素を順番に処理する場合に非常に便利です。

C#開発において最も多用されるループ構文の一つです。

C#
string[] fruits = { "Apple", "Banana", "Cherry" };

foreach (var fruit in fruits)
{
    Console.WriteLine(fruit);
}

配列とコレクション

複数のデータをまとめて扱うための仕組みです。

配列 (Array)

サイズが固定されたデータの集合です。

C#
int[] numbers = new int[3];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;

リスト (List<T>)

サイズを動的に変更できる、非常に柔軟なコレクションです。

実務では配列よりも List<T> が使われるケースが多いです。

C#
using System.Collections.Generic;

List<string> names = new List<string>();
names.Add("Alice");
names.Add("Bob");
names.Remove("Alice");

Console.WriteLine(names.Count); // 要素数を確認

メソッドの定義と呼び出し

特定の処理をひとまとめにしたものをメソッドと呼びます。

C#
// メソッドの定義
// 戻り値の型 メソッド名(引数)
public int Add(int a, int b)
{
    return a + b;
}

// 呼び出し例
int result = Add(5, 3);

引数のオプションと名前付き引数

C#では、引数にデフォルト値を設定したり、呼び出し時に引数名を指定したりできます。

C#
public void Greet(string name, string message = "こんにちは")
{
    Console.WriteLine($"{name}さん、{message}");
}

// 呼び出し
Greet("田中"); // 田中さん、こんにちは
Greet("佐藤", "さようなら"); // 佐藤さん、さようなら
Greet(message: "お元気ですか", name: "鈴木"); // 名前付き引数

オブジェクト指向プログラミングの基本

C#の真骨頂はオブジェクト指向にあります。

クラス、オブジェクト、継承、インターフェースといった概念を理解することが上達の鍵です。

クラスとインスタンス

クラスは「設計図」、インスタンス(オブジェクト)は設計図から作られた「実体」です。

C#
public class Car
{
    // プロパティ(属性)
    public string Model { get; set; }
    public int Speed { get; private set; }

    // コンストラクタ(初期化処理)
    public Car(string model)
    {
        Model = model;
        Speed = 0;
    }

    // メソッド(振る舞い)
    public void Accelerate(int amount)
    {
        Speed += amount;
        Console.WriteLine($"{Model}が加速しました。現在の速度: {Speed}km/h");
    }
}

// メイン処理での利用
var myCar = new Car("プリウス");
myCar.Accelerate(20);

継承

既存のクラスの機能を拡張して新しいクラスを作ることです。

C#
public class ElectricCar : Car
{
    public int BatteryLevel { get; set; }

    public ElectricCar(string model) : base(model)
    {
        BatteryLevel = 100;
    }

    public void Charge()
    {
        BatteryLevel = 100;
        Console.WriteLine("充電が完了しました。");
    }
}

インターフェース

「どのような機能を持つべきか」という契約を定義します。

多態性(ポリモーフィズム)を実現するために不可欠です。

C#
public interface IDriveable
{
    void Drive();
}

public class Truck : IDriveable
{
    public void Drive()
    {
        Console.WriteLine("トラックが走ります。");
    }
}

例外処理

プログラム実行中に発生するエラー(例外)を適切にハンドリングするための仕組みです。

C#
try
{
    int x = 10;
    int y = 0;
    int result = x / y; // 0除算エラー発生
}
catch (DivideByZeroException ex)
{
    Console.WriteLine("0で割ることはできません。");
}
catch (Exception ex)
{
    Console.WriteLine($"予期せぬエラー: {ex.Message}");
}
finally
{
    // エラーの有無にかかわらず必ず実行される
    Console.WriteLine("処理を終了します。");
}

LINQ (Language Integrated Query)

C#の強力な機能の一つが LINQ です。

配列やリストなどのデータ集合に対して、SQLのような直感的な記述で検索や抽出、加工を行うことができます。

C#
using System.Linq;
using System.Collections.Generic;

var numbers = new List<int> { 1, 5, 8, 12, 15, 20 };

// 10より大きい偶数のみを抽出し、2倍にする
var query = numbers
    .Where(n => n > 10 && n % 2 == 0)
    .Select(n => n * 2);

foreach (var n in query)
{
    Console.WriteLine(n);
}
実行結果
24
40

LINQを活用することで、複雑なループ処理を簡潔に記述できるようになり、コードの保守性が飛躍的に向上します。

非同期処理 (async / await)

現代のアプリケーション開発において、ネットワーク通信やファイルI/Oなどの重い処理を待ち時間にせず、アプリをフリーズさせない工夫が必要です。

C#では asyncawait を使うことで、非同期処理を同期処理に近い感覚で記述できます。

C#
public async Task DownloadDataAsync()
{
    Console.WriteLine("ダウンロード開始...");
    
    using var client = new HttpClient();
    // 非同期でデータを取得(完了するまで他の処理をブロックしない)
    string result = await client.GetStringAsync("https://example.com");
    
    Console.WriteLine($"データ取得完了。文字数: {result.Length}");
}

モダンC#の注目機能

C#は進化の速い言語です。

近年のバージョン(C# 10〜13周辺)で導入された便利な機能を紹介します。

レコード型 (record)

データの保持を目的としたクラスを簡潔に定義できます。

値ベースの比較が自動で実装されるのが特徴です。

C#
// 1行で定義可能!
public record Person(string Name, int Age);

var p1 = new Person("Alice", 20);
var p2 = new Person("Alice", 20);

Console.WriteLine(p1 == p2); // True (プロパティの値が同じなら等しいと判定される)

文字列補間と生文字列リテラル

文字列の中に変数を埋め込む「文字列補間」は $ を使います。

また、C# 11からはエスケープシーケンスを気にせず複数行の文字列を書ける「生文字列リテラル」が登場しました。

C#
string name = "C#";
// 文字列補間
Console.WriteLine($"Hello, {name}!");

// 生文字列リテラル (引用符3つで囲む)
string json = """
{
    "name": "C#",
    "version": 12
}
""";

プライマリコンストラクタ

C# 12から、通常のクラスでもレコード型のようにクラス名に続けて引数を記述できるようになりました。

C#
public class User(string username, string email)
{
    public string Username => username;
    public string Email => email;
}

C#を学ぶ上でのベストプラクティス

文法を覚えるだけでなく、「C#らしい書き方」を意識することが大切です。

  1. 命名規則を守る
    クラス名やメソッド名はPascalCase(例:CalculateTotal)、ローカル変数は camelCase(例:itemCount)にするのが標準的です。
  2. Null許容参照型を活用するstring? のように記述し、Null参照例外(NullReferenceException)を未然に防ぐ設計を心がけましょう。
  3. 適切なコレクションの選択
    単なるリストならList<T>、キーと値のペアなら Dictionary<TKey, TValue> を使い分けます。
  4. ドキュメントを活用する
    Microsoftの公式ドキュメント(Microsoft Learn)は非常に充実しています。迷ったらまず公式サイトを確認する癖をつけましょう。

まとめ

C#は、長い歴史を持ちながら常に進化を続けている非常に魅力的な言語です。

今回解説した基本文法(変数、制御構文、オブジェクト指向)は、あらゆるアプリケーション開発の土台となります。

最初は覚えることが多いと感じるかもしれませんが、「型に厳格である」というC#の特徴は、初心者がミスを早期に発見する助けにもなります。

まずは小さなコンソールアプリケーションから作り始め、徐々にLINQや非同期処理、最新のC#機能を組み込んでいくことで、確実にスキルアップできるはずです。

.NETの強力なエコシステムを武器に、ぜひC#でのプログラミングを楽しんでください。