新しいエスケープシーケンス\e(New escape sequence)
C# 13では、エスケープ文字(\x1b)自身を表すエスケープシーケンス\eの利用が可能になりました。
従来は、エスケープ文字自身を文字列に埋め込む際には、\u001b(Unicode表記)あるいは\x1b(ASCII文字の16進数表記)を用いてきました。しかしながら、これらの表記には、「1b」のあとに有効な16進数が続いてしまう場合に、それも含めてエスケープシーケンスとなってしまうという問題がありました。
Console.WriteLine("\x1bNone"); // 0x1b + "None" Console.WriteLine("\x1bfa"); // 0x1bfa
エスケープシーケンスを多用すると思われるコンソール制御においては、「Esc [」が基本となるのであまり問題となることはありませんが、上記のような曖昧さを解消するためにエスケープ文字自身を表すエスケープシーケンス\eがC# 13で導入されました。
Console.WriteLine("\eNone"); // 0x1b + "None" Console.WriteLine("\efa"); // 0x1b + "fa"
\eを用いると、曖昧さの解消の他に、エスケープシーケンスが多用される場合に記述量を減らし、見た目もすっきりとさせることができます。例えばコンソール制御では、エスケープシーケンスを多用するので効果的です。以下は、コンソール制御のエスケープシーケンスのうち、文字色を0~255のカラーコードで指定して切り替えるものを使って、16進数の表を色付けして出力するものです。
for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { int hex = i * 16 + j; Console.Write($"\e[38;5;{hex}m{hex:X2}\e[m "); } Console.WriteLine(); }
[NOTE]コンソール制御のエスケープシーケンス
コンソール制御のエスケープシーケンスを使うと、ターミナルなどコンソールに表示されているテキスト、およびこれから表示されるテキストについて、カーソル移動や表示のクリア、スクロール、色や装飾などを指示することができます。コンソール制御のエスケープシーケンスの基本形式は以下のようになります。
Esc [<パラメーター><機能文字>
<パラメーター>は<機能文字>に応じて指定します。<機能文字>には、A~H(カーソル移動)、J~K(表示のクリア)、S~T(スクロール)、m(色や装飾の変更)などがあります。上記のサンプルで指定した「\e[38;5;{hex}m」は、文字色を0~255の数値で切り替えるエスケープシーケンスで、「\e[m」は文字色や装飾をリセットするエスケープシーケンスです。
メソッドグループの自然型(Method group natural type)
C# 13では、メソッドグループからデリゲートの自然型を決定するときに、インスタンスメソッドを優先的に見つけるようになりました。
デリゲートの自然型とは、C# 10で導入された、デリゲートにおける型決定ルールに基づいて決められたデリゲート型です。デリゲート型をvarなどで受ける場合に、自然型が以下のルールに基づき決定されます。
- 引数の型や個数から可能であれば、Action型、Action<T>型、Func<T>型などを使う
- 上記以外の場合、コンパイラが自動生成する内部的なデリゲート型を使う
例えば、以下のコードでは、右辺のラムダ式の引数と戻り値から、(1)がAction<int>型、(2)がFunc<int, int>型に推論されます。
var action_i = (int i) => { i++; Console.WriteLine("{0}", i);}; (1) action_i(1); // 2 var func_i_i = (int i) => { i++; return i;}; (2) Console.WriteLine("{0}", func_i_i(2)); // 3
Action型は戻り値のないデリゲート型で、引数の型を型パラメーターに指定するジェネリック型です(引数がない場合にはただのAction型)。Func型は戻り値を持つデリゲート型で、戻り値と引数の型を型パラメーターに指定するジェネリック型です。型パラメーターは16個までの引数の組み合わせに対応したものが用意されており、推論で一致するものが選ばれます。なお、引数が16個を超える場合や、引数がrefやoutを伴う場合には、内部的なデリゲート型が生成されて使用されます。このように自然型を使えるようになるまでは(=C#10以前では)、デリゲート型を明示する必要がありました。
こういった自然型の決定が、C#13で少しだけ改良されました。具体的な例を見てみましょう。以下はClassクラスに同名のインスタンスメソッド、拡張メソッドMethodが用意されている例です。
public class Class { public void Method(int i) { Console.WriteLine("Instance method."); } } public static class Extended { public static void Method(this Class c, string s) { Console.WriteLine("Extended method."); } } var n = c.Method; // エラー:デリゲート型を推論できませんでした。 Action<int> i = c.Method; i(100); // Instance method. Action<string> a = c.Method; a("Hello"); // Extended method.
「c.Method」と書いたとき、C# 12以前の環境では、デリゲートの自然型を推論できずにエラーになります。明示的な型指定をすれば問題ありません。
これがC# 13では、明示的な型指定なしで、インスタンスメソッドを優先的に推論します。インスタンスメソッドでオーバロードが複数ある場合に推論できないのは同様です。
var n = c.Method; n(100); // Instance method.
まとめ
今回は、コレクション式が使えるparams、新しいロックセマンティクス、新しいエスケープシーケンス\e、メソッドグループの自然型について紹介しました。
次回は、暗黙的なインデックスアクセス、イテレータと非同期メソッドで使えるようになったrefとunsafe、ジェネリクスの型制約に使えるようになったallows ref struct、partialなプロパティとインデクサ、オーバロード関数の優先順位を指定するOverloadResolutionPriority属性などを紹介します。