本書は、マイクロソフト社が開発したプログラミング言語「C#」について解説しています。
C#は、先行するC、.NET Foundationを通じて開発し、MITライセンスの下でリリースされている共通言語基盤 (Common Language Infrastructure; CLI)で動作することが特徴です。
C#は、多くの開発者によって広く使用されており、プログラミングの初学者から熟練者まで幅広い層に向けて設計されています。また、C#は.NET Frameworkや.NET Coreといったフレームワークを使用して開発することができ、WindowsアプリケーションやWebアプリケーションなどの開発に適しています。
{{コラム|.NET Framework と .NET Core と .NET |2=.NET Framework、.NET Core、および.NETは、Microsoftが開発したプログラミングフレームワークの異なるバージョンやエディションを指す用語です。
.NET Framework: 最初にリリースされた.NET実行環境です。Windows向けのプラットフォームで、広く利用されています。Windowsが動作する環境で構築されたアプリケーションの開発や実行に使用されます。.NET Frameworkは、ASP.NETなどのWebアプリケーション、デスクトップアプリケーション、および一般的なWindowsアプリケーションの開発に使用されます。2019年4月にリリースされたバージョン4.8をもって.NET Frameworkのメジャーアップデートを終了することがアナウンスされました。
.NET Core: クロスプラットフォームの.NET実行環境で、Linux、macOS、Windowsなどの異なるプラットフォームで動作するアプリケーションを構築するための開発フレームワークです。軽量化されており、クロスプラットフォームでの開発、マイクロサービス、クラウドベースのアプリケーションの開発に適しています。.NET Coreは、.NET 5および. NET 6で統合され、以降のバージョンは.NETと呼ばれることになりました。
.NET: .NET 5以降、Microsoftは.NET Coreと.NET Frameworkを統合し、単一のプラットフォームとして提供しています。.NET 5は.NET Core 3.1の後継としてリリースされ、クロスプラットフォーム対応、高速性、新機能の提供が行われました。その後、.NET 6、.NET 7、.NET 8 などのバージョンがリリースされています。この単一の.NETは、クロスプラットフォームでの開発をサポートし、Windows、Linux、macOSなどのさまざまな環境で動作するアプリケーションの構築に使用されます。
これらのフレームワークは、異なる目的やプラットフォームでのアプリケーション開発に使用されますが、現在は.NETが将来のバージョンを統合しているため、従来の.NET Frameworkよりも.NET Coreおよび.NETを使用することが推奨されています。
C# はGUIも作成できますが、本ページでは説明の初期のうちは、コンソールアプリ（コマンド プロンプトのような画面にテキスト表示するプログラムのこと）のプログラムを解説したいと思います。
C++になくてC#にある機能は多々ありますが、特にC++との違いが大きい話題を挙げたいと思います。
{{コラム|C# の標準規格|2=
プログラミング言語C#は、2000年にMicrosoft社のAnders Hejlsberg氏によって設計され、その後2002年にEcma（ECMA-334）、2003年にISO/IEC（ISO/IEC 23270）によって国際標準として承認されました。
2023年12月時点のC#標準
C#には以下のような独立した実装があります。
クローズドなVC#:Visual Studio 2013 まで。
Roslyn:Microsoftが開発したApacheライセンスのオープンソースプロジェクト。GitHubで公開されています。Visual Studio 2015 以降のVC#。
シェアードソース共通言語基盤のC#コンパイラ:共通言語基盤 (CLI) とともにがソースコードが公開されたC#コンパイラ。
Mono Compiler Suite(mcs):Mono Projectが開発したMonoの一部を構成します。
the C-Sharp code compiler (cscc):DotGNU Projectが開発したPortable.NETの一部を構成します2012年12月時点で、DotGNUプロジェクトは廃止され、大規模な新しいボランティアの取り組みが生まれるまで再開される見込みはありません。ただし、例外としてlibjitコンポーネントは、現在は独立したlibjitパッケージとして存在しています。。
Microsoft以外の実装は、ECMA-334に基づいています。
ECMA-334の2023年12月時点での最新は VC#7.0 相当のECMA-334:2023なので、MicrosoftのVC#の比較的新しいバージョンでコンパイル出来るソースコードが、MonoなどMicrosoft以外の実装でコンパイル出来ない場合があります。
C#コードで実行中の.NETバージョンを調べるには、次のような方法があります。
using System;
using System.Runtime.InteropServices;
class Class1 {
  static void Main(string[] args) {
    Console.WriteLine(RuntimeInformation.FrameworkDescription);
  }
}
実行結果 :
.NET 8.0.0
これによって、実行中の.NETのバージョンがコンソールに表示されます。
C#コンパイラのバージョンを調べるには、次のような方法があります。
コンパイル結果 :
Compilation error (line 1, col 8): #error: 'version'
Compilation error (line 1, col 8): Compiler version: '4.8.0-7.23558.1 (e0917286)'. Language version: latest (12.0).
Compilation error (line 1, col 1): Program does not contain a static 'Main' method suitable for an entry point
これによって、C#コンパイラーのバージョンとC#言語のバージョンを確認出来ます。
using System;
class Hello {
    static void Main(string[] args) {
        var a = 14;
        Console.WriteLine($"トムは{a}歳です");
    }
}
実行結果 :
トムは14歳です
このC#のコードは、変数 a の値を文字列に埋め込んで出力するものです。これはC# 6.0から導入された補間文字列（interpolated string）[https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting#format-string-component $ - string interpolation (C# reference)]と呼ばれる機能を使用しています。
補間文字列（Interpolated Strings）
        Console.WriteLine($"トムは{a}歳です");
 
上記の行は、$ 記号を文字列の前に付けることで補間文字列を作成しています。
C#の補間文字列では、波カッコ {} 内にプレースホルダーを配置します。
これにより、その場所に変数や式の値が埋め込まれます。
ここでは、波カッコ {} 内に変数 a を直接埋め込んでいます。
この記法を使うことで、文字列中に変数の値を直接埋め込むことができます。
補間文字列では単純な変数だけでなく、式も埋め込むことができます。例えば、数値の計算結果や関数の戻り値を埋め込むことができます。
 
var x = 10;
var y = 20;
string result = $"合計は{x + y}です"; // 合計は30です
この例では、{} 内に x + y という式があります。
これは変数 x と y の和を計算し、その結果が文字列に埋め込まれます。
補間文字列では、文字列の中に挿入する変数や式に対してフォーマット指定を行うことも可能です。例えば、小数点以下2桁まで表示する場合や日付のフォーマットを指定する場合などに有用です。
 
double pi = Math.PI;
string formattedPi = $"円周率は{pi:F2}です"; // 円周率は3.14です
この例では、{pi:F2} の部分で pi の値が小数点以下2桁まで表示されます。
補間文字列は可読性が高く、動的な文字列の構築を直感的に行うことができます。
変数や式を {} 内に挿入することで、コードをわかりやすく保ちながら柔軟性を持たせることができます。
[https://paiza.io/projects/iXS1RA99F2XbPO1qSXFvxg?language=csharp コード例]:
using System;
public class Hello {
  public static void Main(string[] args) {
    Console.WriteLine($"3 + 5 = {3 + 5}");
    // 十進数の11を変換するコード
    Console.WriteLine($"{11:x} "); // 16進数に変換
    Console.WriteLine($"{Convert.ToString(11, 2)} ") ; // 2進数に変換
  }
}
実行結果 :
3 + 5 = 8
b 
1011
特に書式を宣言しない場合、数値は10進数として扱われます。
が、10進数(decimal)の出力を明示したい場合、 {11:D}  のように「:D」をつけることで可能です。
整数は自動的に昇格し浮動小数点として扱われる:
using System;
public class Hello {
  public static void Main(string[] args) {
    Console.WriteLine($"0x{Int64.MaxValue:x}"); // Hex.
    Console.WriteLine($"{Int64.MaxValue:g}");   // general
    Console.WriteLine($"{Int64.MaxValue:e}");   // exp.
    Console.WriteLine($"{Int64.MaxValue:f}");   // float
    // Console.WriteLine($"{1.2:X}");           // コレはエラーになる
    Console.WriteLine($"{0b1101}");             // binary literal
    // Console.WriteLine($"{13:b}");            // これはエラーになる（.NET 8 からは有効）
  }
}
実行結果 :
0x7fffffffffffffff
9223372036854775807 
9.223372e+018  
9223372036854775807.00 
13
整数に書式化文字列の e や f を適用すると、浮動小数型に変換され表示されます。変態ですね。
この仕様は、型を間違えて書式化文字列を与えたことに気づく機会を奪うので注意が必要です。
なにもチェックしていないのかというと、$"{1.2:X}" はシッカリとエラーにします。一貫性がありませんね。
一貫性と言えば、C#7.2 から 0b1101 のような2進数リテラルに対応したのですが、書式化文字列は2進数に対応していません。一貫性がありませんね。
特殊文字 @ を前置した文字列リテラルは、逐語的文字列リテラルです。
逐語的文字列リテラルでは、単純なエスケープシーケンス(バックスラッシュを表す「 \ 」など)、16 進エスケープシーケンス(大文字の A を表す「 \x0041 」など)、および Unicode エスケープシーケンス (大文字の A を表す「 \u0041 」など) はそのまま解釈されます。引用符のエスケープシーケンス("")のみ文字通りに解釈されず、二重引用符が1つ生成されます[https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/verbatim @]。
[https://paiza.io/projects/nucHBjtah8fPBFFrlZGrzg?language=csharp コード例]:
using System;
public class Hello {
  public static void Main(string[] args) {
    Console.WriteLine(@"
\ -- "" -- 
C:\temp\test.txt
\x0041
\u0041
\n
\t
");
 }
}
実行結果 :
\ -- " -- 
C:\temp\test.txt
\x0041
\u0041
\n
\t
C#における配列は、同じ型の複数の要素を保持するデータ構造です。配列は固定長であり、要素数が宣言時に決まります。以下に基本的な配列の使い方を示します。
配列の宣言と初期化
// int型の要素を持つ配列を宣言して初期化する方法
int[] numbers = new int[5]; // 要素数5のint型配列を作成し、0で初期化
// 文字列の配列を宣言して初期化する方法（初期値を指定）
string[] names = new string[] { "Alice", "Bob", "Charlie" };
// 初期化の省略記法（C# 3.0以降）
char[] vowels = { 'a', 'e', 'i', 'o', 'u' };
 
配列の要素へのアクセス
using System;
// 配列の要素にアクセスする方法
int[] numbers = { 10, 20, 30, 40, 50 };
Console.WriteLine(numbers[0]); // 最初の要素を取得して表示する（出力: 10）
Console.WriteLine(numbers[2]); // 3番目の要素を取得して表示する（出力: 30）
// 配列の要素に値を代入する
numbers[1] = 42; // 1番目の要素を 42 に変更
Console.WriteLine(numbers[1]); // 1番目の要素を取得して表示する（出力: 42）
配列の先頭の要素への添字は 0 です。
配列の長さと反復処理
// 配列の長さを取得する
Console.WriteLine(numbers.Length); // 配列の要素数を取得して表示する（出力: 5）
// 配列の要素を反復処理する
foreach (var name in names) {
    Console.WriteLine(name); // 配列の要素を順番に表示する
}
配列は要素の型と長さが固定されているため、初期化後に要素数を変更することはできません。要素へのアクセスは、配列名[添え字] のように添え字を用いて行います。配列の要素数は Length プロパティを使って取得できます。また、foreach ループを使って配列の要素を順番に処理することができます。
C#には、プログラミングを効率化するために、あらかじめ、よく使いそうなデータ構造を取り扱う仕組むが言語の機能として提供されています。
標準C言語やC++にない、よく使われる機能が、言語仕様として提供されています。
それを使わずとも、C言語などにある機能だけでもプログラミングは可能ですが、しかしC#の提供する専用機能を使うことで、コードが短くなったり、集団開発ではプログラマーたちによるバラツキが無くなるので品質が一様化して効率化が期待できます。また、コードの各部の意図も、C#の専用機能をつかうことで明確化するので効率化することが期待できます。
using System;
class Program {
    static void Main(string[] args) {
        // タプルの作成
        var person = ("John", "Doe");
        // タプルの要素にアクセスしてコンソールに表示
        Console.WriteLine($"First Name: {person.Item1}, Last Name: {person.Item2}");
    }
}
実行結果 :
First Name: John, Last Name: Doe
このコードでは、Main メソッド内でタプルを作成し、その要素にアクセスしています。
タプルは、異なるデータ型をまとめて1つの変数に格納するための便利な仕組みです。この例では、("John", "Doe") というタプルを作成しています。このタプルには2つの要素が含まれており、1つ目の要素は "John" であり、2つ目の要素は "Doe" です。
Item1 と Item2 は、タプルの要素を参照するためのデフォルトのプロパティ名です。この例では、Item1 は名前、Item2 は姓を表しています。これらの要素にアクセスしてコンソールに出力しています。
タプルは、関連するデータを1つにまとめて扱う際に役立ちます。しかし、要素の名前がないために、コードの読みやすさに影響を及ぼすこともあります。
タプル配列と繰り返し
using System;
class Program {
    static void Main(string[] args) {
        // タプルの配列を作成
        var people = new[] {
            ("John", "Doe"),
            ("Jane", "Smith"),
            ("Alice", "Johnson")
        };
        // 配列の要素を繰り返し処理して表示
        foreach (var (firstName, lastName) in people) {
            Console.WriteLine($"First Name: {firstName}, Last Name: {lastName}");
        }
    }
}
実行結果 :
First Name: John, Last Name: Doe
First Name: Jane, Last Name: Smith
First Name: Alice, Last Name: Johnson
people という名前のタプルの配列を作成しています。各タプルは名前と姓を表しており、例えば ("John", "Doe") は John Doe の名前を持つタプルを表しています。
foreach ループを使用して people 配列の要素を繰り返し処理しています。foreach ループの中で、var (firstName, lastName) のようにして、各タプルの要素を分解して firstName と lastName の名前付きの変数に格納しています。
各要素の名前と姓を Console.WriteLine を使ってコンソールに表示しています。Console.WriteLine($"First Name: {firstName}, Last Name: {lastName}"); この行では文字列補間を使って、各人物の情報を表示しています。
このように、タプルと foreach ループを組み合わせることで、配列内の各要素を分解し、分かりやすく取り扱うことができます。また、タプルの分解により、コードがより簡潔になり可読性が向上します。
record 型は、C# 9.0で導入された新しいデータ型で、不変（immutable）なデータ構造を定義するのに役立ちます。record はデータのイミュータビリティをサポートし、簡潔なコードでデータの保持と操作を行うための手段となります。
以下は、C#でRecord型を使用したサンプルコードです。
 
using System;
record Person(string FirstName, string LastName);
class Program {
    static void Main(string[] args) {
        var person1 = new Person("John", "Doe");
        var person2 = new Person("John", "Doe");
        bool areEqual = person1.Equals(person2); // 値ベースの等値比較
        Console.WriteLine($"Are persons equal? {areEqual}"); // 出力: Are persons equal? True
        var updatedPerson = person1 with { LastName = "Smith" }; // 新しいインスタンスを作成
        Console.WriteLine($"Updated person: {updatedPerson.FirstName} {updatedPerson.LastName}"); // 出力: Updated person: John Smith
    }
}
このコードでは、Person Record型を定義する際に、C# 9.0(.NET 5)から導入された短縮構文を使用しています。record キーワードを使って、コンストラクターの引数をフィールドと同時に指定し、簡潔な記述を可能にしています。また、new Person("John", "Doe") のようにコンストラクターを呼び出してインスタンスを生成しています。
Person Record型が定義されています。このRecord型は、FirstName と LastName の2つのプロパティを持っています。
Main メソッドでは、Person Record型のインスタンスを作成しています。new Person("John", "Doe") のようにコンストラクターを使用して、FirstName と LastName の値を渡しています。
person1 と person2 を Equals メソッドを使って比較し、値ベースの等値比較を行っています。この場合、同じ値を持つため true が返されます。
with キーワードを使って、person1 を元に LastName を更新した新しいインスタンス updatedPerson を作成しています。これにより、元のインスタンスは変更されず、新しいインスタンスが作成されます。
record を要素とする配列を作成し、その配列を繰り返し処理する方法を示します。
以下は、C#でRecord型の配列を作成し、それを繰り返し処理するサンプルコードです。
using System;
record Person(string FirstName, string LastName);
class Program {
    static void Main(string[] args) {
        // Person Record型の配列を作成
        var people = new[] {
            new Person("John", "Doe"),
            new Person("Jane", "Smith"),
            new Person("Alice", "Johnson")
        };
        // 配列の要素を繰り返し処理して表示
        foreach (var person in people) {
            Console.WriteLine($"First Name: {person.FirstName}, Last Name: {person.LastName}");
        }
    }
}
Person Record型が定義されています。このRecord型は、FirstName と LastName の2つのプロパティを持っています。
Main メソッドでは、Person Record型のインスタンスを3つ作成し、それらを含む配列 people を作成しています。
foreach ループを使用して、people 配列の要素を繰り返し処理しています。各 person の FirstName と LastName の値をコンソールに表示しています。
このコードでは、Record型を使ってシンプルなデータモデルを作成し、配列の要素を簡単に操作・表示する方法が示されています。
LINQ（Language Integrated Query）を使用して、Record型の配列要素を繰り返し処理する方法を示すコードを書いてみましょう。
using System;
using System.Linq;
record Person(string FirstName, string LastName);
class Program {
    static void Main(string[] args) {
        // Person Record型の配列を作成
        var people = new[] {
            new Person("John", "Doe"),
            new Person("Jane", "Smith"),
            new Person("Alice", "Johnson")
        };
        // LINQを使って配列の要素を繰り返し処理して表示
        var query = from person in people
                    select $"First Name: {person.FirstName}, Last Name: {person.LastName}";
        foreach (var result in query) {
            Console.WriteLine(result);
        }
    }
}
このコードでは、LINQクエリを使ってRecord型の配列要素を繰り返し処理しています。from句を使用してpeople配列内のPerson Record型の要素を取り出し、select句で文字列に変換しています。その後、foreachループを使用してクエリ結果をコンソールに出力しています。
LINQを使うことで、より柔軟なデータのクエリや操作が可能になります。
C#におけるNull許容型（Nullable types）は、通常の値型にnullを許容するための機能です。nullが許容されない通常の値型（int、double、boolなど）では、変数にnullを代入することができませんが、Null許容型を使用することで、nullを含む値を代入できるようになります。
Null許容型は、C# 2.0で導入されました。主な目的は、データベースから取得したデータや他の外部ソースからのデータを扱う際に、nullを適切に処理することです。例えば、データベースの列がnull許容型である場合、その列の値がnullであることを表現できます。
C#では、Null許容型は値型の末尾に「?」を付けることで宣言されます。例えば、int型のNull許容型は「int?」となります。
[https://dotnetfiddle.net/knVpWJ Null許容型の使用例]:
using System;
public class Program {
  public static void Main() {
    int ? nullableInt = null;
    if (nullableInt.HasValue) {
      Console.WriteLine("nullableIntの値は: " + nullableInt.Value);
    } else {
      Console.WriteLine("nullableIntはnullです");
    }
  }
}
ここで、"HasValue"プロパティはnullableIntがnullでないかどうかをチェックし、「Value」プロパティは実際の値を取得します。
Null許容型は、プログラムでnullを正しく扱うための重要なツールであり、特に外部リソースやデータベースとのやり取りなどで有用です。
C# 8.0から導入されたNullable Reference Types (null 許容参照型)は、null可能性を表現するための機能です。通常の参照型（クラス、インターフェースなど）はnullを許容しますが、Nullable Reference Typesを使用することで、nullが許容されるかどうかを厳密に指定できます。
この機能を有効にすると、コンパイラがnullに関する潜在的な問題を見つけてくれます。主な機能や使い方は次の通りです:
null 許容注釈: ?を型の末尾に追加することで、nullが許容されることを示します。例えば、string? nullableString = null;というように、nullableStringがnullを持つ可能性があることを宣言します。
null 警告と注釈の付与: Nullable Reference Typesを有効にすると、null許容性に関する警告が出るようになります。変数やパラメータがnullを許容する場合、適切な注釈を付けることで、nullを許容することが意図されていることを示します。
Nullable許容性のコンテキスト フロー: メソッドや式のコンテキストで、nullが許容されるかどうかを推論します。例えば、nullを返すメソッドが呼び出された場合、戻り値がnull許容かどうかを判断し、適切な警告を出します。
Nullable Reference Typesの有効化: プロジェクト全体でNullable Reference Typesを有効にするには、プロジェクトファイルに enable を追加するか、コンパイラオプションを設定します。
Nullable Reference Typesは、null関連のバグを減らしたり、コードの安全性を向上させたりするのに役立ちます。しかし、全てのnull関連の問題を解決するわけではないため、コードの品質を維持するためにも、nullに関する適切な扱いが重要です。
以下に、C#のNullable Reference Typesのコード例とその解説を示します。
まず、Nullable Reference Typesを有効にするには、プロジェクトファイルに enable を追加します。
[https://dotnetfiddle.net/XktYhl Nullable Reference Typesのコード例]:
using System;
class Program {
  static void Main() {
    string ? nullableString = null; // null 許容参照型を使用した nullableString 変数の宣言
    ProcessString(nullableString); // メソッド呼び出し
    string regularString = "Hello!";
    ProcessString(regularString); // 通常のstringを渡す
    // Nullable Reference Typesの機能を使った場合の例外処理
    string nonNullableString = "This is not nullable";
    nullableString = nonNullableString; // Nullableの変数に非Nullableの値を代入する
    Console.WriteLine(nullableString.ToUpper()); // コンパイルエラーになる可能性があります（Nullableの変数を使用する前にnullチェックが必要）
  }
  static void ProcessString(string ? text) {
    if (text != null) {
      Console.WriteLine(text.ToUpper()); // null チェック後の安全な参照
    } else {
      Console.WriteLine("Input string is null");
    }
  }
}
#nullable enable: Nullable Reference Types を有効にするためのディレクティブです。これにより、null 許容参照型が有効になります。
string? nullableString = null;: nullableString という変数を null 許容参照型として宣言し、nullで初期化します。string?はnullを含むことを示しています。
ProcessString(nullableString);: ProcessString メソッドに nullableString を渡します。このメソッド内では、null チェックを行って安全に参照を行っています。
string nonNullableString = "This is not nullable"; nullableString = nonNullableString;: 非nullableの nonNullableString を nullableString に代入しようとすると、Nullable Reference Typesのチェックによって警告が出たり、コンパイルエラーになる可能性があります。
Console.WriteLine(nullableString.ToUpper());: コンパイラは nullableString がnullの可能性があるため、これを呼び出す前にnullチェックが必要であることを示します。明示的なnullチェックが行われていないため、コンパイルエラーになるかもしれません。
Nullable Reference Typesを使うことで、nullに関する潜在的な問題をコンパイル時に発見し、それらを回避するための対策を行うことができます。
拡張メソッドは、既存の型に新しいメソッドを追加するための仕組みです。これは静的クラスに定義され、対象の型（通常はクラスまたはインタフェース）に対してメソッドを追加します。ただし、拡張メソッドはインスタンスメソッドではなく、静的メソッドであり、そのインスタンスが実際に作成されていないため、ボックス化には直接的な影響を与えません。
このC#のコードは、文字列を逆順にする拡張メソッドを使用する単純な例です。コードの各部分を解説してみましょう。
using System;
public static class StringExtensions {
  public static string ReverseString(this string input) {
    char[] charArray = input.ToCharArray();
    Array.Reverse(charArray);
    return new string(charArray);
  }
}
public class Program {
  public static void Main() {
    string originalString = "Hello, world!";
    string reversedString = originalString.ReverseString();
    Console.WriteLine(reversedString); // 出力: "!dlrow ,olleH"
  }
}
実行結果:
!dlrow ,olleH
using System;: System 名前空間を使うためのディレクティブ。Console クラスなど、基本的な入出力機能を提供します。
StringExtensions クラス: StringExtensions は静的クラスです。this string input という引数を持つ ReverseString という名前の拡張メソッドが含まれています。このメソッドは、文字列を逆順にして新しい文字列を返すものです。
public class Program: Program クラスは通常のクラスであり、C#のアプリケーションは Main() メソッドを持つクラスで始まります。このクラスには Main() メソッドが含まれています。
public static void Main(): C#のプログラムのエントリーポイントである Main() メソッド。void は戻り値がないことを意味し、static は Main() メソッドが静的であることを示しています。このメソッドは、文字列を逆順にする拡張メソッド ReverseString() を使用して、元の文字列を逆順にしてコンソールに出力します。
このプログラムは、originalString の値を ReverseString() で逆順にし、reversedString に格納しています。そして Console.WriteLine() を使ってその逆順の文字列をコンソールに出力しています。
別の例、IntExtensions などのように、int 型に対して拡張メソッドを提供するためのクラスを定義することもできます。C#では、任意の型に対して拡張メソッドを定義することが可能です。
以下は、IntExtensions クラスを使用して int 型に対する拡張メソッドを定義した例です。
using System;
public static class IntExtensions {
  public static bool IsEven(this int number) {
    return number % 2 == 0;
  }
}
public class Program {
  public static void Main() {
    int num = 6;
    // 拡張メソッドを使って奇数か偶数かを判定する
    if (num.IsEven()) {
      Console.WriteLine("Even number");
    } else {
      Console.WriteLine("Odd number");
    }
  }
}
実行結果:
Even number
この例では、IntExtensions クラスが IsEven() という名前の拡張メソッドを提供しています。これは int 型の変数に対して偶数かどうかを判定する機能を追加します。そして Main() メソッドでこの拡張メソッドを使用して、与えられた整数が偶数か奇数かを判定し、コンソールに出力しています。
{{コラム|C#のアップデートやトピック|2=バージョンごとのアップデートやトピック
C# 9.0 (2020年11月リリース)
record キーワードを使用して、イミュータブルで値型のオブジェクトを定義できます。
パターンマッチングや分解などの便利な機能を提供します。
switch ステートメントや if 式にパターンマッチングを使用する際に、新しいパターンが追加されました。
より柔軟なパターンマッチングが可能になりました。
イミュータブルなオブジェクトの初期化時に使用される init アクセサーが導入されました。
設定は初期化時のみ可能で、その後は読み取り専用になります。
C# 10.0 (2021年11月リリース) 
グローバルな using 宣言が可能になり、全てのファイルで共通のusingを指定できるようになりました。
namespace 宣言をファイルスコープで行えるようになりました。
ファイル全体で共通のネームスペースを宣言できます。
コンストラクタでの this キーワードの省略や、フィールドの初期化と宣言を同時に行えるようになりました。
文字列補間内での改行文字 (\n) の使用が可能になりました。
これらのアップデートはC#の使いやすさや柔軟性を向上させ、コーディングをより効率的にするための機能を提供しています。