C Sharp

C#は、Microsoft社が開発した、汎用のマルチパラダイムプログラミング言語である。C#は、Javaに似た構文を持ち、C++に比べて扱いやすく、プログラムの記述量も少なくて済む。また、C#は、.NET Framework上で動作することを前提として開発された言語であり、WindowsアプリケーションやWebアプリケーションの開発に適している。

マルチパラダイムをサポートする汎用高レベルプログラミング言語で、静的型付け、タイプセーフ、スコープ、命令型、宣言型、関数型、汎用型、オブジェクト指向、コンポーネント指向のプログラミング分野を含んでいる。

共通言語基盤  といった周辺技術も含め、Microsoft社のフレームワークである「.NET Framework」の一部である。また、以前のVisual J++で「非互換なJava」をJavaに持ち込もうとしたMicrosoft社とは異なり、その多くの全てではなく一部にプロプライエタリなコンポーネントもある。そのため、それに依存するものなど、後述のMonoなどで制限がある場合がある ! ISO/IEC ! style="width:8em;" | マイクロソフト |- | 1.0 | rowspan="2"|[1] | rowspan="2"|[2] | [3] | 2002年1月 | | .NET  |- | | [4] | 2003年4月 | .NET   Framework   1.1 | .NET 2003 |- | 2.0 | [5] | [6] | [7] | | | 2005 |- | 3.0 | | | [8] | 2007年11月 | | 2008 |- | 4.0 | | | 2010年4月 | 2010年4月 | .NET   Framework   4 | 2010 |- | 5.0 | [9] | [10] | [11] | 2012年8月 | .NET   Framework   4.5 | |- | 6.0 | [12] | | [13] | 2015年7月 | | 2015 |- | 7.0 | | | | 2017年3月 | .NET   Framework   4.7 | 2017 version   15.0 |- | 7.1 | | | | 2017年8月 | .NET   Core   2.0 | 2017 version   15.3 |- | 7.2 | | | | 2017年11月 | .NET   Core   2.0 | 2017 version   15.5 |- | 7.3 | | | | 2018年5月 | | 2017 version   15.7 |- | 8.0 | | | | 2019年9月 | | 2019 version   16.3 |- |
9.0 | | | | 2020年11月 | .NET 5.0 | 2019 version   16.8 |- | 10.0 | | | [14] | 2021年12月 | | 2022 version   17.0 |- | 11.0 | | | [15] | 2022年11月 | .NET 7.0 | 2022 version   17.4 |}

1. 言語仕様
-------

さまざまな意味において、基盤であるCLIの機能をもっとも反映している言語であるといえる。C#にある組み込み型のほとんどは、CLIフレームワークに実装されている値型と対応している。しかし、C#の言語仕様はコンパイラのコード生成については何も言及していないため、CLRに対応しなければならないとか、共通中間言語  などの特定のフォーマットのコードを生成しなければならないとかいうことは述べられていない。そのため、理論的にはC++やFORTRANのように環境依存のマシン語を生成することも可能である。しかし、現在存在するすべてのC#コンパイラはCLIをターゲットにしている。

1.1. CやC++からの改良点
----------------

C#では、CやC++と比較してさまざまな制限や改良が加えられている。また、仕様の多くはC#言語というよりは、基盤である.NET Frameworkそのものに依拠している。Javaで導入された制限および改良をC#でも同様に採用しているものが多いが、C#で新たに導入された改良がのちにJavaにも同様に採用されたものもある。その例を次に挙げる。

1.1.1. 構文や構文以外の改良点
------------------

外のブロックで宣言した変数と同じ名前の変数を、内のブロックで再宣言してはいけない。再宣言は便利なこともあれば、混乱や曖昧のもとと主張されることもあるが、C#では禁止されている。
C#にはブール型boolが存在し、while文やif文のように条件をとるステートメントには、bool型の式を与えなければならない。C言語では、ブール型が無くint型に兼用させた上、ポインタでもwhile文やif文に与える式にできる、という仕様としていた。これは便利なこともあったが、本来比較式を記述すべきところで誤って代入式を記述してもコンパイル適合となってしまうなど、ミスが見逃されることもあった。C#ではdate=2017年11月に、そのような仕様ではなくブール型を独立させ、またブール型を厳密に要求する場所を多くしている。
switch文に整数型あるいは整数型に準ずる型のみならず、文字列型stringを使用できる。caseラベルには、整数型あるいは整数型に準ずる型の定数のみならず、文字列リテラルを使用できる。
組み込み型のサイズおよび内部表現が仕様で定められており、プラットフォームや処理系に依存しない。浮動小数点数はIEEE 754に準拠する。文字および文字列はUTF-16エンコーディングを採用する。

1.1.2. ポインタとメモリ管理
-----------------

ポインタをサポートする。ポインタはunsafeスコープ内のみで使用することができ、適切な権限をもつプログラムのみがunsafeとマークされたコードを実行することができる。オブジェクトへのアクセスの大部分は管理された安全な参照によってなされ、大部分の算術演算はオーバフローのチェックがなされる。unsafeポインタは値型や文字列を指すことができる。セーフコードでは、必ずしもそうする必要はないものの、IntPtr型を通してポインタをやりとりすることができる。
マネージドなメモリを明示的に解放する方法は存在せず、参照されなくなったメモリはガベージコレクタによって自動的に解放される。ガベージコレクタは、メモリの解放忘れによって起こるメモリリークを解消する。C#は、データベース接続のようなアンマネージドなリソースに対しても明示的に制御する方法を提供している。これはIDisposableインタフェースとusingステートメントによってなされる。

1.1.3. 名前空間とオブジェクト指向な型システム
--------------------------

グローバル変数やグローバルメソッドは存在しない。すべてのフィールドとメソッドはクラスあるいは構造体の一部として宣言されなければならない。 例えばC/C++のprintf関数のように名前空間レベルに存在するフリー関数を定義することはできない。ほとんどの場合クラスおよび構造体は名前の衝突を避けるために名前空間に所属する。
名前空間は階層構造をもつ。つまり、名前空間は他の名前空間の中に宣言することができる。
組み込みの値型を含めたすべての型は、objectクラス  の派生型である。つまりobjectクラスのもつすべてのプロパティやメソッドを継承する。例えば、すべての型はToStringメソッドをもつ。
クラス  は参照型であり、構造体  および列挙型  は値型である。構造体はクラスよりも軽量で、C/C++との相互運用性に優れるが、派生型を定義することができない。
クラスおよび構造体は複数のインタフェースを実装することができるが、多重継承はサポートされない。
C#はC++に比べて型安全である。既定の暗黙変換は、整数の範囲を広げる変換や、派生クラスから基底クラスへの変換といった、安全な変換のみに限定される。これは、コンパイル時、JITコンパイル時、そして一部の動的なケースでは実行時に強制される。ブール型と整数型、列挙型と整数型、の間は暗黙変換はできない。暗黙変換をユーザー定義する際は、明示的にそのように指定しなければならない。これはC++のコンストラクタとは違った仕様である。
列挙型のメンバーは、列挙型のスコープの中に置かれる。また、列挙型の定数名を取得することができる。さらに、列挙型の定数名から動的に定数値を得ることができる。
アクセサの定義と利用を簡略化するためにプロパティ構文を利用できる。C++およびJavaにおけるカプセル化では、通例getter/setterアクセサとなるメンバー関数あるいはメソッドを定義して利用するが、C#ではプロパティ機能により、カプセル化を維持しつつ、あたかもフィールドを直接読み書きするような直感的な構文でオブジェクトの状態にアクセスすることができる。プロパティによってメンバーのアクセス制御やデータの正当性チェックを実行することができる。なお、イベントハンドラーに利用するデリゲートのカプセル化にはイベント構文  が用意されている。

1.2. C# 2.0からの仕様
----------------

1.2.1. 部分型
----------

部分型  が導入された。以下のようにクラスや構造体の宣言にpartial修飾子をつけることで、その宣言を分割することができる。 partial class MyClass { int a; } partial class MyClass { int b; } これは以下と同義である: class MyClass { int a; int b; } これによって、巨大なクラスを分割したり、自動生成されたコードを分離したりすることができる。partial 修飾子はすべての宣言につける必要がある。

1.2.2. ジェネリクス
-------------

ジェネリクスが導入されたwhats-new-csharp-version-history。これは.NET Framework 2.0の機能である。クラス、構造体、インタフェース、デリゲート、メソッドに対して適用することができる。.NETのGenericsはC++のテンプレート、あるいはJavaにおけるそれとも異なるもので、コンパイルによってではなく実行時にランタイムによって特殊化される。これによって異なる言語間の運用を可能にし、リフレクションによって型パラメーターに関する情報を取得することができる。また、where節によって型パラメーターに制約を与えることができる。一方、C++のように型パラメーターとして式を指定することはできない。なお、ジェネリックメソッドの呼び出し時に引数によって型パラメーターが推論できる場合、型パラメーターの指定は省略できる。

1.2.3. 静的クラス
------------

静的クラスが導入されたwhats-new-csharp-version-history。static属性をクラスの宣言につけることで、クラスはインスタンス化できなくなり、静的なメンバーしか持つことができなくなる。

1.2.4. イテレータ
------------

イテレータ#C# 2.0を参照。

1.2.4.1. yieldキーワード
-------------------

yieldキーワードによるコルーチンを使うことで、イテレータの生成を楽に実装できるようになった。

1.2.5. 匿名デリゲート
--------------

クロージャの機能を提供する匿名デリゲートが導入された。

1.2.6. プロパティに対する個別のアクセス制御
-------------------------

プロパティのget もしくは setアクセサのどちらかにアクセス修飾子を指定することでアクセス制御が別個にできるようになったwhats-new-csharp-version-history。次の例では、getアクセサはpublic、setアクセサはprivateである。 public class MyClass { private string status = string.Empty; public string Status { get { return status; } private set { status = value; } } }

1.2.7. Null許容型とnull結合演算子
------------------------

nullを保持できる値型、Nullableが導入されたwhats-new-csharp-version-history。 int? i = 512; i = null;

int? j = i + 500; //jはnullとなる。nullとの演算の結果はnullになる。<WtXmlEndTag />int?はNullableの糖衣構文である。また、nullを保持しているNull許容型のインスタンスをボックス化しようとすると、単に空参照  に変換される。 int? x = null; object o = x; System.Console.WriteLine; //Trueが出力される

また、null結合演算子 が導入された。これは、nullでない最初の値を返す。 object obj1 = null; object obj2 = new object; object obj3 = new object; return obj1 ?? obj2 ?? obj3; // obj2 を返す この演算子は主にNullable型を非Nullable型に代入するときに使われる。 int? i = null; int j = i ?? -1; // nullをint型に代入することはできない

1.2.8. その他
----------

匿名メソッド
External Aliases/Namespace Aliases Qualifiers
プラグマディレクティブ/C言語の様な固定長の配列表記en

1.3. C# 3.0からの仕様
----------------

1.3.1. varキーワード
---------------

var キーワードが導入され、型推論を利用したローカル変数の宣言ができるようになったwhats-new-csharp-version-history。 var s = "foo"; // 上の文は右辺が string 型であるため、次のように解釈される: string s = "foo"; // 以下に挙げる文は誤りである: var v; // 初期化式を欠いている  var v = null; // 型が推論できない 

1.3.2. 拡張メソッド
-------------

拡張メソッド  が導入されたwhats-new-csharp-version-history。既存のクラスを継承して新たなクラスを定義することなく、新たなインスタンスメソッドを疑似的に追加定義することができる。具体的には、入れ子になっていない、非ジェネリックの静的クラス内に、this 修飾子をつけた、拡張メソッドを追加する対象の型の引数を最初に持つメソッドをまず定義する。これによって、通常の静的メソッドとしての呼び出しの他に、指定した型のインスタンスメソッドとしての呼び出しを行うことができるメソッドを作ることができる。以下に例を挙げる: public static class StringUtil { public static string Repeat { var array = new string[count]; for  array[i] = str; return string.Concat; } } この例は、文字列を指定した回数繰り返し連結したものを返すメソッド Repeat を、既存の string 型に追加している。このメソッドは、以下のように呼び出すことができる: // 静的メソッドとしての呼び出し StringUtil.Repeat; // 拡張メソッドとしての呼び出し "foo".Repeat; //  また、列挙型やインタフェースなど本来メソッドの実装を持ち得ない型に、見かけ上インスタンスメソッドを追加することも可能である。以下に例を挙げる: public enum Way { None, Left, Right, Up, Down }

public static class EnumUtil { public static Way Reverse { switch  { case Way.Left: return Way.Right; case Way.Right: return Way.Left; case Way.Up: return Way.Down; case Way.Down: return Way.Up; default: return Way.None; } } }<WtXmlEndTag /> このメソッドは以下のように呼び出すことができる: Way l = Way.Left; Way r = l.Reverse; // Way.Right

拡張メソッドは糖衣構文の一種であり、カプセル化の原則に違反するものではないが、必要な場合に限り注意して実装することがガイドラインとして推奨されている。

1.3.3. 部分メソッド
-------------

部分メソッドが導入されたwhats-new-csharp-version-history。部分型内で定義された private で、かつ戻り値が void のメソッドに partial 修飾子をつけることでメソッドの宣言と定義を分離させることができる。定義されていない部分メソッドは何も行わず、何らエラーを発生させることもない。例えば: partial class Class { partial void DebugOutput;

void Method { DebugOutput; Console.WriteLine; } }<WtXmlEndTag /> 上のコードにおいて Method を呼び出すと、Did something. と表示されるだけだが、ここで以下のコード: partial class Class { partial void DebugOutput { Console.Write; } } を追加した上で Method を呼び出すと、[DEBUG: Some message] Did something. と表示される。

1.3.4. ラムダ式
-----------

ラムダ式が導入されたwhats-new-csharp-version-history。この名前はラムダ計算に由来する。

以下の匿名メソッド // iを変数としてi+1を返すメソッド delegate  { return i + 1; } は、ラムダ式を使って次のように記述できる:  => i + 1; /* 式形式のラムダ */ //或いは:  => { return i + 1; }; /* ステートメント形式のラムダ */ ラムダ式は匿名メソッドと同様に扱えるが、式形式のラムダがExpression型として扱われた場合のみ匿名メソッドとして扱われず、コンパイラによって式木を構築するコードに変換される。匿名デリゲートが実行前にコンパイルされたCILを保持するのに対し、式木はCILに実行時コンパイル可能であるDOMのような式の木構造そのものを保持する。これはLINQクエリをSQLクエリなどに変換する際に役立つ。

以下は、3つの任意の名前の変数、整数、括弧、及び四則演算子のみで構成された式を逆ポーランド記法に変換する汎用的なコードである: public static string ToRPN { return Parse expression.Body).TrimEnd; }

private static string Parse { string str = "";

if  { str += Parse expr.Left); } else if  { str +=  expr.Left).Name + " "; } else if  { str +=  expr.Left).Value + " "; }

if  { str += Parse expr.Right); } else if  { str +=  expr.Right).Name + " "; } else if  { str +=  expr.Right).Value + " "; }

return str + expr.NodeType.ToString .Replace .Replace .Replace .Replace + " "; }

// 呼び出し例: ToRPN =>  *  / z)); // "x 1 + y 2 - z / *" を返す<WtXmlEndTag />

1.3.5. オブジェクト初期化の簡略化
--------------------

オブジェクトの初期化が式として簡潔に記述できるようになった。 var p = new Point { X = 640, Y = 480 }; // 上の文は次のように解釈される: Point __p = new Point; __p.X = 640; __p.Y = 480; Point p = __p; また、コレクションの初期化も同様に簡潔に記述できるようになった。 var l = new List {1, 2, 3}; var d = new Dictionary<string, int> ; // 上の文は次のように解釈される: List __l = new List; __l.Add; __l.Add; __l.Add; List l = __l; Dictionary<string, int> __d = new Dictionary<string, int>; __d.Add; __d.Add; __d.Add; Dictionary<string, int> d = __d; 但し、上のコードでは匿名の変数に便宜的に __p、__l、__d と命名している。実際はプログラマはこの変数にアクセスすることはできない。

1.3.6. 自動実装プロパティ
----------------

プロパティをより簡潔に記述するための自動実装プロパティが導入されたwhats-new-csharp-version-history。プロパティの定義に get; set; と記述することで、プロパティの値を保持するための匿名のフィールドと、そのフィールドにアクセスするためのアクセサが暗黙に定義される。また、C# 5.0 までは get;とset;のどちらか片方だけを記述することは出来なかったが、C# 6.0 からは get; のみが可能。以下のコード: public int Value { get; set; } は、以下のようなコードに相当する動作をする: private int __value; public int Value { get { return __value; } set { __value = value; } } 但し、上のコードでは匿名のフィールドに便宜的に __value と命名している。実際はプログラマはこのフィールドにアクセスすることはできない。

1.3.7. 匿名型
----------

一時的に使用される型を簡単に定義するための匿名型が導入されたwhats-new-csharp-version-history。以下に例を挙げる: new { Name = "John Doe", Age = 20 } 上の式は、以下の内容のクラスを暗黙に定義する。定義されたクラスは匿名であるが故にプログラマは参照できない。 public string Name { get; } public int Age { get; } 同じ型、同じ名前のプロパティを同じ順序で並べた匿名型は同じであることが保証されている。即ち、以下のコード: var her = new { Name = "Jane Doe", Age = 20 } var him = new { Name = "John Doe", Age = 20 } において、her.GetType == him.GetType は true である。

1.3.8. 配列宣言の型省略
---------------

new キーワードを用いた配列の宣言の際、型を省略できるようになった。匿名型の配列を宣言する際に威力を発揮する。 var a = new[] {"foo", "bar", null}; // 上の文は次のように解釈される: string[] a = new string[] {"foo", "bar", null}; // 以下の文: var a = new[] {"foo", "bar", 123}; // は次のように解釈されることなく、誤りとなる: object[] a = new object[] {"foo", "bar", 123};

1.3.9. クエリ式
-----------

LINQ をサポートするために、クエリ式が導入されたwhats-new-csharp-version-history。これは SQL の構文に類似しており、最終的に通常のメソッド呼び出しに変換されるものである。以下に例を示す: var passedStudents = from s in students where s.MathScore + s.MusicScore + s.EnglishScore > 200 select s.Name; 上のコードは以下のように変換される: var passedStudents = students .Where .Select; C# 3.0で追加された構文の多くは式であるため、より巨大な式の一部として組み込むことができる。旧来複数の文に分けたり、作業用の変数を用意して記述していたコードを単独の式としてより簡潔に記述できる可能性がある。

出井秀行著の『実戦で役立つ C#プログラミングのイディオム/定石&パターン』という書籍ではクエリ構文よりメソッド構文を推奨しており、クエリ構文ではLINQの全ての機能を使用できるわけではないこと、メソッド呼び出しは処理を連続して読める可読性があること、メソッド呼び出しであればMicrosoft Visual Studioの強力なインテリセンスが利用できることを理由に、著者はクエリ構文をほとんど使用していないと記している。

1.4. C# 4.0からの仕様
----------------

1.4.1. dynamicキーワード
-------------------

dynamicキーワードが導入され、動的型付け変数を定義できるようになったwhats-new-csharp-version-history。dynamic型として宣言されたオブジェクトに対する操作のバインドは実行時まで遅延される。 // xはint型と推論される: var x = 1; // yはdynamic型として扱われる: dynamic y = 2;

public dynamic GetValue { // objにValueが定義されていなくとも、コンパイルエラーとはならない: return obj.Value; }<WtXmlEndTag />

1.4.2. オプション引数・名前付き引数
---------------------

VBやC++に実装されているオプション引数・名前付き引数が、C#でも利用できるようになったwhats-new-csharp-version-history。 public void MethodA { // 第1引数と第2引数を指定、第3引数は未指定: Console.WriteLine); // Ans: 3 … 1 + 2 + 0となっている

// 第1引数と第3引数を指定、第2引数は未指定: Console.WriteLine); // Ans: 4 … 1 + 0 + 3となっている }

// 引数が指定されなかった場合のデフォルト値を等号で結ぶ: public int MethodB { return A + B + C; }<WtXmlEndTag />

1.4.3. ジェネリクスの共変性・反変性
---------------------

ジェネリクスの型引数に対してin、out修飾子を指定することにより、ジェネリクスの共変性・反変性を指定できるようになったwhats-new-csharp-version-history。 IEnumerable x = new List { "a", "b", "c" }; // IEnumerableインターフェイスは型引数にout修飾子が指定されているため、共変である。 // したがって、C# 4.0では次の行はコンパイルエラーにならない IEnumerable y = x;

1.5. C# 5.0からの仕様
----------------

非同期処理 
呼び出し元情報属性
foreach の仕様変更

1.6. C# 6.0からの仕様
----------------

自動実装プロパティの初期化子
get のみの自動実装プロパティおよびコンストラクタ代入
静的 using ディレクティブ
インデックス初期化子
catch/finally での await
例外フィルタ
式形式のメンバー 
null条件演算子
文字列補間
nameof 演算子
#pragma
コレクションの初期化子での拡張メソッド
オーバーロード解決の改善

1.6.1. 静的 using ディレクティブ
-----------------------

静的 using ディレクティブを利用することで、型名の指定無しに他クラスの静的メンバーの呼び出しを行えるようになった。利用するにはusing staticの後に完全修飾なクラス名を指定する。

using static System.Math; // ↑ソースコードの上部で宣言 class Hogehoge { // System.Math.Pow , System.Math.PI を修飾無しで呼び出す double area = Pow * PI; }

1.6.2. 例外フィルタ
-------------

catchの後にwhenキーワードを使用することで、処理する例外を限定することができるようになった。

try { // ... } catch  when  { // ... }

1.7. C# 7.0からの仕様
----------------

出力変数宣言
パターンマッチング 
タプル 
ローカル関数
数値リテラルの改善
ref戻り値、ref変数
非同期戻り値型の汎用化
Expression-bodied 機能の拡充
Throw 式

1.7.1. 出力変数宣言
-------------

out引数で値を受け取る場合、その場所で変数宣言可能となった。

total += int.TryParse ? num : 0;

1.7.2. パターンマッチング
----------------

1.7.2.1. is 式の拡張
----------------

is式の構文が拡張され、型の後ろに変数名を宣言できるようになったwhats-new-70。 拡張されたis式はマッチした場合に宣言した変数にキャストした値を代入し、さらにtrueと評価される。 マッチしなかった場合はfalseと評価され、宣言した変数は未初期化状態となる。

void CheckAndSquare { // objの型チェックと同時にnumに値を代入する。 if  { num = num * num; } else { num = 0; } // if文の条件セクションは、ifの外側と同じスコープ Console.WriteLine; }

1.7.2.2. switch 文の拡張
--------------------

switch文のマッチ方法が拡張され、caseラベルに従来の「定数パターン」に加え、新たに「型パターン」を指定できるようになった。 また、「型パターン」のcaseラベルでは、when句に条件を指定することができる。 「型パターン」を含むswitch文では、必ずしも条件が排他的でなくなったため、最初にマッチしたcaseラベルの処理が実行される。

void Decide { switch  { case int num when num < 0: Console.WriteLine; break; case int num: Console.WriteLine; break; case "B": Console.WriteLine; break; case string str when str.StartsWith: Console.WriteLine; break; case string str: Console.WriteLine; break; case null: Console.WriteLine; break; default: Console.WriteLine; break; } }

1.7.3. タプル
----------

タプルのための軽量な構文が導入されたwhats-new-70。従来のSystem.Tupleクラスとは別に、System.ValueTuple構造体が新しく追加された。

1.7.3.1. タプル記法
--------------

2個以上の要素を持つタプルのための記法が導入された。 引数リストと同様の形式で、タプルを記述できる。

// タプル記法  tuple = ; Console.WriteLine;

1.7.3.2. 分解
-----------

多値戻り値を簡単に扱えるように、分解がサポートされたwhats-new-70。

var tuple = ; // 分解  = tuple; Console.WriteLine;

分解はタプルに限らない。Deconstructメソッドが定義されたクラスでも、分解を利用できるwhats-new-70。

以下に、DateTime型に分解を導入する例を示す。

static class DateExt { public static void Deconstruct { year = dateTime.Year; month = dateTime.Month; day = dateTime.Day; } } 上記のコードでDateTime型にDeconstruct拡張メソッドを定義し、 // 分解  = DateTime.Now; のように左辺で3つの変数に値を受け取ることができる。

1.7.4. 値の破棄
-----------

分解、out引数、パターンマッチングで、値の破棄を明示するために_が利用できるようになった。 破棄された値は、後で参照することはできない。

// 年と日は使わない  = DateTime.Now;

// 解析結果だけ取得し、変換された値は使わない bool isNumeric = int.TryParse;

switch  { // string型で分岐するが、値は使わない case string _: // Do something. break; }<WtXmlEndTag />

1.7.5. ref戻り値、ref変数
-------------------

refキーワードの使用方法が拡張された。これによって、安全な参照の使い道が広がった。

1.7.5.1. ref戻り値
---------------

戻り値の型をrefで修飾することで、オブジェクトの参照を戻り値とすることができる。

// 二つの参照引数の内、値の大きいものの参照戻り値を返す static ref int Max { if  { return ref left; } else { return ref right; } }

変数の寿命は変わらないため、メソッド終了時に破棄されるローカル変数をref戻り値とすることはできない。

static int s_count = 1;

// メンバーの参照はref戻り値になる。 static ref int ReturnMember { return ref s_count; } // ref引数はもちろんref戻り値になる。 static ref int ReturnRefParam { return ref something; } // ローカル変数をref戻り値とすることはできない。 // static ref int ReturnLocal { // int x = 1; // return ref x; // }<WtXmlEndTag />

1.7.5.2. ref変数
--------------

ローカル変数の型をrefで修飾することで、参照を代入することができる。

// 参照戻り値を参照変数で受け取る ref int max = ref Max; // limitとmaxは同じ値を参照する ref int limit = ref max;

1.8. C# 7.1からの仕様
----------------

1.8.1. 非同期なMainメソッド
-------------------

Mainメソッドの戻り値として、Task型、Task型が認められた。 static Task Main static Task Main

1.8.2. default式
---------------

型推論可能な場面では、defaultの型指定は省略可能となったwhats-new-71。 int number = default; string name = default;

1.9. C# 7.2からの仕様
----------------

C#7.2で追加された仕様は以下の通り。

1.9.1. 値型の参照セマンティクス
-------------------

値型におけるパフォーマンス向上を意図した複数の機能が追加された。

1.9.1.1. in参照渡し、ref readonly参照戻り値
---------------------------------

引数にinを指定することで、読み取り専用参照渡しを指定できる。 また、戻り値にref readonlyを指定することで、読み取り専用参照戻り値を指定できる。

これにより、構造体のコピーを避けると共に、意図しない値の変更を抑止できる。

1.9.1.2. readonly構造体
--------------------

構造体宣言時にreadonlyを指定することで、真の読み取り専用構造体を定義できる。 readonly構造体の全てのフィールドはreadonlyでなければならず、thisポインタも読み取り専用となる。

これにより、メンバーアクセス時の意図しない防御的コピーを抑止できる。

1.9.1.3. ref構造体
---------------

構造体宣言時にrefを指定することで、ヒープ領域へのコピーを防ぐ構造体がサポートされる。 ref構造体では、box化できない、配列を作成できない、型引数になることができない、など、ヒープ領域へのコピーを防ぐための厳しい制限がかかる。

この機能は、Spanのような構造体をサポートするために利用され、unsafe文脈以外でのstackallocの利用をも可能とする。

1.9.2. 末尾以外の場所での名前付き引数
----------------------

C#4.0で追加された名前付き引数が末尾以外でも利用できるようになった。

Hogehoge;

1.9.3. private protected アクセス修飾子
--------------------------------

同一アセンブリ内、かつ、継承先からのアクセス許可を表すprivate protectedアクセス修飾子が追加された。

1.9.4. 数値リテラルの改善
----------------

十六進リテラルの0x、二進リテラルの0bの直後のアンダースコアが認められた。

int bin = 0b_01_01; int hex = 0x_AB_CD;

1.10. C# 7.3からの仕様
-----------------

C#7.3では以下の仕様が追加された。

ジェネリック型制約の種類の追加
System.Enum, System.Delegate
unmanaged  unsafe class MyGenericsClass<T1,T2,T3> where T1 : System.Enum where T2 : System.Delegate where T3 : unmanaged {

public MyGenericsClass { if ) { func.DynamicInvoke; } else { T3* ptr = &unmanagedValue; } } }<WtXmlEndTag />

refローカル変数の再割り当て
stackalloc初期化子
Indexing movable fixed buffers
カスタムfixedステートメント
オーバーロード解決ルールの改善
出力変数宣言の利用箇所の追加 class MyOutVar { // メンバー変数初期化子やコンストラクタ初期化子で出力変数宣言が可能 readonly int x = int.TryParse ? number : -1; }

タプル同士の比較  tuple = ; // タプルのすべての要素間で == が比較可能 if ) { } // 要素数が異なるタプル同士は比較できない。 //if ) { }

バッキングフィールドに対するAttribute指定 // C#7.2までは無効な指定 // C#7.3からはバッキングフィールドに対するAttribute指定と見なされる [field: NonSerialized] public int MyProperty { get; set; }

1.11. C# 8.0からの仕様
-----------------

C# 8.0で追加された仕様は以下の通り。

1.11.1. null許容参照型
-----------------

参照型にnull許容性を指定できるようになった。参照型の型名に?を付加した場合にnull許容参照型となる。

参照型の型名に?を付加しない場合、null非許容参照型となる。

フロー解析レベルでのnull許容性チェックが行われる。null許容値型のNullableのような新しい型は導入されない。

1.11.1.1. null許容コンテキスト
----------------------

参照型のnull許容性は、null許容コンテキストによって有効、無効の切り替えが可能である。 C#7.3以前の互換性のために、既定では無効となっている。

Nullable コンパイルオプション： プロジェクト全体でのnull許容コンテキストを指定する
#nullable ディレクティブ： ソースコードの部分ごとにnull許容コンテキストを指定する
annotations オプション、warningsオプションにより、適用範囲を限定できる

1.11.1.2. null免除演算子
-------------------

null許容参照型の変数名の後に !を使用することで、フロー解析時の警告が免除される。

1.11.2. インタフェースの既定メンバー
----------------------

インタフェースのメンバーに既定の実装を指定できるようになった。また、インタフェースに静的メンバーを持つことができるようになった。

さらに、インタフェースのメンバーにアクセシビリティを指定できるようになった。

既定のアクセシビリティは、従来通り public となる。
実装があるインスタンスメンバーは、既定で virtual となり override可能である。
実装をoverrideさせないためにsealedを指定することができる。

1.11.3. パターンマッチングの拡張
--------------------

switch式が追加された。 プロパティパターン、タプルパターン、位置指定パターンの追加により、再帰的なパターンマッチングが可能になった。

switch式
再帰パターン
プロパティパターン
タプルパターン
位置指定パターン

1.11.4. 非同期ストリーム
----------------

IAsyncEnumerableインタフェースを返すことで、イテレータ構文と非同期構文の共存が可能になった。

async IAsyncEnumerable EnumerateAsync { await Task.Delay; yield return 1; await Task.Delay; yield return 2; }

await foreachによって非同期ストリームを列挙する。

async void SpendAsync { await foreach ) { Console.WriteLine; } }

1.11.5. 範囲指定
------------

IndexとRangeを指定できる専用構文が追加された。

Index a = 1; // new Index Index b = ^1; // new Index Range range = a..b; // new Range

1.11.6. その他の仕様
--------------

静的ローカル関数
null結合代入演算子
構造体の読み取り専用メンバー
using 宣言
ref構造体のDispose
ジェネリクスを含むアンマネージ型
式中のstackalloc
文字列補間のトークン順序の緩和

1.12. C# 9.0からの仕様
-----------------

C# 9.0で追加された仕様は以下の通り。

レコード
プロパティのinitアクセサ
最上位レベルステートメント
パターンマッチングの拡張
new式の型推論
条件演算子の型推論
共変戻り値
GetEnumeratorの拡張メソッド対応
静的匿名関数
ラムダ式引数の破棄
ローカル関数への属性適用
パフォーマンスと相互運用
ネイティブサイズの整数型
関数ポインタ
変数初期化フラグの抑制
コードジェネレータのサポート
モジュール初期化子
部分メソッドの拡張

1.13. C# 10.0からの仕様
------------------

C# 10.0で追加された仕様は以下の通り。

レコード構造体
構造体型の機能強化
補間された文字列ハンドラー
global using ディレクティブ
ファイル スコープの名前空間の宣言
拡張プロパティのパターン
ラムダ式の機能強化
const 補間文字列を許可する
レコードの型で ToString を封印できる
限定代入の機能強化
同じ分解で代入と宣言の両方を許可する
メソッドで AsyncMethodBuilder 属性を許可する
CallerArgumentExpression 属性
拡張 #line pragma
警告ウェーブ 6

1.14. C# 11.0からの仕様
------------------

C# 11.0で追加された仕様は以下の通り。cs11_mslearn

1.14.1. 生文字列リテラル
----------------

エスケープなどの加工を施さない文字列を3個の二重引用符で括って表現できる様になった。 string logMsg = """ 原因不明のエラーが発生しました。 詳細はログファイル "C:\Logs\exception.log" を確認してください。 """;

1.14.2. 汎用属性
------------

属性の型が型引数を持てる様になった。 // 属性 [AttributeUsage] public class ConverterContractAttribute<TFrom, TTo> : Attribute { }

// 使用例 [ConverterContract<byte, string>] [ConverterContract<sbyte, string>] [ConverterContract<short, string>] [ConverterContract<ushort, string>] [ConverterContract<int, string>] [ConverterContract<uint, string>] [ConverterContract<long, string>] [ConverterContract<ulong, string>] public class IntToStringConverter { // ... }<WtXmlEndTag />

1.14.3. パターンマッチングの拡張
--------------------

リストや配列に対するパターンマッチが可能になった。 int[] nums = new[] { 0, 1, 2, 3, 4, 5 }; if  { Console.WriteLine; } else { Console.WriteLine; } また、SpanやReadOnlySpanに対するパターンマッチが可能になった。 bool CheckSignature { return sig is "HOGE"; }

1.14.4. ジェネリック型数値演算
-------------------

1.14.5. その他の仕様
--------------

UTF-8 文字列リテラル
文字列補間式の改行
ファイルローカル型
必須メンバー
auto-default 構造体
nameof のスコープ拡張
IntPtr に別名 nint、UIntPtr に別名 nuint が付いた
ref フィールド
scoped ref 変数
メソッドグループからデリゲートへの変換の改善
警告ウェーブ 7

2. 実装
-----

C#の言語仕様は標準化団体Ecma Internationalを通じて公開・標準化されており、第三者がマイクロソフトとは無関係にコンパイラや実行環境を実装することができるInfoQ-Microsoft-Community-Promise}}。 現段階で、C#コンパイラの実装は次の5つが知られている。

マイクロソフト製
Visual Studio 2015 以降で使用されている、.NETコンパイラプラットフォーム 。ApacheライセンスのオープンソースプロジェクトでGitHubで公開されている。Windows、macOS、Linuxで動作する。C#のコンパイラはC#、VB.NETのコンパイラはVB.NETで実装されている。以前のコンパイラと比べて、リファクタリングやIDE、スクリプティングなどへの利用が可能なAPIが公開されており、コンパイラ以外への様々な応用が可能。
Visual Studio 2013 まで使われていた、マイクロソフトによるVisual C# コンパイラ。
2006年のC# 2.0当時の、マイクロソフトによる[16]。共通言語基盤  とC#コンパイラがソースコードで公開されている。
[17]によるMono内の Mono Compiler Suite 。
2012年まで開発されていた、[18]によるPortable.NET内の the C-Sharp code compiler 。

3. 名称
-----

ECMA-334 3rd/4th/5th edition によると、C# は「C Sharp」と発音し、LATIN CAPITAL LETTER C  の後に NUMBER SIGN #  と書く。 音楽のシャープ ) ではなくナンバーサイン  を採用したのは、フォントやブラウザなどの技術的な制約に加え、ASCIIコードおよび標準的キーボードには前者の記号が存在しないためである。
"#"接尾辞は、他の.NET言語にも使用されており、J#、A#、F#が含まれる。また"#"接尾辞はGtk#、Cocoa#などのライブラリにも使用されている。そのほか、SharpDevelopなどの"Sharp"を冠する関連ソフトウェアも存在する。
C#という名称の解釈として、「直前の音を半音上げる」という音楽記号の役割に着目し、「C言語を改良したもの」を意味したのではないか、date=2018年11月。これは、C++の名称が「C言語を1つ進めたもの」という意味でつけられたことにも似ている。
アンダース・ヘルスバーグは、「C#」が「C++++」にみえるのが由来である、と語っている。

4. 注釈
-----

5. 出典
-----

5.1. 公式発表
---------

5.2. 個人サイト
----------

6. 参考文献
-------

7. 関連項目
-------

言語仕様
C#のデータ型
キーワード 
実行環境
.NET Framework
.NET Core
Mono
Xamarin
開発環境
Visual C#
Visual Studio
SharpDevelop - フリーの統合開発環境
比較
C#とJavaの比較

8. 外部リンク
--------

[19] - 公式ウェブサイト
言語仕様
[20] - C# 言語仕様、Microsoft Docs
[21] ECMA-334 C# 言語仕様
[22] Mono C# コンパイラ