本書は、マイクロソフト社が開発したプログラミング言語「C#」について解説しています。 C#は、先行するCC++Javaと同じファミリーに属するプログラミング言語で、マイクロソフト社の社員が.NET Foundationを通じて開発し、MITライセンスの下でリリースされている共通言語基盤 (Common Language Infrastructure; CLI)で動作することが特徴です。

Wikipedia
Wikipedia
ウィキペディアC Sharpの記事があります。
メインページ > 工学 > 情報技術 > [プログラミング > C Sharp

C#は、多くの開発者によって広く使用されており、プログラミングの初学者から熟練者まで幅広い層に向けて設計されています。また、C#は.NET Framework.NET Coreといったフレームワークを使用して開発することができ、WindowsアプリケーションやWebアプリケーションなどの開発に適しています。

.NET Framework と .NET Core と .NET
.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# の標準規格
プログラミング言語C#は、2000年にMicrosoft社のAnders Hejlsberg氏によって設計され、その後2002年にEcma(ECMA-334)、2003年にISO/IEC(ISO/IEC 23270)によって国際標準として承認されました。

2023年12月時点のC#標準

  • ECMA-334:2023(VC#7.0相当)
  • ISO/IEC 23270:2023(VC#7.0相当)
  • JIS X 3015:2008『プログラム言語C#』(VC#2.0相当)

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の一部を構成します[1]

Microsoft以外の実装は、ECMA-334に基づいています。

ECMA-334の2023年12月時点での最新は VC#7.0 相当のECMA-334:2023なので、MicrosoftのVC#の比較的新しいバージョンでコンパイル出来るソースコードが、MonoなどMicrosoft以外の実装でコンパイル出来ない場合があります。

C#のコードから.NETのバージョンを調べる

編集

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#コンパイラーのバージョンを調べる

編集

C#コンパイラのバージョンを調べるには、次のような方法があります。

#error version
コンパイル結果
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)[2]と呼ばれる機能を使用しています。

補間文字列(Interpolated Strings)
        Console.WriteLine($"トムは{a}歳です");

上記の行は、$ 記号を文字列の前に付けることで補間文字列を作成しています。 C#の補間文字列では、波カッコ {} 内にプレースホルダーを配置します。 これにより、その場所に変数や式の値が埋め込まれます。

ここでは、波カッコ {} 内に変数 a を直接埋め込んでいます。 この記法を使うことで、文字列中に変数の値を直接埋め込むことができます。

式の埋め込み
編集

補間文字列では単純な変数だけでなく、式も埋め込むことができます。例えば、数値の計算結果や関数の戻り値を埋め込むことができます。

var x = 10;
var y = 20;
string result = $"合計は{x + y}です"; // 合計は30です

この例では、{} 内に x + y という式があります。 これは変数 xy の和を計算し、その結果が文字列に埋め込まれます。

フォーマット指定
編集

補間文字列では、文字列の中に挿入する変数や式に対してフォーマット指定を行うことも可能です。例えば、小数点以下2桁まで表示する場合や日付のフォーマットを指定する場合などに有用です。

double pi = Math.PI;
string formattedPi = $"円周率は{pi:F2}です"; // 円周率は3.14です

この例では、{pi:F2} の部分で pi の値が小数点以下2桁まで表示されます。

補間文字列は可読性が高く、動的な文字列の構築を直感的に行うことができます。 変数や式を {} 内に挿入することで、コードをわかりやすく保ちながら柔軟性を持たせることができます。

基数の指定
編集
コード例
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つ生成されます[3]

コード例
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" です。

Item1Item2 は、タプルの要素を参照するためのデフォルトのプロパティ名です。この例では、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
  1. people という名前のタプルの配列を作成しています。各タプルは名前と姓を表しており、例えば ("John", "Doe") は John Doe の名前を持つタプルを表しています。
  2. foreach ループを使用して people 配列の要素を繰り返し処理しています。foreach ループの中で、var (firstName, lastName) のようにして、各タプルの要素を分解して firstNamelastName の名前付きの変数に格納しています。
  3. 各要素の名前と姓を Console.WriteLine を使ってコンソールに表示しています。Console.WriteLine($"First Name: {firstName}, Last Name: {lastName}"); この行では文字列補間を使って、各人物の情報を表示しています。

このように、タプルと foreach ループを組み合わせることで、配列内の各要素を分解し、分かりやすく取り扱うことができます。また、タプルの分解により、コードがより簡潔になり可読性が向上します。

record型

編集

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") のようにコンストラクターを呼び出してインスタンスを生成しています。

  1. Person Record型が定義されています。このRecord型は、FirstNameLastName の2つのプロパティを持っています。
  2. Main メソッドでは、Person Record型のインスタンスを作成しています。new Person("John", "Doe") のようにコンストラクターを使用して、FirstNameLastName の値を渡しています。
  3. person1person2Equals メソッドを使って比較し、値ベースの等値比較を行っています。この場合、同じ値を持つため true が返されます。
  4. with キーワードを使って、person1 を元に LastName を更新した新しいインスタンス updatedPerson を作成しています。これにより、元のインスタンスは変更されず、新しいインスタンスが作成されます。
Record型の配列と繰り返し
編集

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}");
        }
    }
}
  1. Person Record型が定義されています。このRecord型は、FirstNameLastName の2つのプロパティを持っています。
  2. Main メソッドでは、Person Record型のインスタンスを3つ作成し、それらを含む配列 people を作成しています。
  3. foreach ループを使用して、people 配列の要素を繰り返し処理しています。各 personFirstNameLastName の値をコンソールに表示しています。

このコードでは、Record型を使ってシンプルなデータモデルを作成し、配列の要素を簡単に操作・表示する方法が示されています。

Record型の配列と繰り返し(LINQ版)
編集

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を使うことで、より柔軟なデータのクエリや操作が可能になります。

Null許容型

編集

C#におけるNull許容型(Nullable types)は、通常の値型にnullを許容するための機能です。nullが許容されない通常の値型(int、double、boolなど)では、変数にnullを代入することができませんが、Null許容型を使用することで、nullを含む値を代入できるようになります。

Null許容型は、C# 2.0で導入されました。主な目的は、データベースから取得したデータや他の外部ソースからのデータを扱う際に、nullを適切に処理することです。例えば、データベースの列がnull許容型である場合、その列の値がnullであることを表現できます。 C#では、Null許容型は値型の末尾に「?」を付けることで宣言されます。例えば、int型のNull許容型は「int?」となります。

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を正しく扱うための重要なツールであり、特に外部リソースやデータベースとのやり取りなどで有用です。

Nullable Reference Types (null 許容参照型)

編集

C# 8.0から導入されたNullable Reference Types (null 許容参照型)は、null可能性を表現するための機能です。通常の参照型(クラス、インターフェースなど)はnullを許容しますが、Nullable Reference Typesを使用することで、nullが許容されるかどうかを厳密に指定できます。

この機能を有効にすると、コンパイラがnullに関する潜在的な問題を見つけてくれます。主な機能や使い方は次の通りです:

  1. null 許容注釈: ?を型の末尾に追加することで、nullが許容されることを示します。例えば、string? nullableString = null;というように、nullableStringがnullを持つ可能性があることを宣言します。
  2. null 警告と注釈の付与: Nullable Reference Typesを有効にすると、null許容性に関する警告が出るようになります。変数やパラメータがnullを許容する場合、適切な注釈を付けることで、nullを許容することが意図されていることを示します。
  3. Nullable許容性のコンテキスト フロー: メソッドや式のコンテキストで、nullが許容されるかどうかを推論します。例えば、nullを返すメソッドが呼び出された場合、戻り値がnull許容かどうかを判断し、適切な警告を出します。
  4. Nullable Reference Typesの有効化: プロジェクト全体でNullable Reference Typesを有効にするには、プロジェクトファイルに <Nullable>enable</Nullable> を追加するか、コンパイラオプションを設定します。

Nullable Reference Typesは、null関連のバグを減らしたり、コードの安全性を向上させたりするのに役立ちます。しかし、全てのnull関連の問題を解決するわけではないため、コードの品質を維持するためにも、nullに関する適切な扱いが重要です。

以下に、C#のNullable Reference Typesのコード例とその解説を示します。

まず、Nullable Reference Typesを有効にするには、プロジェクトファイルに <Nullable>enable</Nullable> を追加します。

Nullable Reference Typesのコード例
#nullable enable

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");
    }
  }
}
  1. #nullable enable: Nullable Reference Types を有効にするためのディレクティブです。これにより、null 許容参照型が有効になります。
  2. string? nullableString = null;: nullableString という変数を null 許容参照型として宣言し、nullで初期化します。string?はnullを含むことを示しています。
  3. ProcessString(nullableString);: ProcessString メソッドに nullableString を渡します。このメソッド内では、null チェックを行って安全に参照を行っています。
  4. string nonNullableString = "This is not nullable"; nullableString = nonNullableString;: 非nullableの nonNullableStringnullableString に代入しようとすると、Nullable Reference Typesのチェックによって警告が出たり、コンパイルエラーになる可能性があります。
  5. 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 は戻り値がないことを意味し、staticMain() メソッドが静的であることを示しています。このメソッドは、文字列を逆順にする拡張メソッド 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#のアップデートやトピック
バージョンごとのアップデートやトピック
C# 9.0 (2020年11月リリース)
  1. Records (レコード)
    • record キーワードを使用して、イミュータブルで値型のオブジェクトを定義できます。
    • パターンマッチングや分解などの便利な機能を提供します。
    • with式を使用したイミュータブルな変更が可能です。
  2. パターンマッチングの拡張
    • switch ステートメントや if 式にパターンマッチングを使用する際に、新しいパターンが追加されました。
    • より柔軟なパターンマッチングが可能になりました。
    • 関係パターン(<, >, <=, >=)のサポートが追加されました。
  3. Init アクセサー
    • イミュータブルなオブジェクトの初期化時に使用される init アクセサーが導入されました。
    • 設定は初期化時のみ可能で、その後は読み取り専用になります。
  4. Top-level statements(トップレベルステートメント)
    • プログラムのエントリーポイントを簡略化し、Main メソッドを省略できるようになりました。
    • 特に小規模なプログラムやスクリプトの記述が容易になりました。
  5. Target-typed new 式
    • 変数の型が文脈から明らかな場合、new 演算子で型を省略できるようになりました。
    • コードの冗長性を減らし、可読性を向上させます。
  6. Covariant return types(共変戻り値型)
    • オーバーライドしたメソッドでより派生した型を戻り値として指定できるようになりました。
  7. Static Anonymous Functions(静的匿名関数)
    • static キーワードを使用して、キャプチャを防ぐ匿名関数を定義できます。
C# 10.0 (2021年11月リリース)
  1. Global Usings (グローバル Using)
    • グローバルな using 宣言が可能になり、全てのファイルで共通のusingを指定できるようになりました。
    • global using キーワードを使用して宣言します。
  2. File-scoped Namespace Declarations (ファイルスコープのネームスペース宣言)
    • namespace 宣言をファイルスコープで行えるようになりました。
    • ファイル全体で共通のネームスペースを宣言できます。
    • インデントレベルを1つ減らすことができます。
  3. Record Structs
    • 値型のレコードを定義できるようになりました。
    • record struct キーワードを使用して宣言します。
  4. Improved Interpolated Strings(補間文字列の改善)
    • 文字列補間でのパフォーマンスが向上しました。
    • FormattableString の生成を最適化します。
    • Newline characters in string interpolation (文字列補間での改行文字のサポート)が追加されました。
  5. Constant interpolated strings(定数補間文字列)
    • 文字列補間を使用して定数を定義できるようになりました。
    • コンパイル時に評価される文字列補間が可能です。
  6. Extended property patterns(拡張プロパティパターン)
    • ネストされたプロパティに対するパターンマッチングが改善されました。
  7. Lambda式の改善
    • ラムダ式に属性を付けられるようになりました。
    • 自然な型推論が強化されました。
    • 戻り値の型を明示的に指定できるようになりました。
  8. Caller argument expressions(呼び出し元引数式)
    • CallerArgumentExpressionAttribute を使用して、メソッドに渡された引数の元の式を取得できます。
    • デバッグやログ出力で有用です。
C# 11.0 (2022年11月リリース)
  1. Raw string literals(生文字列リテラル)
    • 複数行の文字列を """ を使用して簡単に記述できるようになりました。
    • インデントや特殊文字のエスケープが不要になりました。
    • 文字列補間と組み合わせて使用可能です。
  2. Required members(必須メンバー)
    • required モディファイアを使用して、オブジェクト初期化時に必ず設定が必要なプロパティを指定できます。
    • コンパイル時の型安全性が向上します。
  3. Static abstract members in interfaces(インターフェースの静的抽象メンバー)
    • インターフェースで静的メンバーを定義できるようになりました。
    • ジェネリック型の制約として使用可能です。
  4. Generic attributes(ジェネリック属性)
    • 属性クラスでジェネリック型パラメータを使用できるようになりました。
  5. UTF-8文字列リテラル
    • u8 サフィックスを使用してUTF-8エンコードの文字列リテラルを作成できます。
  6. Pattern matching on spans
    • Span<T>ReadOnlySpan<T> に対するパターンマッチングが可能になりました。
  7. List patterns(リストパターン)
    • 配列やリストに対する新しいパターンマッチング構文が追加されました。
    • [1, 2, .., 10] のような形式でマッチングができます。
  8. File-local types
    • file アクセス修飾子を使用して、ファイル内でのみアクセス可能な型を定義できます。
  9. String interpolation improvements(文字列補間の改善)
    • 新しい改行とインデントの処理
    • より柔軟な式の使用が可能に
C# 12.0 (2023年11月リリース)
  1. Primary constructors(プライマリコンストラクタ)
    • クラスやstructの宣言で直接パラメータを指定できるようになりました。
    • より簡潔なコードが書けるようになりました。
      public class Person(string name, int age) {
          public string Name => name;
          public int Age => age;
      }
      
  2. Collection expressions(コレクション式)
    • 配列やリストの初期化をより簡潔に行えるようになりました。
    • [1, 2, 3] のような構文で様々なコレクション型を初期化できます。
    • スプレッド演算子 .. を使用して既存のコレクションを展開できます。
  3. Optional parameters in lambda expressions(ラムダ式のオプショナルパラメータ)
    • ラムダ式でオプショナルパラメータを使用できるようになりました。
    • デフォルト値を指定可能です。
  4. ref readonly parameters(参照読み取り専用パラメータ)
    • メソッドパラメータを参照渡しかつ読み取り専用として宣言できます。
    • パフォーマンスと安全性の両立が可能に。
  5. Alias any type(任意の型のエイリアス)
    • using ディレクティブで、より複雑な型に対してもエイリアスを定義できるようになりました。
      using MyHandler = System.Action<string, System.Collections.Generic.IList<int>>;
      
  6. Experimental attribute(実験的属性)
    • [Experimental] 属性を使用して、実験的なAPIをマークできます。
    • 使用時に警告を生成し、開発者に注意を促します。
  7. Interceptors(インターセプター)
    • メソッド呼び出しをインターセプトして、追加の処理を挿入できます。
    • ロギングやキャッシュなどの横断的関心事の実装に有用です。
  8. nameof accessing instance members(instanceメンバーへのnameofアクセス)
    • インスタンスメンバーに対して nameof 式を使用できるようになりました。

これらの新機能により、C#は:

  1. より簡潔で表現力豊かなコードが書けるように
  2. パフォーマンスの最適化がより容易に
  3. 型安全性がさらに向上
  4. クロスプラットフォーム開発がより便利になっています。
特にC# 12.0のプライマリコンストラクタとコレクション式は、日常的なコーディングを大幅に簡素化する重要な機能と言えます。

脚註

編集
  1. ^ 2012年12月時点で、DotGNUプロジェクトは廃止され、大規模な新しいボランティアの取り組みが生まれるまで再開される見込みはありません。ただし、例外としてlibjitコンポーネントは、現在は独立したlibjitパッケージとして存在しています。
  2. ^ $ - string interpolation (C# reference)
  3. ^ @