<?xml version="1.0" encoding="UTF-8" ?>

<rss version="2.0">
	<channel>
		<title>++C++; // 未確認飛行 C</title>
		<link>http://www.ufcpp.net</link>
		<description><![CDATA[ C# によるプログラミング入門・情報工学を中心とした勉強用ページとブログを載せています。 ]]></description>
		<pubDate>Sun, 15 Feb 2026 17:23:26 +0900</pubDate>
		<lastBuildDate>Mon, 13 Apr 2026 20:31:36 +0900</lastBuildDate>
		<language>ja</language>
		<copyright>Copyright Nobuyuki Iwanaga since 2000</copyright>

			<item>
				<title>UnsafeAccessor</title>
				<link>http://www.ufcpp.net/study/csharp/misc/unsafeaccessor/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<p>.NET 8 から、<a href="https://ufcpp.net/study/csharp/sp_reflection.html">リフレクション</a>なしで<a href="https://ufcpp.net/study/csharp/oo_conceal.html#level">アクセシビリティ</a>を無視した(private や internal なメンバーにアクセス可能な)仕組みとして UnsafeAccessor というものが追加されました。</p>
<p>用途が狭いですし、unsafe と付く名前通り割とデメリットもある機能なので、使い心地はそれほどよくありません。
「全くできないと困るので口だけは用意した」系の機能になります。
例えば、フィールド1個にアクセスするだけでも以下のような書き方になります。</p>
<pre class="source" title="UnsafeAccessor の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="type">A</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span>();

<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="static"><span class="method">RefValue</span></span>(<span class="variable">a</span>) <span class="operator">=</span> <span class="number">1</span>; <span class="comment">// private であることを無視して a._value = 1; 相当の処理を実行。</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(1)</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    <span class="comment">// A._value にアクセスするためのメソッド。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;_value&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="static"><span class="method">RefValue</span></span>(<span class="type">A</span> <span class="variable local">@this</span>);
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_value</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p><code>UnsafeAccessor</code> 属性(<code>System.Runtime.CompilerServices</code>)を付けた extern メソッドを書くと、.NET Runtime が静的に(JIT 時に) <code>_value</code> フィールド直参照と同等のコードを生成します。</p>
<h2><a id="ignore-accessibility">アクセシビリティ無視とリフレクション</a></h2>
<p>これまでアクセシビリティを無視したい場合、
たとえ型情報が静的に既知であってもリフレクションを使っていました。
例えば冒頭の例同様に <code>a._value = 1;</code> するためだけに、以下のようなコードが必要になっていました。</p>
<pre class="source" title="リフレクションで private フィールドにアクセスする例">
<span class="type">A</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span>();

<span class="comment">// a._value = 1; 相当のコードをリフレクションでやるとこうなる。</span>
<span class="reserved">typeof</span>(<span class="type">A</span>)
    <span class="operator">.</span><span class="method">GetField</span>(<span class="string">&quot;_value&quot;</span>, System<span class="operator">.</span>Reflection<span class="operator">.</span><span class="type">BindingFlags</span><span class="operator">.</span>NonPublic <span class="operator">|</span> System<span class="operator">.</span>Reflection<span class="operator">.</span><span class="type">BindingFlags</span><span class="operator">.</span>Instance)<span class="operator">!</span>
    <span class="operator">.</span><span class="method">SetValue</span>(<span class="variable">a</span>, <span class="number">1</span>);

<span class="comment">// Type 型インスタンスが作られて、</span>
<span class="comment">// FieldInfo 型インスタンスが作られて、</span>
<span class="comment">// 動的な処理で a._value = 1; 相当のコードを実行。</span>
<span class="comment">// しかも、int 型の 1 は object にボックス化されるコストもかかる。</span>

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(1)</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_value</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>コード中のコメントに書きましたが、この処理には様々なオーバーヘッドがかかります。
本当に動的な処理がしたい(本当に実行時まで型に関する情報を知らない)なら必要なコストですが、
この例の <code>A</code> のように型が既知の場合だいぶもったいないです。</p>
<p>すなわち、リフレクションの持つ以下の2つの側面があるわけですが、</p>
<ol>
<li>実行時までわからない型のメンバーを読み書きする</li>
<li>本来アクセスできないメンバーを読み書きする</li>
</ol>
<p>このうち後者だけを切り出したものが UnsafeAccessor です。</p>
<p>UnsafeAccessor を使った冒頭のコードなら、
パフォーマンス的には <code>a._value = 1;</code> と同水準になります。</p>
<h5><a id="unsafe">余談: 「unsafe」</a></h5>
<p>名前に unsafe の文字が入っていますが、
メモリ安全性や型安全性の保証はあります(この意味では普通に safe)。
バッファー オーバー ランのようなメモリ脆弱性を起こせるような機能ではないですし、
型が合わないようなコードを書くと JIT 時にエラーになります。</p>
<p>UnsafeAccessor の「unsafe」は「private や internal な物に触れるので変更されても文句が言えない」くらいの意味です。</p>
<p>また、C# コンパイラーのレベルでは型チェックできない(JIT 時チェックになるので実行してみる必要はある)という不利益もあります。</p>
<h2><a id="motivation">利用場面</a></h2>
<p>UnsafeAccessor の主な用途は以下のようなものです。</p>
<ol>
<li>シリアライザーや <a href="https://learn.microsoft.com/ja-jp/dotnet/core/extensions/dependency-injection/overview">DI</a> などをリフレクションから Source Generator に移行したい</li>
<li>元々あった大きな<a href="https://ufcpp.net/study/csharp/package/project/">アセンブリ</a>を複数に分ける際などにやむを得ず使う</li>
<li>単体テスト用途</li>
</ol>
<p>元々の想定利用場面は 1. になります。
シリアライザーでは private なフィールドへの読み書きをリフレクションで行うことが多かったです。
ところがこれは、
リフレクションを避けたい実行環境
(<a href="https://learn.microsoft.com/ja-jp/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8">AOT</a> や、<a href="https://ja.wikipedia.org/wiki/WebAssembly">Web Assembly</a> など)で困りました。
シリアライザーの場合まさに「型は静的に既知」な場合が多く、
リフレクションを使った動的コード生成から、
<a href="https://ufcpp.net/study/csharp/misc/analyzer-generator/">Source Generator</a> を使った静的なコード生成への移行が進んでいます
(例: <a href="https://learn.microsoft.com/ja-jp/dotnet/standard/serialization/system-text-json/source-generation">System.Text.Json のソース生成利用</a>)。
これがまさに UnsafeAccessor で想定する場面になります。</p>
<p>ただ、多くの人にとって、
Source Generator は使う側にはなる一方で、作る側になることは希少です。
そのため 1. の用途では、UnsafeAccessor も「ライブラリで内部的に使われている」であって、直接の利用はあまりないでしょう。</p>
<p>続いて 2. ですが、
これもよほど大規模でよほど歴史のあるコードでしか見られないものです。
例えば .NET の標準ライブラリ内で、
<a href="https://source.dot.net/#System.Net.Security/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs">System.Net.Security</a> から <a href="https://source.dot.net/#System.Net.Http/System/Net/Http/GlobalHttpSettings.cs">System.Net.Http</a> 内の internal 型への参照が残っています。
元々大きな1つのアセンブリとして提供していたものを「Http」と「Security」で分けたときに困ったものと思われます。</p>
<p>結局のところ、多くの人にとっては 3. の単体テスト用途で使うことが多くなると思われます。
「private メンバー、internal メンバーの単体テストはすべきかどうか」ということ自体議論が分かれる問題ですが、まあ「private アクセスしたくなったことがある」くらいであれば多くの人が通ったことがある道だと思います。</p>
<p>例えば以下のようなライブラリ コードがあったとして、
「<code>Dispose</code> 後は中身が null になっていてほしい」というテストを書くみたいな用途が考えられます。</p>
<pre class="source" title="">
<span class="reserved">namespace</span> Lib;

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Class1</span>(<span class="reserved">object</span><span class="operator">?</span> <span class="variable local">resource</span>) : <span class="type">IDisposable</span>
{
    <span class="reserved">private</span> <span class="reserved">object</span><span class="operator">?</span> <span class="field">_someResource</span> <span class="operator">=</span> <span class="variable local">resource</span>;

    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>()
    {
        <span class="field">_someResource</span> <span class="operator">=</span> <span class="reserved">null</span>;
    }
}
</pre>
<pre class="source" title="">
<span class="reserved">using</span> Lib;
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">namespace</span> TestProject1;

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">UnitTest1</span>
{
    [<span class="type">Fact</span>]
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose後は中身がnull</span>()
    {
        <span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">Class1</span>(<span class="string">&quot;&quot;</span>);

        <span class="reserved">using</span> (<span class="variable">x</span>)
        {
        }

        <span class="type">Assert</span><span class="operator">.</span>Null(<span class="static"><span class="method">GetSomeResourceRef</span></span>(<span class="variable">x</span>));
    }

    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;_someResource&quot;</span>)]
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">object</span><span class="operator">?</span> <span class="static"><span class="method">GetSomeResourceRef</span></span>(<span class="type">Class1</span> <span class="variable local">class1</span>);
}
</pre>
<p>こういう単体テストがいいのかどうかという話はありますが…
(仕様に応じて「<code>Dispose</code> 後に何らかの操作をしても何も起きない」とか「<code>ObjectDisposedException</code> が出る」とか、別の形でのテストが望ましい可能性あり。)
「やりたいことは時々ある」の範疇かと思われます。</p>
<p>単体テストの場合、ライブラリと単体テストでプロジェクトは分かれているものの、同じ人がコードを書くことが非常に多いです。
そのため「private なものは変更されても文句が言えない」問題が軽微(変更して単体テストが失敗するようになっても、修正する義務を同じ人が負うのですぐに直すことになるだけ)なので、UnsafeAccessor とは相性がいいです。</p>
<h2><a id="how-to-use">UnsafeAccessor の書き方</a></h2>
<p>すでにいくつかの例を書いていますが、UnsafeAccessor を使うには
<code>UnsafeAccessor</code> 属性(<code>System.Runtime.CompilerServices</code> 名前空間)を付けた extern メソッドを書きます。</p>
<p><code>UnsafeAccessor</code> 属性の第1引数に渡す <code>UnsafeAccessorKind</code> には以下の5つの値があります
(ほぼ名前通り):</p>
<ul>
<li><code>Constructor</code>: コンストラクター</li>
<li><code>Method</code>: インスタンス メソッド</li>
<li><code>StaticMethod</code>: 静的メソッド</li>
<li><code>Field</code>: インスタンス フィールド</li>
<li><code>StaticField</code>: 静的フィールド</li>
</ul>
<p>プロパティ、インデクサーや演算子などは「.NET の型システム上はメソッドになっている」という仕様があるので、<code>Method</code> か <code>StaticMethod</code> を使ってそのメソッドを呼び出すことになります。</p>
<p>ちなみに、型自体は public という場面では <code>A Accessor()</code> とか <code>void Accessor(A x)</code> みたいな素直な書き方で <code>A</code> の private メンバーにアクセスできるんですが、
型自体が internal の時はさらにちょっと面倒な書き方が必要になります。
この場合は、<code>UnsafeAccessorType</code> というもう1つの属性を使って、文字列で型名を指定することになります。</p>
<h3><a id="constructor">コンストラクター</a></h3>
<p>コンストラクターへのアクセスは以下のように書きます。</p>
<pre class="source" title="コンストラクターに対する UnsafeAccessor の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="static"><span class="method">CreateA</span></span>());
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="static"><span class="method">CreateA</span></span>(<span class="number">1</span>));

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    <span class="comment">// new A() 相当。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Constructor)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="type">A</span> <span class="static"><span class="method">CreateA</span></span>();

    <span class="comment">// new A(value) 相当。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Constructor)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="type">A</span> <span class="method"><span class="static">CreateA</span></span>(<span class="reserved">int</span> <span class="variable local">value</span>);
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="type">A</span>() { }
    <span class="reserved">private</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">=</span> <span class="variable local">value</span>;

    <span class="reserved">private</span> <span class="reserved">int</span> <span class="property">Value</span> { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="property">Value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>「何の型のコンストラクターを呼ぶか」は戻り値の型を見ます。
メソッドの引数の型はアクセス先のコンストラクターの引数と一致させます。
(引数名は違っていても平気です。一致の必要があるのは型のみ。)</p>
<p>この機能は構造体に対しても使えます。</p>
<pre class="source" title="構造体に対しても利用可能">
<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>
{
    <span class="comment">// 構造体に対しても使えて、書き方はクラスの場合と同じ。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Constructor)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="type struct">A</span> <span class="static"><span class="method">CreateA</span></span>(<span class="reserved">int</span> <span class="variable local">value</span>);
}

<span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="reserved">private</span> <span class="type struct">A</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">=</span> <span class="variable local">value</span>;
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="property">Value</span> { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="property">Value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<h3><a id="method">インスタンス メソッド</a></h3>
<p>インスタンス メソッドへのアクセスは以下のように、
「先頭に1つ引数を足す」書き方をします。</p>
<pre class="source" title="インスタンス メソッドに対する UnsafeAccessor の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>();
<span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="method"><span class="static">Add</span></span>(<span class="variable">a</span>, <span class="number">1</span>);
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(1)</span>

<span class="reserved">var</span> <span class="variable">b</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">B</span>();
<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="method"><span class="static">Add</span></span>(<span class="reserved">ref</span> <span class="variable">b</span>, <span class="number">1</span>);
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">b</span>); <span class="comment">// B(1)</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    <span class="comment">// 第1引数をアクセス先の型にする。</span>
    <span class="comment">// (拡張メソッドと同じ感覚。)</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method"><span class="static">Add</span></span>(<span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">value</span>);

    <span class="comment">// 構造体のインスタンス メソッドを呼びたい場合は ref 引数にする。</span>
    <span class="comment">// このメソッドの名前とアクセス先のメソッドの名前が違う場合は、Name で明示的に指定する。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;PrivateAdd&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method"><span class="static">Add</span></span>(<span class="reserved">ref</span> <span class="type struct">B</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">value</span>);
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_value</span>;
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">Add</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="field">_value</span> <span class="operator">+=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}

<span class="reserved">struct</span> <span class="type struct">B</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_value</span>;
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">PrivateAdd</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="field">_value</span> <span class="operator">+=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">readonly</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">B(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>2つ目以降の引数の型はアクセス先のメソッドの引数と一致させます。
(コンストラクター同様、型のみの一致で OK。)
また、戻り値の型が一致している必要もあります。</p>
<p>アクセス先の型が構造体の場合、第1引数は <code>ref</code> もしくは <code>in</code> でないとアクセスできなくなります。
(実行時エラーを起こします。)</p>
<p>また、<code>UnsafeAccessor</code> 属性をつけるメソッドの名前とアクセス先のメソッドの名前が異なる場合には <code>Name</code> プロパティの明示が必要になります。</p>
<h3><a id="field">フィールド</a></h3>
<p>インスタンス フィールドへのアクセスは以下のように、
「<code>ref</code> 戻り値、引数なしのメソッド」で書きます。</p>
<pre class="source" title="">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>();
<span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="static"><span class="method">Value</span></span>(<span class="variable">a</span>) <span class="operator">=</span> <span class="number">1</span>;
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(1)</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>
{
    <span class="comment">// 引数なし、ref 戻り値なメソッドでアクセス。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;_value&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method"><span class="static">Value</span></span>(<span class="type">A</span> <span class="variable local">a</span>);
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_value</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>フィールドとメソッドでは命名規約が違う(<code>_value</code> と <code>Value</code> になる)ので、
自然な書き方をしようとすると <code>Name</code> の明示が必要になるかと思いますが、
メソッド名が変でもいいなら以下のように <code>Name</code> の省略もできます。</p>
<pre class="source" title="メソッド名をフィールドに一致させると Name 省略可能">
<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>
{
    <span class="comment">// あまりメソッドに _ 始まりの名前を付けないものの、気にしないのであればこれでも OK。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method"><span class="static">_value</span></span>(<span class="type">A</span> <span class="variable local">a</span>);
}
</pre>
<h3><a id="static">静的メソッド、静的フィールド</a></h3>
<p>静的メソッド、静的フィールドへのアクセスには <code>UnsafeAccessorKind</code> の <code>StaticMethod</code> と <code>StaticField</code> を使います。
インスタンス メソッド、インスタン フィールドの時と同様、引数の先頭にアクセス先の型を足します(静的メンバーなのでこの第1引数は使われず、ダミー引数になります)。</p>
<pre class="source" title="静的メンバーに対する UnsafeAccessor の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="static"><span class="method">Value</span></span>(<span class="reserved">null</span>) <span class="operator">=</span> <span class="number">2</span>;

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="method"><span class="static">M</span></span>(<span class="reserved">null</span>, <span class="number">3</span>));

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>StaticField, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;_value&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="static"><span class="method">Value</span></span>(<span class="type">A</span><span class="operator">?</span> <span class="variable local">_</span>);

    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>StaticMethod)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">int</span> <span class="static"><span class="method">M</span></span>(<span class="type">A</span><span class="operator">?</span> <span class="variable local">_</span>, <span class="reserved">int</span> <span class="variable local">x</span>);
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">int</span> <span class="static"><span class="field">_value</span></span>;
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">int</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="static"><span class="field">_value</span></span>;
}
</pre>
<h3><a id="property">プロパティ</a></h3>
<p><code>UnsafeAccessorKind</code> にはプロパティを指定する方法はありませんが、
C# のプロパティは内部的にはメソッドになっているので、
そのメソッドに対する UnsafeAccessor を作ることでプロパティにアクセスできます。</p>
<p>プロパティ <code>T P</code> があったとすると、
<code>get</code>/<code>set</code> アクセサーにはそれぞれ
<code>T get_P()</code>、 <code>void set_P(T value)</code> というメソッドが対応します。
(元のプロパティ名 + <code>get_</code>/<code>set_</code> 接頭辞。)</p>
<pre class="source" title="プロパティへの UnsafeAccessor は get_ / set_ メソッドで代用">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>();
<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="static"><span class="method">SetValue</span></span>(<span class="variable">a</span>, <span class="number">1</span>);

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(1)</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="method"><span class="static">GetValue</span></span>(<span class="variable">a</span>)); <span class="comment">// 1</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    <span class="comment">// Value プロパティの get アクセサーは get_Value。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;get_Value&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">int</span> <span class="static"><span class="method">GetValue</span></span>(<span class="type">A</span> <span class="variable local">a</span>);

    <span class="comment">// Value プロパティの set アクセサーは set_Value。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;set_Value&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method"><span class="static">SetValue</span></span>(<span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">value</span>);
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="property">Value</span>{ <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="property">Value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>ちなみにこの<a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#153102-member-names-reserved-for-properties">「プロパティ名 + <code>get_</code>/<code>set_</code> 接頭辞」ルールは C# の言語仕様で決まっています</a>。
少なくとも C# コンパイラーで作ったプロパティの場合は必ずこのルールに基づくメソッド名になっています。
(<a href="https://learn.microsoft.com/ja-jp/dotnet/framework/tools/ilasm-exe-il-assembler">IL アセンブラー</a>を使えばこのルールを破れるはずですが、そんなことをやっている人は見たことがありません。)</p>
<h3><a id="indexer">インデクサー</a></h3>
<p><a href="#property">プロパティ</a>同様です。
<a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#153104-member-names-reserved-for-indexers">C# の仕様</a>上、インデクサーからは <code>get_Item</code> / <code>set_Item</code> というメソッドが作られているはずなので、これを経由してアクセスします。</p>
<pre class="source" title="インデクサーへの UnsafeAccessor は get_Item / set_Item メソッドで代用">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>(<span class="number">2</span>);
<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="method"><span class="static">SetValue</span></span>(<span class="variable">a</span>, <span class="number">0</span>, <span class="number">1</span>);
<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="method"><span class="static">SetValue</span></span>(<span class="variable">a</span>, <span class="number">1</span>, <span class="operator">-</span><span class="number">1</span>);

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A([1, -1])</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="method"><span class="static">GetValue</span></span>(<span class="variable">a</span>, <span class="number">0</span>)); <span class="comment">// 1</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="method"><span class="static">GetValue</span></span>(<span class="variable">a</span>, <span class="number">1</span>)); <span class="comment">// -1</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>
{
    <span class="comment">// インデクサーの get アクセサーは get_Item。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;get_Item&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">int</span> <span class="static"><span class="method">GetValue</span></span>(<span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">i</span>);

    <span class="comment">// インデクサーの set アクセサーは set_Item。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;set_Item&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method"><span class="static">SetValue</span></span>(<span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">i</span>, <span class="reserved">int</span> <span class="variable local">value</span>);
}

<span class="reserved">class</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">length</span>)
{
    <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="reserved">int</span>[] <span class="field">_items</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="reserved">int</span>[<span class="variable local">length</span>];
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="reserved">this</span>[<span class="reserved">int</span> <span class="variable local">i</span>]{ <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="field">_items</span>[<span class="variable local">i</span>]; <span class="reserved">set</span> <span class="operator">=&gt;</span> <span class="field">_items</span>[<span class="variable local">i</span>] <span class="operator">=</span> <span class="reserved">value</span>; }
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A([</span>{<span class="reserved">string</span><span class="operator">.</span><span class="method"><span class="static">Join</span></span>(<span class="string">&quot;, &quot;</span>, <span class="field">_items</span>)}<span class="string">])</span><span class="string">&quot;</span>;
}
</pre>
<p>(ちなみにこの <code>Item</code> の部分は <code>IndexerName</code> 属性を使って変更できたりします。
実際、<code>string</code> 型のインデクサーは <code>Chars</code> という名前です。
この場合、作られているメソッドの名前も <code>get_Chars</code> です。)</p>
<h3><a id="operator">演算子</a></h3>
<p>C# のユーザー定義の演算子は public でないといけない仕様なので、わざわざ UnsafeAccessor を使う場面はより一層少ないですが、一応触れておきます。
(後述する<a href="#unsafe-accessor-type">型自体が internal な場合</a>に対して使えなくはないです。)</p>
<p>ユーザー定義の演算子も、内部的にはただのメソッドになります。
<code>+</code> 演算子の場合は <code>op_Addition</code> など、演算子ごとに名前が決まっています。
(参考: <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#153106-method-names-reserved-for-operators">演算子とメソッド名の対応関係</a>)</p>
<pre class="source" title="演算子に対するアクセスは op_ から始まるメソッドで代用">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>(<span class="number">1</span>);

<span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="method"><span class="static">Add</span></span>(<span class="variable">a</span>, <span class="number">1</span>); <span class="comment">// a += 1;</span>

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(2)</span>

<span class="variable">a</span> <span class="operator">=</span> <span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="static"><span class="method">Add</span></span>(<span class="reserved">null</span>, <span class="variable">a</span>, <span class="number">1</span>); <span class="comment">// a = a + 1;</span>

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(3)</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>
{
    <span class="comment">// + は op_Addition。</span>
    <span class="comment">// 静的メソッドなのでダミーの第1引数が必要。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>StaticMethod, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;op_Addition&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="type">A</span> <span class="static"><span class="method">Add</span></span>(<span class="type">A</span><span class="operator">?</span> <span class="variable local">_</span>, <span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">x</span>);

    <span class="comment">// += は op_AdditionAssignment。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;op_AdditionAssignment&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="static"><span class="method">Add</span></span>(<span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">x</span>);
}

<span class="reserved">class</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">value</span>)
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_value</span> <span class="operator">=</span> <span class="variable local">value</span>;

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">A</span> <span class="reserved">operator</span> <span class="operator">+</span>(<span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">new</span>(<span class="variable local">a</span><span class="operator">.</span><span class="field">_value</span> <span class="operator">+</span> <span class="variable local">x</span>);

    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">+=</span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="field">_value</span> <span class="operator">+=</span> <span class="variable local">x</span>;

    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<h3><a id="extension">拡張メンバーを UnsafeAccessor にする</a></h3>
<p>UnsafeAccessor の「静的メソッドにして第1引数を足す」という仕様が拡張メソッドと相性がよく、
拡張メソッドをそのまま UnsafeAccessor にすることができます。</p>
<pre class="source" title="拡張メソッドに UnsafeAccessor 属性をつけるだけ">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>(<span class="number">1</span>);

<span class="comment">// 拡張メソッド X.Add(A, int) を通して private な A.Add(int) を呼ぶ。</span>
<span class="variable">a</span><span class="operator">.</span><span class="method">Add</span>(<span class="number">1</span>);

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(2)</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="static"><span class="method">Add</span></span>(<span class="reserved">this</span> <span class="type">A</span> <span class="variable local">a</span>, <span class="reserved">int</span> <span class="variable local">x</span>);
}

<span class="reserved">class</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">value</span>)
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="property">Value</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; } <span class="operator">=</span> <span class="variable local">value</span>;
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">Add</span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">+=</span> <span class="variable local">x</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="property">Value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>これは C# 14 で入る <code>extension</code> ブロック形式の拡張メンバーでもできて、
以下のような書き方で UnsafeAccessor を書けたりします。</p>
<pre class="source" title="extension ブロックで UnsafeAccessor を作る例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>(<span class="number">1</span>);

<span class="comment">// 拡張メソッド X.Add を経由して、private な A.Add を呼ぶ。</span>
<span class="variable">a</span><span class="operator">.</span><span class="method">Add</span>(<span class="number">1</span>);

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(2)</span>

<span class="comment">// 拡張プロパティ X.Value を経由して、private な A.Value を取得・設定する。</span>
<span class="variable">a</span><span class="operator">.</span><span class="property">Value</span> <span class="operator">=</span> <span class="number">3</span>;
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span><span class="operator">.</span><span class="property">Value</span>); <span class="comment">// 3</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>
{
    <span class="reserved">extension</span>(<span class="type">A</span> <span class="variable local">a</span>)
    {
        <span class="comment">// コンパイル結果は void Add(this A, int x) と一緒。</span>
        <span class="comment">// そのまま UnsafeAccessor にできる。</span>
        [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method)]
        <span class="reserved">public</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method">Add</span>(<span class="reserved">int</span> <span class="variable local">x</span>);

        <span class="comment">// 拡張プロパティも通常のプロパティと同じ get_ / set_ という名前でメソッドを作る仕様で、</span>
        <span class="comment">// int get_Value(A) / void set_Value(A, int) というメソッドができてる。</span>
        <span class="comment">// 属性も伝搬されてて、 A.Value の UnsafeAccessor にできる。</span>
        <span class="reserved">public</span> <span class="reserved">extern</span> <span class="reserved">int</span> <span class="property">Value</span>
        {
            [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method)]
            <span class="reserved">get</span>;

            [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method)]
            <span class="reserved">set</span>;
        }
    }
}

<span class="reserved">class</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">value</span>)
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="property">Value</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; } <span class="operator">=</span> <span class="variable local">value</span>;
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">Add</span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">+=</span> <span class="variable local">x</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="property">Value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<h3><a id="generics">ジェネリックな型やメンバーへのアクセス</a></h3>
<p>.NET 9 からはジェネリックな型に対して UnsafeAccessor を書けるようになりました。
型引数は以下のように「型は型に、メソッドはメソッドに」というルールで書けば大丈夫です。</p>
<pre class="source" title="ジェネリックな UnsafeAccessor の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>&lt;<span class="reserved">int</span>&gt;(<span class="number">1</span>);

<span class="static"><span class="type">X</span></span>&lt;<span class="reserved">int</span>&gt;<span class="operator">.</span><span class="method"><span class="static">M</span></span>(<span class="variable">a</span>); <span class="comment">// 1</span>
<span class="type"><span class="static">X</span></span>&lt;<span class="reserved">int</span>&gt;<span class="operator">.</span><span class="method"><span class="static">M</span></span>(<span class="variable">a</span>, <span class="string">&quot;abc&quot;</span>); <span class="comment">// 1 abc</span>

<span class="comment">// 型の型引数は型に。</span>
<span class="comment">// A&lt;T&gt; の T はここに書く。</span>
<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>&lt;<span class="type param">T</span>&gt;
{
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">A</span>&lt;<span class="type param">T</span>&gt; <span class="variable local">a</span>);

    <span class="comment">// メソッドの型引数はメソッドに。</span>
    <span class="comment">// A&lt;T&gt;.M&lt;U&gt; の U はここに書く。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Method)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">U</span>&gt;(<span class="type">A</span>&lt;<span class="type param">T</span>&gt; <span class="variable local">a</span>, <span class="type param">U</span> <span class="variable local">x</span>);
}

<span class="reserved">class</span> <span class="type">A</span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span> <span class="variable local">value</span>)
{
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">M</span>() <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable local">value</span>);
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">M</span>&lt;<span class="type param">U</span>&gt;(<span class="type param">U</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">$&quot;</span>{<span class="variable local">value</span>}<span class="string"> </span>{<span class="variable local">x</span>}<span class="string">&quot;</span>);
}
</pre>
<p>型引数の付け方は制限がかかっていて、
上記の例とは違う書き方、
例えば「クラス <code>X</code> にメソッド <code>M&lt;T&gt;</code> や <code>M&lt;T, U&gt;</code> を書く」みたいなことをすると実行時エラーになります。</p>
<h3><a id="unsafe-accessor-type">型自体が internal な場合</a></h3>
<p>.NET 10 から「型自体が internal で参照できない」という場合に対して UnsafeAccessor を使う手段が提供されるようになりました。</p>
<p>これまでの例で <code>A</code> 型の引数や戻り値を書いていた場所をとりあえず <code>object</code> 型にして、
その代わり、引数・戻り値に <code>UnsafeAccessorType</code> 属性を付けます。
<code>UnsafeAccessorType</code> 属性の引数に文字列で型名を書くことで、internal な型を参照できます。</p>
<p>例えばまず、<code>ClassLibrary1</code> という名前のプロジェクトに以下のようなクラスを用意したとします。</p>
<pre class="source" title="ClassLibrary1 プロジェクト内に internal なクラスを用意">
<span class="reserved">namespace</span> Lib;

<span class="comment">// ClassLibrary1 というプロジェクト内にあるものとする。</span>
<span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_value</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>この型を別プロジェクトから参照するには以下のように書きます。</p>
<pre class="source" title="ClassLibaray1 内の Lib.A クラスにアクセスするための UnsafeAccessor の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="static"><span class="method">CreateA</span></span>(); <span class="comment">// var a = new A();</span>
<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="static"><span class="method">_value</span></span>(<span class="variable">a</span>) <span class="operator">=</span> <span class="number">1</span>;   <span class="comment">// a._value = 1;</span>

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>);

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">X</span></span>
{
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Constructor)]
    [<span class="reserved">return</span>: <span class="type">UnsafeAccessorType</span>(<span class="string">&quot;Lib.A, ClassLibrary1&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">object</span> <span class="static"><span class="method">CreateA</span></span>();

    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="static"><span class="method">_value</span></span>([<span class="type">UnsafeAccessorType</span>(<span class="string">&quot;Lib.A, ClassLibrary1&quot;</span>)] <span class="reserved">object</span> <span class="variable local">@this</span>);
}
</pre>
<p>型名はフルネーム(<code>Lib.A</code>)で書き、
<code>,</code> でつなげて アセンブリ名(通常、プロジェクト名がそのままアセンブリ名になります。今回は <code>ClassLibrary1</code>)を書きます。</p>
<p><code>UnsafeAccessorType</code> 属性は拡張メンバーでも使えます。
(<code>object</code> 型インスタンスに対する拡張になってしまって誤用が怖いという問題はあり。)</p>
<pre class="source" title="">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="method"><span class="static">CreateA</span></span>(); <span class="comment">// var a = new A();</span>

<span class="comment">// 拡張メソッド呼び。</span>
<span class="variable">a</span><span class="operator">.</span><span class="method">_value</span>() <span class="operator">=</span> <span class="number">1</span>;   <span class="comment">// a._value = 1;</span>

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>);

<span class="comment">// 拡張プロパティ呼び。</span>
<span class="variable">a</span><span class="operator">.</span><span class="property">Value</span> <span class="operator">=</span> <span class="number">2</span>;   <span class="comment">// a._value = 2;</span>

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>);

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Constructor)]
    [<span class="reserved">return</span>: <span class="type">UnsafeAccessorType</span>(<span class="string">&quot;Lib.A, ClassLibrary1&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">object</span> <span class="static"><span class="method">CreateA</span></span>();

    <span class="comment">// 拡張メソッドでも使える。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method"><span class="static">_value</span></span>([<span class="type">UnsafeAccessorType</span>(<span class="string">&quot;Lib.A, ClassLibrary1&quot;</span>)] <span class="reserved">this</span> <span class="reserved">object</span> <span class="variable local">@this</span>);

    <span class="comment">// extension ブロックでも使える。</span>
    <span class="reserved">extension</span>([<span class="type">UnsafeAccessorType</span>(<span class="string">&quot;Lib.A, ClassLibrary1&quot;</span>)] <span class="reserved">object</span> <span class="variable local">@this</span>)
    {
        <span class="reserved">public</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="property">Value</span>
        {
            [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;_value&quot;</span>)]
            <span class="reserved">get</span>;
        }
    }
}
</pre>
<p><a href="#generics">ジェネリックな型</a>の場合は <code>`1</code> みたいな語尾をつける必要があります。
例として <code>ClassLibrary1</code> 側のクラス <code>A</code> を以下のようにジェネリック クラスにしてみます。</p>
<pre class="source" title="internal なジェネリック クラスを用意">
<span class="reserved">namespace</span> Lib;

<span class="comment">// ClassLibrary1 というプロジェクト内にあるものとする。</span>
<span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">A</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field">_value</span>;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="field">_value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>これを参照するためには以下のような書き方になります。</p>
<pre class="source" title="ClassLibaray1 内の Lib.A&lt;T&gt; クラスにアクセスするための UnsafeAccessor の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="type"><span class="static">X</span></span>&lt;<span class="reserved">int</span>&gt;<span class="operator">.</span><span class="static"><span class="method">CreateA</span></span>(); <span class="comment">// var a = new A();</span>
<span class="type"><span class="static">X</span></span>&lt;<span class="reserved">int</span>&gt;<span class="operator">.</span><span class="static"><span class="method">_value</span></span>(<span class="variable">a</span>) <span class="operator">=</span> <span class="number">1</span>;   <span class="comment">// a._value = 1;</span>

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>);

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>&lt;<span class="type param">T</span>&gt;
{
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Constructor)]
    [<span class="reserved">return</span>: <span class="type">UnsafeAccessorType</span>(<span class="string">&quot;Lib.A`1, ClassLibrary1&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">object</span> <span class="static"><span class="method">CreateA</span></span>();

    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="type param">T</span> <span class="method"><span class="static">_value</span></span>([<span class="type">UnsafeAccessorType</span>(<span class="string">&quot;Lib.A`1, ClassLibrary1&quot;</span>)] <span class="reserved">object</span> <span class="variable local">@this</span>);
}
</pre>
<p>UnsafeAccessor 定義側のクラス(この例だと <code>X&lt;T&gt;</code>)の書き方は<a href="#generics">前節</a>と同じです。
一方、 <code>UnsafeAccessorType</code> 属性に渡す型名は、
<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.type"><code>Type</code> 型</a> の <a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.type.fullname"><code>FullName</code> プロパティ</a>で得られる文字列と同じです。
<code>A&lt;T&gt;</code> であれば <code>Lib.A`1</code> になります。
<code>`</code> はバッククオートで、日本語キーボードの場合 shift + <code>@</code> で入力するやつです。
また、<code>1</code> の部分は型引数の個数で、
これが <code>A&lt;T1, T2&gt;</code> の場合だと <code>`2</code>、
<code>A&lt;T1, T2, T3&gt;</code> の場合だと <code>`3</code> になります。</p>
<h3><a id="compiler-generated-field">コンパイラー生成のフィールド</a></h3>
<p>ここからは C# の言語仕様にはない話になります。
(現在の Roslyn と呼ばれる C# コンパイラーの実装ではそうなっているけども、
将来もずっと同じ実装が続くかとかの保証はない話です。)</p>
<p><a href="https://ufcpp.net/study/csharp/oo_property.html#auto">自動プロパティ</a>
(<a href="https://ufcpp.net/study/csharp/oo_property.html?p=2#field-keyword"><code>field</code> キーワード</a>を使ったものも含む)からはフィールドが生成されています。
現在の Roslyn の場合、このフィールドの命名ルールは「プロパティ <code>P</code> に対して <code>&lt;P&gt;k__BackingField</code>」みたいになります。
この挙動を使えばプロパティのバッキング フィールドを読み書きすることができます。</p>
<pre class="source" title="バッキング フィールドを UnsafeAccessor を使って読み書き">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>();
<span class="static"><span class="type">X</span></span><span class="operator">.</span><span class="static"><span class="method">RefValue</span></span>(<span class="variable">a</span>) <span class="operator">=</span> <span class="number">1</span>;

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(1)</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    <span class="comment">// これで Value プロパティのバッキング フィールドを参照できる。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;&lt;Value&gt;k__BackingField&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method"><span class="static">RefValue</span></span>(<span class="type">A</span> <span class="variable local">a</span>);
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Value</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="property">Value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre>
<p>また、<a href="https://ufcpp.net/study/csharp/oo_construct.html#capture">プライマリ コンストラクター引数のキャプチャ</a>で作られるフィールドは、引数 <code>x</code> に対して <code>&lt;x&gt;P</code> という名前になります。</p>
<pre class="source" title="">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>(<span class="number">0</span>);
<span class="type"><span class="static">X</span></span><span class="operator">.</span><span class="method"><span class="static">RefValue</span></span>(<span class="variable">a</span>) <span class="operator">=</span> <span class="number">1</span>; <span class="comment">// 書き換え。</span>

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">a</span>); <span class="comment">// A(1)</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">X</span></span>
{
    <span class="comment">// プライマリ コンストラクター引数から作られるフィールドは &lt;&gt;P。</span>
    [<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>Field, <span class="property">Name</span> <span class="operator">=</span> <span class="string">&quot;&lt;value&gt;P&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method"><span class="static">RefValue</span></span>(<span class="type">A</span> <span class="variable local">a</span>);
}

<span class="reserved">class</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">value</span>)
{
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="string">$&quot;</span><span class="string">A(</span>{<span class="variable local">value</span>}<span class="string">)</span><span class="string">&quot;</span>;
}
</pre> ]]></description>
				<pubDate>Sun, 15 Feb 2026 17:23:26 +0900</pubDate>
			</item>
			<item>
				<title>言語バージョンの指定</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/langversionoption/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<p>ここでは、C# の言語バージョンを明示的に指定する方法について説明します。</p>
<h2><a id="lang-and-compiler">SDK バージョンと言語バージョン</a></h2>
<p>最新の C# の機能を使うためには、コンパイラー自体も最新のものを使う必要があります。
コンパイラーは <a href="https://dotnet.microsoft.com/">.NET SDK</a> に付属しているので、
最新バージョンの .NET SDK をインストールすると、C# コンパイラーも最新のものになります。
なので、最新の .NET SDK を使えば、C# も最新のものが使えます。</p>
<p>一方で、その逆は話が違って、新しいコンパイラーでもC# の「言語バージョン」をオプション指定することで、古い C# のまま維持することができます</p>
<p>例えば、以下のようなコード(<a href="https://ufcpp.net/study/csharp/cheatsheet/file-based-app/">.NET 10 以降でだけ実行できます</a>)を書いたとします。</p>
<pre class="source" title="C# 言語バージョン 11 を明示した C# コード">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">property</span><span class="string"> LangVersion=11.0</span>

<span class="comment">// C# 12 からの機能なので、C# 11 ではエラーになる。</span>
<span class="reserved">int</span>[] <span class="variable">array</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
</pre>
<p>.NET 10 だと C# の規定のバージョンは 14 になりますが、
<code>LangVersion</code> というものを明示しているので、このコードは C# 11 扱いでコンパイルされます。
このコードはあえて C# 12 の機能を使っているので、当然、エラーになります。</p>
<pre class="console" title="C# 言語バージョン 11 を明示した C# コード">
D:\src\app1&gt; dotnet .\app1.cs
D:\src\app1\app1.cs(4,15): <span style="color:#FF8080">error CS9058</span>: 機能 'コレクション式' は C# 11.0 では使用できません。12.0 以上の言語バージョンをお使いください。

<span style="color:#FF8080">ビルドに失敗しました。ビルド エラーを修正して、もう一度実行してください。</span>
</pre>
<p>特に指定がない場合、基本的には「ターゲット フレームワークで指定した .NET と同世代のバージョン」になります
(<a href="#targetframework">ターゲット フレームワーク</a>については後述)。
例えば、 .NET 9 を使うと C# 13 になりますし、 .NET 10 を使うと C# 14 になります。</p>
<p>基本的に C# は破壊的変更を好まない言語<sup>※</sup>なので、古いバージョンを維持するメリットはあまりありません。
ただ、「チーム内で .NET 10 SDK を入れた人と、9 のままの人がいる」みたいな状況では、
言語バージョンを明記しておかないと「ある人は C# 14 が使えて、他のある人は 13 のまま」みたいなことになります。
そのため、チーム内で C# のバージョンをそろえるといった意図で、バージョン明示をすることがあります。</p>
<p><sup>※</sup> かつての C# は破壊的変更をほとんどしませんでしたし、
基準が緩くなった今でも悪影響よりもメリットが大幅に上回る場合にのみ破壊的変更を認めています。</p>
<h3><a id="targetframework">ターゲット フレームワーク</a></h3>
<p>C# は .NET 上で動く言語です。
C# で書いたプログラムを動かす環境には .NET Runtime をインストールする必要があります。</p>
<p>どのバージョンの .NET Runtime を対象にプログラムを動かすかを指定するのがターゲット フレームワーク(target framework) で、
プロジェクト設定上 <code>TargetFramework</code> という項目で指定します。
例えば、<code>TargetFramework</code> に <code>net8.0</code> を指定すると、.NET 8.0 以降の Runtime で動くプログラムになります。</p>
<p>逆は真ではなく、新機能を使ったプログラムは古い .NET Runtime では動かなくなります。
<a href="https://www.nuget.org/packages/Polyfill/">互換ライブラリみたいなもの</a>を導入することで過去の .NET Runtime で新機能を動かせる場合もありますが、
<a href="https://github.com/dotnet/runtime">公式</a>がサポートするものではなく、
あくまで自己責任での導入になります(動かないことに文句を言われても公式は困る)。</p>
<p>また、一部の機能は .NET Runtime の特別なサポートが必要で、
古い環境ではどうやっても動かせないものもあります。
例えば以下のようなものがあります。</p>
<ul>
<li><a href="/study/csharp/sp2_generics.html">ジェネリクス</a> は .NET Framework 2.0 (2005年リリース)以降が必須</li>
<li><a href="/study/csharp/oo_interface.html?p=5#dim">インターフェイスのデフォルト実装</a> は .NET Core 3.0 (2019年リリース)以降が必須</li>
</ul>
<p>そもそも言語機能に限らず、標準ライブラリとして何が使えるかによってプログラムの書き方は全然変わってきますし、
「どの .NET で動かしたいか」の指定は欠かせません。
これをターゲット フレームワーク(target framework)と言います。</p>
<p>ターゲットフレームワークにはモニカー(moniker: あだ名)と呼ばれる短縮名みたいなものが振られていて、
例えば以下のように書きます。</p>
<table>
<thead>
<tr>
	<th>.NET のバージョン</th>
	<th>モニカー</th>
</tr>
</thead>
<tbody>
<tr>
	<td>.NET Framework 4.8</td>
	<td><code>net48</code></td>
</tr>
<tr>
	<td>.NET Core 3.0</td>
	<td><code>netcoreapp3.0</code></td>
</tr>
<tr>
	<td>.NET 9.0</td>
	<td><code>net9.0</code></td>
</tr>
</tbody>
</table>
<p>補足: 
.NET Framework は当初 Windows のみで動いた初期の .NET 実行環境です。
.NET Core はマルチプラットフォームで動くように作り直したもので、
バージョン番号を振りなおしたので「.NET Framework 4.8 よりも .NET Core 3.0 の方が新しい」みたいなことになっています。
.NET は単に名称の変更で中身としては .NET Core の系譜で、バージョン番号は .NET Framework 4.8 よりも .NET Core 3.0 よりも新しく見えるよう、5 から開始しています。
負の遺産として、「<code>net10</code> は .NET Framework 1.0 を指して、<code>net10.0</code> は .NET 10 を指す」みたいなことになっているので注意が必要です。</p>
<p>詳しくは公式ドキュメントである以下のページを参照してください。</p>
<ul>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/standard/frameworks?WT.mc_id=AI-MVP-123445">ターゲット フレームワーク</a></li>
</ul>
<h2><a id="option">言語バージョンの指定方法</a></h2>
<p>C# コンパイラーのオプションで、言語バージョンを明示的に指定することができます。
言語バージョンは、Visual Studio 上で行う場合、プロジェクトのプロパティを開いて、以下の場所から設定できます。
(※ ちょっと古いバージョンのスクショになります。最新バージョンでもプロジェクトのプロパティで設定できますが、UI は変わっています。)</p>
<p><img src="/media/1173/langversionja.png" alt="言語バージョン オプション" /></p>
<p>プロジェクト ファイル(拡張子が <code>csproj</code> のファイル)を直接書き換える場合、<code>PropertyGroup</code>の下に<code>LangVersion</code>タグを書きます(タグ内に書けるオプションの種類は後述します)。</p>
<pre class="xsource" title="LangVersion タグ">
<span class="attvalue">&lt;</span><span class="element">Project</span><span class="attvalue"> </span><span class="attribute">Sdk</span><span class="attvalue">=</span>"<span class="attvalue">Microsoft.NET.Sdk</span>"<span class="attvalue">&gt;</span>

<span class="attvalue">  &lt;</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">OutputType</span><span class="attvalue">&gt;</span>Exe<span class="attvalue">&lt;/</span><span class="element">OutputType</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">TargetFrameworks</span><span class="attvalue">&gt;</span>netcoreapp2.2<span class="attvalue">&lt;/</span><span class="element">TargetFrameworks</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">LangVersion</span><span class="attvalue">&gt;</span>11<span class="attvalue">&lt;/</span><span class="element">LangVersion</span><span class="attvalue">&gt;</span>
<span class="attvalue">  &lt;/</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>

<span class="attvalue">&lt;/</span><span class="element">Project</span><span class="attvalue">&gt;</span>
</pre>
<p>.NET 10 以降であれば<a href="https://ufcpp.net/study/csharp/cheatsheet/file-based-app/">ファイル ベース実行</a>という機能を使って C# ファイル中で直接 <code>LangVersion</code> 指定することもできます。</p>
<pre class="source" title="ファイル ベース実行での LangVersion 指定の例">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">property</span><span class="string"> LangVersion=11.0</span>

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;C# 11&quot;</span>);
</pre>
<p>古くは(.NET Framework の時代では)、<code>csc</code> というコマンド名で C# コンパイラーを直接呼び出していました。
この <code>csc</code> を直接使う場合には、<code>-langversion</code>オプションを指定します
(書けるオプションは上記の <code>LangVersion</code> タグと同じ)。</p>
<pre class="xsource" title="csc 直呼びの例">
<code>csc -langversion:11 app1.cs
</code></pre>
<p><code>LangVersion</code> には以下の2通りのオプション指定ができます。</p>
<ul>
<li><code>7.0</code> など、バージョン番号を直接指定</li>
<li><code>preview</code> など、後述するいくつかの文字列</li>
</ul>
<p>前者の番号指定では、メジャー バージョンであれば <code>7</code> などというように、小数点以下は省略可能です。
(※ マイナー バージョンがあったのは 7 世代の 7.1, 7.2, 7.3 だけでそれ以降はないので、
実質的には整数値で 8, 9, 10, ... などと書くだけで充分です。)</p>
<p>後者は、<code>preview</code>、<code>latest</code>、<code>latestMajor</code>、<code>default</code> の4種類があります(大文字・小文字は区別しません)が、
今となっては <code>preview</code> 以外の利用はあまり推奨しません。
バージョン番号を明示するか、何も指定しないかのどちらかがおすすめです。</p>
<h3><a id="default">何も指定しないときの挙動</a></h3>
<p><code>LangVersion</code> を指定しない場合、基本的には「<code>TargetFramework</code> に応じて自動選択」になります。
.NET 9 (<code>net9.0</code>)なら C# 13、 .NET 10 (<code>net10.0</code>)なら C# 14 というように、
同世代の言語バージョンが選ばれます。</p>
<p>公式にサポートされているのはこの「同世代の組み合わせ」なので、
特に理由がない限りには「何も指定しない」をお勧めします。</p>
<p>最近では、「<code>TargetFramework</code> と C# 言語バージョンをそろえてアップデートした場合だけ破壊的変更の影響を避けれる」みたいなことを認める方針が取られたりしています。
以下のブログのように、「C# 14 では結構大きな破壊的変更があるものの、同時に .NET 10 にした場合だけエラーにならない」みたいなことがあります。</p>
<ul>
<li><a href="https://ufcpp.net/blog/2025/10/first-class-span-breaking-change/">C# 14 の破壊的変更点(First-class Span)</a></li>
</ul>
<h3><a id="explicit">バージョン番号の明示</a></h3>
<p>ある程度分かっている人向けですが、C# の言語バージョンを明示することができます。
主に以下のような場面で使います。</p>
<ul>
<li>プログラムを動かす環境には手を入れづらく <code>TargetFramework</code> は変えられないが、開発環境は自由にできるので .NET SDK は最新にでき、C# も新しい言語バージョンが使える</li>
<li><code>TargetFramework</code> を複数指定しているが、それぞれ異なる言語バージョンが選ばれるのは困る</li>
</ul>
<p>(後述しますが、<code>latest</code> よりもバージョン明示の方をお勧めします。)</p>
<p>例えば以下のようなコードをライブラリ配布することを考えます。</p>
<pre class="source" title="複数 TargetFramework にしたいコードの例">
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Class1</span>
{
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">string</span> <span class="field"><span class="static">_rawData</span></span> <span class="operator">=</span> <span class="string">&quot;example data some words with space separation&quot;</span>;

    <span class="comment">// field キーワードを使いたいから C# 14 にしたい。</span>
    <span class="reserved">public</span> <span class="type">IEnumerable</span>&lt;<span class="type struct">KeyValuePair</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;&gt; <span class="property">Counts</span> <span class="operator">=&gt;</span> <span class="reserved">field</span> <span class="operator">??=</span> <span class="method"><span class="static">GetCounts</span></span>(<span class="static"><span class="field">_rawData</span></span><span class="operator">.</span><span class="method">Split</span>(<span class="string">' '</span>));

    <span class="reserved">private</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type struct">KeyValuePair</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;&gt; <span class="static"><span class="method">GetCounts</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">string</span>&gt; <span class="variable local">items</span>)
    {
<span class="preprocess">#</span><span class="preprocess">if</span> NET9_0_OR_GREATER
        <span class="comment">// .NET 9 以降ならこれが速い。</span>
        <span class="control">return</span> <span class="variable local">items</span><span class="operator">.</span><span class="method">CountBy</span>(<span class="variable local">x</span> <span class="operator">=&gt;</span> <span class="variable local">x</span><span class="operator">.</span><span class="property">Length</span>);
<span class="preprocess">#</span><span class="preprocess">else</span>
<span class="excluded">        // .NET 8 以前でも動くようにしたいから残すけど、
        // このコードだと長いしだいぶ遅い。
        return items.GroupBy(x =&gt; x.Length).Select(g =&gt; KeyValuePair.Create(g.Key, g.Count()));
</span><span class="preprocess">#</span><span class="preprocess">endif</span>
    }
}
</pre>
<p>このコードには以下のような意図があります。</p>
<ul>
<li>極力多くの人に使ってもらいたいので、極力古い .NET をターゲットにしたい(最低ラインを .NET 5 にする)</li>
<li>でも、新しい .NET で使う場合には高速になるように最新機能を使いたい(.NET 9 からの新機能を使えるなら使いたい)</li>
<li>ターゲットによらす、C# の機能は新しいものを使いたい(C# は 14 にしたい)</li>
</ul>
<p>この意図通りのプロジェクトを書くと以下のようになります。</p>
<pre class="xsource" title="LangVersion タグ">
<span class="attvalue">&lt;</span><span class="element">Project</span> <span class="attribute">Sdk=</span><span class="attvalue">"Microsoft.NET.Sdk"</span><span class="attvalue">&gt;</span>

  <span class="attvalue">&lt;</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>
    <span class="attvalue">&lt;</span><span class="element">TargetFrameworks</span><span class="attvalue">&gt;</span>net9.0;net5.0<span class="attvalue">&lt;/</span><span class="element">TargetFrameworks</span><span class="attvalue">&gt;</span>
    <span class="attvalue">&lt;</span><span class="element">LangVersion</span><span class="attvalue">&gt;</span>14<span class="attvalue">&lt;/</span><span class="element">LangVersion</span><span class="attvalue">&gt;</span>
    <span class="attvalue">&lt;</span><span class="element">ImplicitUsings</span><span class="attvalue">&gt;</span>enable<span class="attvalue">&lt;/</span><span class="element">ImplicitUsings</span><span class="attvalue">&gt;</span>
    <span class="attvalue">&lt;</span><span class="element">Nullable</span><span class="attvalue">&gt;</span>enable<span class="attvalue">&lt;/</span><span class="element">Nullable</span><span class="attvalue">&gt;</span>
  <span class="attvalue">&lt;/</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>

<span class="attvalue">&lt;/</span><span class="element">Project</span><span class="attvalue">&gt;</span>
</pre>
<p>この時 <code>LangVersion</code> を書かないと、
「.NET 5 向けには C# 9、.NET 9 向けには C# 13 でコンパイル」みたいなことになります。
この状態だと、「うっかり C# 13 で書ける気になって書いちゃうけど、実際は C# 9 でないとコンパイルできない」とか、
「C# 9 のときと 13 以降で解釈の違うコードを書いてしまうとどうやってもコンパイルできない」とか、
いろいろな問題を起こす可能性があります。</p>
<h3><a id="preview">プレビュー機能の利用</a></h3>
<p><code>LangVersion</code> に <code>preview</code> を指定すると、正式リリース前の C# の最新機能を先行して試すことができます。</p>
<p>2020年(.NET 5, C# 9 の世代)から、.NET は年に1回(毎年11月に)正式リリース版を出しています。
それとは別に、月に1回程度の頻度でプレビュー版を出していて、
C# の最新機能も少しずつ実装されています。
この最新機能を先行して試したい場合に <code>LangVersion</code> <code>preview</code> を指定します。</p>
<p>後述する <code>latest</code> と同じく、使っている .NET SDK のバージョン依存です。
(<code>TargetFramework</code> が実行環境(どこでプログラムを動かすか)依存なのに対して、これは開発環境依存です。)
.NET 9 SDK Preview なら C# 13 (に入る予定の当時の新機能)でしたし、
.NET 10 SDK Preview なら C# 14 (予定)でした。</p>
<p>開発環境依存なのは <code>latest</code> と同じく問題を起こしえるんですが、
そもそも <code>preview</code> で最新の C# 言語機能を試そうという人は「相当詳しい人」のはずなので特に問題視はされません。</p>
<h3><a id="other">その他のバージョン指定</a></h3>
<p><code>latest</code>、<code>latestMajor</code>、<code>default</code> の3つはおおむね「過去の名残」です。
これから新規プロジェクトを作る場合、あまり利用はお勧めしません。</p>
<p><code>latest</code> は .NET SDK バージョン依存で最新の C# 言語バージョンになります。
.NET SDK バージョン依存 = 開発環境依存なので、例えば以下のような状況で問題を起こします。</p>
<ul>
<li>
チーム開発していて、うっかり1人だけ .NET SDK のバージョンを上げてしまった
<ul>
<li>自動的にその1人だけ C# の言語バージョンが変わる</li>
</ul>
</li>
<li>
CI 環境を更新せず、手元の開発環境だけを更新してしまった
<ul>
<li>手元ではコンパイルできているのに、GitHub などに Push するとチェックが通らない</li>
</ul>
</li>
</ul>
<p>こういう問題を避けるため、<a href="#default">バージョン未指定</a>にできない場合でも極力、
<a href="#explict">バージョン番号の明示</a>にした方が安全です。</p>
<p><code>latestMajor</code> は <code>latest</code> に似ているんですが、メジャー バージョンしか選ばれないというものです。
C# 7.1, 7.2, 7.3 時代の遺物で、
この時代は <code>latest</code> だと 7.1～7.3、<code>latestMajor</code> だと 7.0 になっていました。
当時は .NET Framework から .NET Core への移行期間で、
7.1 や 7. 2 のサポートが間に合っていなかったという開発体制の都合です。
C# 8 以降、マイナー バージョンアップなリリースはないので、今となっては実質 <code>latest</code> と差がありません。</p>
<p><code>default</code> は意味通りにとらえるなら「未指定時と同じ」になるはずなんですが、以下のような事情で少し複雑です。</p>
<ul>
<li>
プロジェクト(csproj ファイル)中
<ul>
<li>未指定は<a href="#default">前述のとおり</a> <code>TargetFramework</code> に応じた自動選択</li>
<li>
<code>&lt;LangVersion&gt;default&lt;/LangVersion&gt;</code> は後述のコンパイラー オプションの <code>-langversion:default</code> と同じ意味
<ul>
<li>結果、<code>-langversion:latest</code> と同じ意味</li>
</ul>
</li>
</ul>
</li>
<li>
C# コンパイラーのオプション
<ul>
<li>未指定 = <code>-langversion:default</code> = <code>-langversion:latest</code></li>
<li>開発環境依存の「最新」</li>
<li>(ただし、C# 7.1～C# 7.3 の時代に限り、<code>-langversion:default</code> = <code>-langversion:latestMajor</code>)</li>
</ul>
</li>
</ul>
<p>C# コンパイラー自体にはプロジェクト ファイル(csproj)を解釈する機能がなく、
<code>TargetFramework</code> がわからないのでこういうことになっています。
とりあえず <code>default</code> は使わない方が無難でしょう。</p>
<p>(ちなみに、プロジェクト中で1度設定されてしまった <code>LangVersion</code> も再度 <code>&lt;LangVersion&gt;</code> タグを書くことで上書きできますが、
<a href="#default">バージョン未指定</a>挙動にしたい場合は <code>&lt;LangVersion&gt;&lt;/LangVersion&gt;</code> というように空タグを書きます。
<code>&lt;LangVersion&gt;default&lt;/LangVersion&gt;</code> と書いてしまうとここで説明したように <code>latest</code> 挙動になります。)</p>
 ]]></description>
				<pubDate>Sun, 23 Nov 2025 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>ファイル ベース実行</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/file-based-app/</link>
				<description><![CDATA[ <h1>ファイル ベース実行</h1>
<h2><a id="abstract">概要</a></h2>
<p>.NET 10 (C# 14 と同世代)で単独の <code>.cs</code> ファイルだけで C# プログラムを実行できるようになりました。
例えば、<code>app1.cs</code> という名前で保存した C# ファイルを <code>dotnet app1.cs</code> という1コマンドだけで実行できます。
それに伴って、C# 14 で <code>#!</code> と <code>#:</code> (無視ディレクティブ)という機能が追加されています。</p>
<p>(C# 言語の新文法というよりは、C# コンパイラーの1機能という感じのものです。
バージョン的にも C# 14 である必要はなくて、.NET 10 以降付属の C# コンパイラーであれば言語バージョン問わず <code>#!</code> と <code>#:</code> を認識します。)</p>
<p>本項ではこの「単独のファイルでの実行」(ファイル ベース実行)の話と、
C# 14 の <code>#!</code> と <code>#:</code> (無視ディレクティブ)について説明します。</p>
<p>サンプル コード: <a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/FileBaseApp">FileBaseApp</a></p>
<h2><a id="file-based-app">ファイル ベース実行</a></h2>
<p>改めて、 .NET 10 で C# ファイルを直接1コマンドで実行できるようになりました。
例えば、以下の1行だけ書いたファイル <code>app1.cs</code> を用意して、</p>
<pre class="source" title="1行だけの .cs ファイル">
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;🐈&quot;</span>);
</pre>
<p>以下のようなコマンドを打つと、この C# ファイルを単独で実行できます。</p>
<pre class="source" title="app1.cs ファイルを直接実行する">
<span class="prompt">&gt;</span> dotnet app1.cs
🐈
</pre>
<p>これは<a href="https://ufcpp.net/study/csharp/cheatsheet/apscripting/">スクリプト実行</a>ではなく、通常の<sup><a href="#non-scripting">※脚注</a></sup> C# 実行になります。
この仕組みをファイル ベース実行(file-based execution) と言い、これを使って書かれた C# プログラムをファイル ベース アプリ(file-based app)と言ったりします。</p>
<p>この機能の追加に伴い、これまでであれば<a href="https://ufcpp.net/study/csharp/devenv/vs_project/">プロジェクト</a> (実体は拡張子 <code>.csproj</code> の XML ファイル)に書いていた設定の類を C# 中に直接書けるようになりました。
以下の2つが追加されています。</p>
<ul>
<li><code>#!</code> : いわゆる <a href="https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%90%E3%83%B3_(Unix)">shebang</a></li>
<li><code>#:</code> : プロジェクト設定の類を書くための<a href="https://ufcpp.net/study/csharp/sp_preprocess.html#preprocess">ディレクティブ</a>で、C# コンパイラーにとっては「単に無視」になる</li>
</ul>
<p>ちなみに、普通に <code>.csproj</code> ファイルを使って C# プロジェクトをコンパイルする際には、<code>#!</code> や <code>#:</code> があるとコンパイル エラーになります。
ただし、<code>.csproj</code> ファイル中に <code>&lt;Features&gt;FileBasedProgram&lt;/Features&gt;</code> オプションを書いておくとコンパイルでき、この場合、<code>#!</code> や <code>#:</code> から始まる行は単に無視されます。
C# コンパイラーからすると「単に無視するもの」なので、無視ディレクティブ(ignored directive)と呼ばれます。</p>
<p><sup><a id="non-scripting">※</a></sup> スクリプト実行が「それ専用の構文がいくつかある」状態なのに対して、
ファイル ベース実行は本当に普通の C# です。
スクリプト実行みたいに「1行1行追加で実行」みたいなことができない一方で、
「コードが多くなってきたから <code>.csproj</code> 形式の通常の C# プロジェクトに切り替えたい」というときにスムーズに移行できます。
移行を自動化するための <code>dotnet project convert</code> というコマンドも用意されています。</p>
<h2><a id="shebang">shebang</a></h2>
<p><code>#!</code> (通称 shebang。 sharp + bang が由来)は主に Unix のスクリプト言語で使われるもので、
ソースコードの先頭にこの記号から始まる行を入れると「何を使ってこのスクリプトを実行するか」を指定できます。</p>
<p>C# 14 で、C# にもこの1行を入れることができるようになりました。
例えば前節の <code>app1.cs</code> ファイルにちょっと手を加えて以下のような内容にします。</p>
<pre class="source" title="shebang 入り .cs ファイル">
<span class="comment">#!/usr/bin/env dotnet</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;🐈&quot;</span>);
</pre>
<p>このファイルは <a href="https://ja.wikipedia.org/wiki/Bash">bash</a> などの Unix 系シェルで <code>./app1.cs</code> みたいに直接実行できるようになります。
(実行権限が必要なので、最初に1回 <code>chmod +x</code> などの操作が必要。)</p>
<pre class="source" title="bash 上で app1.cs を直接実行する">
<span class="prompt">$</span> ls
app1.cs
<span class="prompt">$</span> chmod +x app1.cs
<span class="prompt">$</span> ./app1.cs
🐈
</pre>
<p>用途的に、<code>#!</code> はファイルの先頭にのみ書けます。
<code>#!</code> の前には改行はもちろんのこと、空白文字や <a href="https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E9%A0%86%E3%83%9E%E3%83%BC%E3%82%AF">BOM</a> を入れることもできません。</p>
<h2><a id="ignored-directive">: 無視ディレクティブ</a></h2>
<p><code>#:</code> から始まる行は <code>dotnet</code> コマンドがプロジェクト設定として解釈するために使い、
C# 上は単に無視されます。</p>
<p>例えば、以下のような <code>.cs</code> ファイルをファイル ベース実行するのは、</p>
<pre class="source" title="#: を使ったファイル ベース実行の例">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">property</span><span class="string"> InvariantGlobalization=true</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="reserved">new</span> <span class="type struct">DateTime</span>(<span class="number">2000</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>));
</pre>
<p>以下のような2ファイルを使って既存の <code>.csproj</code> ベースの <code>dotnet run</code> をするのとほぼ同じ意味になります。</p>
<p><code>app1.csproj</code>:</p>
<pre class="xml" title="既存の .csproj ベース実行の例(app1.csproj)">
&lt;Project Sdk=&quot;Microsoft.NET.Sdk&quot;&gt;
    &lt;PropertyGroup&gt;
    &lt;OutputType&gt;Exe&lt;/OutputType&gt;
    &lt;TargetFramework&gt;net10.0&lt;/TargetFramework&gt;
    &lt;ImplicitUsings&gt;enable&lt;/ImplicitUsings&gt;
    &lt;Nullable&gt;enable&lt;/Nullable&gt;
    &lt;/PropertyGroup&gt;
    <em>&lt;InvariantGlobalization&gt;true&lt;/InvariantGlobalization&gt;</em>
&lt;/Project&gt;
</pre>
<p><code>app1.cs</code>:</p>
<pre class="source" title="既存の .csproj ベース実行の例(app1.cs)">
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="reserved">new</span> <span class="type struct">DateTime</span>(<span class="number">2000</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>));
</pre>
<p>(ちなみに <code>InvariantGlobalization</code> を指定すると書式が北米フォーマットになるので、出力される結果は <code>01/02/2000 03:04:05</code> (MM/dd/yyyy)になります。)</p>
<p><code>#:</code> で始まる無視ディレクティブは <a href="#shebang">shebang</a> とコメントを除いて、ファイルの先頭に置く必要があります。
例えば以下のコードでは、5行目(<code>LangVersion</code> の行)は問題なく、
9行目(<code>ImplicitUsings</code> の行)でだけコンパイル エラーを起こします。</p>
<pre class="source" title="">
<span class="comment">#!/usr/bin/env dotnet</span>

<span class="comment">// コメントはあってもいい。</span>

<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">property</span><span class="string"> LangVersion=13</span>

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;🐈&quot;</span>);

<span class="preprocess">#</span><span class="preprocess"><span class="error" title="CS9297">:</span></span><span class="preprocess">property</span><span class="string"> ImplicitUsings=disable</span>
</pre>
<p>.NET 10 時点で、<code>dotnet</code> コマンドは以下のディレクティブを解釈できます。</p>
<table>
<thead>
<tr>
	<th>ディレクティブ</th>
	<th>意味</th>
	<th><code>.csproj</code> での書き方</th>
</tr>
</thead>
<tbody>
<tr>
	<td><code>#:sdk</code></td>
	<td><a href="https://learn.microsoft.com/ja-jp/dotnet/core/project-sdk/overview">プロジェクト SDK</a> を指定</td>
	<td><code>&lt;Project Sdk=&quot;これ&quot;&gt;</code></td>
</tr>
<tr>
	<td><code>#:property</code></td>
	<td><a href="https://learn.microsoft.com/ja-jp/visualstudio/msbuild/propertygroup-element-msbuild">プロパティ要素</a></td>
	<td><code>&lt;PropertyGroup&gt;</code> の子要素</td>
</tr>
<tr>
	<td><code>#:package</code></td>
	<td><a href="https://learn.microsoft.com/ja-jp/nuget/consume-packages/package-references-in-project-files">パッケージ参照</a></td>
	<td><code>&lt;PackageReference&gt;</code> 要素</td>
</tr>
<tr>
	<td><code>#:project</code></td>
	<td><a href="https://learn.microsoft.com/ja-jp/visualstudio/msbuild/common-msbuild-project-items#projectreference">プロジェクト参照</a></td>
	<td><code>&lt;ProjectReference&gt;</code> 要素</td>
</tr>
</tbody>
</table>
<h3><a id="sdk-directive">sdk ディレクティブ</a></h3>
<p><code>#:sdk</code> は、 <code>.csproj</code> では <code>&lt;Project Sdk=&quot;Identifier&quot;&gt;</code> と書いていたものです。
省略した場合は <code>Microsoft.NET.Sdk</code> (ライブラリやコンソール プログラムで使う一番シンブルな SDK)になります。 
実質的には「ASP.NET プログラムを書きたいときに <code>Microsoft.NET.Sdk.Web</code> にするもの」です。</p>
<p>例えば、以下のようなコードで ASP.NET なコードをファイル ベース実行できます。</p>
<pre class="source" title="ファイル ベース ASP.NET コード">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">sdk</span><span class="string"> Microsoft.NET.Sdk.Web</span>

<span class="reserved">var</span> <span class="variable">app</span> <span class="operator">=</span> <span class="type">WebApplication</span><span class="operator">.</span>CreateBuilder(<span class="reserved">args</span>)<span class="operator">.</span>Build();
<span class="variable">app</span><span class="operator">.</span>MapGet(<span class="string">&quot;/&quot;</span>, () <span class="operator">=&gt;</span> <span class="string">&quot;Hello World!&quot;</span>);
<span class="variable">app</span><span class="operator">.</span>Run();
</pre>
<h3><a id="property-directive">property ディレクティブ</a></h3>
<p><code>#:property</code> は、 <code>.csproj</code> では <code>&lt;PropertyGroup&gt;</code> の子要素として書いていたものです。
<code>.csproj</code> の <code>&lt;Tag&gt;Value&lt;/Tag&gt;</code> 要素が <code>#:property Tag=Value</code> という書き方になります。</p>
<p><a href="#ignored-directive">無視ディレクティブの節</a>の冒頭の <code>InvariantGlobalization</code> の例もこれになります。
その他、例えば <a href="https://ufcpp.net/study/csharp/sp_unsafe.html">unsafe ブロック</a>はオプションを指定しないと使えない構文なわけですが、以下のように書くことでそのオプションを指定できます。</p>
<pre class="source" title="AllowUnsafeBlocks=true">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">property</span><span class="string"> AllowUnsafeBlocks=true</span>

<span class="comment">// unsafe ブロックはオプションをつけないと使えない構文。</span>
<span class="reserved">unsafe</span>
{
    <span class="reserved">int</span> <span class="variable">n</span> <span class="operator">=</span> <span class="number">1</span>;
    <span class="reserved">int</span><span class="operator">*</span> <span class="variable">pn</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="variable">n</span>;
    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">$&quot;</span>{(<span class="reserved">nint</span>)<span class="variable">pn</span>:<span class="string">x</span>}<span class="string">&quot;</span>);
}
</pre>
<h3><a id="package-directive">package ディレクティブ</a></h3>
<p><code>#:package</code> は、 <code>.csproj</code> では <code>&lt;PackageReference&gt;</code> 要素で書いていたものです。
<code>.csproj</code> の <code>&lt;PackageReference Include=&quot;PackageName&quot; Version=&quot;x.y.z&quot; /&gt;</code> 要素が <code>#:package PackageName@x.y.z</code> という書き方になります。</p>
<p>例として <code>Microsoft.CodeAnalysis.CSharp</code> パッケージ(C# 中から C# コンパイラー自身を呼ぶためのライブラリ)を参照したコードを書くと以下のようになります。
(ちなみに、4.14.0 は C# 13 当時のバージョンです。)</p>
<pre class="source" title="Microsoft.CodeAnalysis.CSharp パッケージを参照する例">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">package</span><span class="string"> Microsoft.CodeAnalysis.CSharp@4.14.0</span>

<span class="reserved">using</span> Microsoft<span class="operator">.</span>CodeAnalysis<span class="operator">.</span>CSharp;

<span class="reserved">var</span> <span class="variable">tree</span> <span class="operator">=</span> <span class="type">CSharpSyntaxTree</span><span class="operator">.</span><span class="method"><span class="static">ParseText</span></span>(<span class="string">&quot;class Class1;&quot;</span>);
<span class="reserved">var</span> <span class="variable">root</span> <span class="operator">=</span> <span class="control">await</span> <span class="variable">tree</span><span class="operator">.</span><span class="method">GetRootAsync</span>();
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">root</span><span class="operator">.</span><span class="method">GetFirstToken</span>()<span class="operator">.</span><span class="property">Text</span>);
</pre>
<h3><a id="project-directive">project ディレクティブ</a></h3>
<p><code>#:project</code> は、 <code>.csproj</code> では <code>&lt;ProjectReference&gt;</code> 要素で書いていたものです。
<code>.csproj</code> の <code>&lt;ProjectReference Include=&quot;path&quot; /&gt;</code> 要素が <code>#:project path</code> という書き方になります。</p>
<p>例えば以下のような書き方で、<code>.cs</code> のある場所からの相対パスで <code>Lib/Lib.csproj</code> プロジェクトを参照できます。</p>
<pre class="source" title="プロジェクトを参照する例">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">project</span><span class="string"> Lib/Lib.csproj</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(Lib<span class="operator">.</span><span class="type">Class1</span><span class="operator">.</span><span class="property"><span class="static">Name</span></span>);
</pre>
<h3><a id="unknown-directive">未対応のディレクティブ</a></h3>
<p>未対応の <code>#:</code> ディレクティブは、ファイル ベース実行するとエラーを起こします。
例えば以下のようなコードを書いて <code>dotnet app1.cs</code> コマンド実行すると、
「認識されないディレクティブ ' aaa' です。」というエラーが出ます。</p>
<pre class="source" title="わざと変な無視ディレクティブを書いた例">
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">aaa</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;🐈&quot;</span>);
</pre>
<p>ちなみにこのエラーを出すのはあくまで <code>dotnet</code> コマンドであって、
C# コンパイラー的には「<code>#:</code> で始まるディレクティブはすべて無視」という挙動になっています。
<code>&lt;Features&gt;FileBasedProgram&lt;/Features&gt;</code> オプションを書いた <code>.csproj</code> ファイルを用意して、
旧来方式でコンパイルすると <code>#:aaa</code> の行のエラーは出ません。</p>
 ]]></description>
				<pubDate>Sat, 11 Oct 2025 16:20:45 +0900</pubDate>
			</item>
			<item>
				<title>C# 14.0 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver14/</link>
				<description><![CDATA[ <div class="version version14">Ver. 14.0</div>
<table>
<tr>
<th>リリース時期</th>
<td>2025/11</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>.NET 10.0</li>
<li>Visual Studio 2022 18.0</li>
</td>
</tr>
</table>
<p>執筆予定: <a href="https://github.com/ufcpp/UfcppSample/issues/487">C# 14.0 トラッキング issue</a></p>
<h2><a id="field-keyword">field キーワード</a></h2>
<p><code>field</code> という文脈キーワードが追加されました。
プロパティの <code>get</code>/<code>set</code> の中に <code>field</code> と書くと、
バッキング フィールドを生成した上で、そのフィールドの読み書きができます。
例えば前述の例を <code>field</code> を使って書き直すと以下のようになります。</p>
<pre class="source" title="field キーワードの例">
<span class="reserved">using</span> System<span class="operator">.</span>ComponentModel;
<span class="reserved">using</span> System<span class="operator">.</span>Diagnostics<span class="operator">.</span>CodeAnalysis;

<span class="reserved">class</span> <span class="type">FieldBackedProperties</span> : <span class="type">INotifyPropertyChanged</span>
{
    <span class="comment">// 遅延初期化: 最初のプロパティ アクセス時にインスタンスを生成。</span>
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="property">X</span> <span class="operator">=&gt;</span> <span class="reserved">field</span> <span class="operator">??=</span> <span class="string">&quot;&quot;</span>;

    <span class="comment">// set 側だけ null 許容(get 側で ?? で非 null 化)。</span>
    [<span class="type">AllowNull</span>]
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="property">Y</span>
    {
        <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="reserved">field</span> <span class="operator">??</span> <span class="string">&quot;&quot;</span>;
        <span class="reserved">set</span>;
    }

    <span class="comment">// INotifyPropertyChanged の実装: get 側だけ素通し。</span>
    <span class="reserved">public</span> <span class="reserved">string</span><span class="operator">?</span> <span class="property">Z</span>
    {
        <span class="reserved">get</span>;
        <span class="reserved">set</span>
        {
            <span class="control">if</span> (<span class="reserved">field</span> <span class="operator">!=</span> <span class="reserved">value</span>)
            {
                <span class="reserved">field</span> <span class="operator">=</span> <span class="reserved">value</span>;
                PropertyChanged<span class="operator">?</span><span class="operator">.</span><span class="method">Invoke</span>(<span class="reserved">this</span>, <span class="reserved">new</span>(<span class="reserved">nameof</span>(<span class="property">Z</span>)));
            }
        }
    }

    <span class="reserved">public</span> <span class="reserved">event</span> <span class="type">PropertyChangedEventHandler</span><span class="operator">?</span> PropertyChanged;
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oo_property.html?p=2#field-keyword">field キーワード</a>」で説明します。</p>
<h2><a id="null-conditional-assignment">null 条件代入</a></h2>
<p>代入演算の左側で <code>?.</code> や <code>?[]</code> を書くことで「null じゃないときだけ代入」ができるようになりました。
これを null 条件代入(null conditional assignment)といいます。</p>
<pre class="source" title="null 条件代入の例">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">A</span><span class="operator">?</span> <span class="variable local">a</span>)
{
    <span class="comment">// if (a != null) a.X = 10; とほぼ同じ。</span>
    <span class="variable local">a</span><span class="operator">?</span><span class="operator">.</span><span class="property">X</span> <span class="operator">=</span> <span class="number">10</span>;

    <span class="comment">// if (a != null) a[0] = 10; とほぼ同じ。</span>
    <span class="variable local">a</span><span class="operator">?</span>[<span class="number">0</span>] <span class="operator">=</span> <span class="number">10</span>;

    <span class="comment">// if (a != null) a.Event += () =&gt; { }; とほぼ同じ。</span>
    <span class="variable local">a</span><span class="operator">?</span><span class="operator">.</span>Event <span class="operator">+=</span> () <span class="operator">=&gt;</span> { };
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">X</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }

    <span class="reserved">public</span> <span class="reserved">int</span> <span class="reserved">this</span>[<span class="reserved">int</span> <span class="variable local">index</span>]
    {
        <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="number">0</span>;
        <span class="reserved">set</span> { }
    }

    <span class="reserved">public</span> <span class="reserved">event</span> <span class="type">Action</span><span class="operator">?</span> <span class="warning" title="CS0067">Event</span>;
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/rm_nullusage.html#null-conditional-assignment">null の取り扱い - null じゃないときだけ代入</a>」で説明します。</p>
<h2><a id="first-class-span">First-class Span</a></h2>
<p><code>Span&lt;T&gt;</code>/<code>ReadOnlySpan&lt;T&gt;</code> 構造体を言語構文的に特別扱いするようなりました。</p>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/resource/span/#first-class-span">First-class Span</a>」で説明します。</p>
<h2><a id="overload-compound">複合代入演算子のオーバーロード</a></h2>
<p>複合代入演算子を直接オーバーロードできるようになりました。</p>
<pre class="source" title="複合代入演算子のオーバーロードの例">
<span class="reserved">record</span> <span class="reserved">struct</span> <span class="type struct">X</span>(<span class="reserved">int</span> <span class="variable local">Value</span>)
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">+=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">+=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">-=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">-=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">*=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">*=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">/=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">/=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">%=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">%=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">&amp;=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">&amp;=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">|=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">|=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">^=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">^=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">&lt;&lt;=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">&lt;&lt;=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">&gt;&gt;=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">&gt;&gt;=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">&gt;&gt;&gt;=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="property">Value</span> <span class="operator">&gt;&gt;&gt;=</span> <span class="variable local">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator">+=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) { <span class="reserved">checked</span> { <span class="property">Value</span> <span class="operator">+=</span> <span class="variable local">value</span>; }; }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator">-=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) { <span class="reserved">checked</span> { <span class="property">Value</span> <span class="operator">+=</span> <span class="variable local">value</span>; }; }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator">*=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) { <span class="reserved">checked</span> { <span class="property">Value</span> <span class="operator">+=</span> <span class="variable local">value</span>; }; }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator">/=</span>(<span class="reserved">int</span> <span class="variable local">value</span>) { <span class="reserved">checked</span> { <span class="property">Value</span> <span class="operator">+=</span> <span class="variable local">value</span>; }; }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">++</span>() <span class="operator">=&gt;</span> <span class="property">Value</span><span class="operator">++</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="operator">--</span>() <span class="operator">=&gt;</span> <span class="property">Value</span><span class="operator">--</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator">++</span>() { <span class="reserved">checked</span> { <span class="property">Value</span><span class="operator">++</span>; } }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator">--</span>() { <span class="reserved">checked</span> { <span class="property">Value</span><span class="operator">--</span>; } }
}
</pre>
<p>以前から二項演算子(<code>+</code> など)のオーバーロードをすることで、それに対応する複合代入(<code>+=</code> など)ができていましたが、この実装だとコピーのコストが不可避でした。
複合代入演算子を直接オーバーロードすることでこのコストを削減できます。</p>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oo_operator.html#overload-compound">複合代入演算子のオーバーロード</a>」で説明します。</p>
<h2><a id="simple-param-with-modifier">修飾子付きの引数の型名省略</a></h2>
<p><code>ref</code> や <code>out</code> などの修飾子が必須の引数でも、ラムダ式引数の型名を省略できるようになりました。</p>
<pre class="source" title="修飾子が必須でも引数の型名を省略できるように">
<span class="comment">// C# 13 までは型名省略不可で、(string text, out int result) のように書く必要があった。</span>
<span class="type">TryParse</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">m</span> <span class="operator">=</span> (<span class="variable local">text</span>, <span class="reserved">out</span> <span class="variable local">result</span>) <span class="operator">=&gt;</span> { <span class="variable local">result</span> <span class="operator">=</span> <span class="number">0</span>; <span class="control">return</span> <span class="reserved">true</span>; };

<span class="reserved">delegate</span> <span class="reserved">bool</span> <span class="type">TryParse</span>&lt;<span class="type param">T</span>&gt;(<span class="reserved">string</span> <span class="variable local">text</span>, <span class="reserved">out</span> <span class="type param">T</span> <span class="variable local">result</span>);
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/functional/fun_localfunctions/#simple-param-with-modifier">修飾子付きの引数の型名省略</a>」で説明します。</p>
<h2><a id="others">その他</a></h2>
<h3><a id="partial-event">部分イベントと部分コンストラクター</a></h3>
<p><a href="https://ufcpp.net/study/csharp/misc/partial-type/#partial_property">部分プロパティ</a> (C# 13)に続いて、
C# 14 では<a href="https://ufcpp.net/study/csharp/sp_event.html">イベント</a>と<a href="https://ufcpp.net/study/csharp/oo_construct.html">コンストラクター</a>も部分定義できるようになりました。</p>
<pre class="source" title="部分イベントと部分コンストラクターの例">
<span class="comment">// 元コード(手書き想定)。</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="comment">// 部分イベント。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">event</span> <span class="type">Action</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> PartialEvent;

    <span class="comment">// 部分コンストラクター。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="type">PartialClass</span>();
}

<span class="comment">// コード生成で作ってもらう前提のコード。</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">private</span> <span class="type">Action</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="field">_partialEvent</span>;
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">event</span> <span class="type">Action</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> PartialEvent
    {
        <span class="reserved">add</span> <span class="operator">=&gt;</span> <span class="field">_partialEvent</span> <span class="operator">+=</span> <span class="reserved">value</span>;
        <span class="reserved">remove</span> <span class="operator">=&gt;</span> <span class="field">_partialEvent</span> <span class="operator">-=</span> <span class="reserved">value</span>;
    }

    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="type">PartialClass</span>() { }
}
</pre>
<h3><a id="unbount-type-in-nameof">unbound な型に対する nameof</a></h3>
<p><code>T&lt;&gt;</code> みたいに型引数を埋めていないジェネリック型(これを unbound (未束縛)とか open (開きっぱなし) な型といいます)に対して <code>nameof</code> 演算子を使えるようになりました。</p>
<pre class="source" title="unbound なジェネリック型に対する nameof 演算子">
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="reserved">nameof</span>(<span class="type">List</span>&lt;&gt;)); <span class="comment">// &quot;List&quot;</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="reserved">nameof</span>(<span class="type">Dictionary</span>&lt;,&gt;<span class="operator">.</span><span class="property">Keys</span>)); <span class="comment">// &quot;Keys&quot;</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="reserved">nameof</span>(<span class="type">List</span>&lt;&gt;<span class="operator">.</span><span class="type struct">Enumerator</span><span class="operator">.</span><span class="method">MoveNext</span>)); <span class="comment">// &quot;MoveNext&quot;</span>
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/st_string.html#unbount-type-in-nameof">unbound な型に対する nameof</a>」で説明します。</p>
<h3><a id="file-based-app">ファイル ベース実行</a></h3>
<p>.NET 10 (C# 14 と同世代)で単独の <code>.cs</code> ファイルだけで C# プログラムを実行できるようになりました。</p>
<p>それに伴って、C# 的にも <code>#!</code> と <code>#:</code> (無視ディレクティブ)という機能が追加されています。
例えば以下のようなコードが書けて、
Unix 系シェルの <a href="https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%90%E3%83%B3_(Unix)">shebang</a> を書けたり、これまでであればプロジェクト(<code>.csproj</code> ファイル中)に書いていた設定の類を C# ソースコード中に書けるようになっています。</p>
<pre class="source" title="shebang 入り .cs ファイル">
<span class="comment">#!/usr/bin/env dotnet</span>
<span class="preprocess">#</span><span class="preprocess">:</span><span class="preprocess">sdk</span><span class="string"> Microsoft.NET.Sdk.Web</span>

<span class="reserved">var</span> <span class="variable">app</span> <span class="operator">=</span> <span class="type">WebApplication</span><span class="operator">.</span>CreateBuilder(<span class="reserved">args</span>)<span class="operator">.</span>Build();
<span class="variable">app</span><span class="operator">.</span>MapGet(<span class="string">&quot;/&quot;</span>, () <span class="operator">=&gt;</span> <span class="string">&quot;Hello World!&quot;</span>);
<span class="variable">app</span><span class="operator">.</span>Run();
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/cheatsheet/file-based-app/">ファイル ベース実行</a>」で説明します。</p>
 ]]></description>
				<pubDate>Sun, 31 Aug 2025 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] オーバーロード解決</title>
				<link>http://www.ufcpp.net/study/csharp/structured/miscoverloadresolution/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p><a href="/study/csharp/st_function.html#overload">関数</a>で説明しましたが、
C# では<a href="/study/csharp/st_function.html#function-member">関数メンバー</a>に対して、
同名で引数リストだけが違う物を定義でき、これをオーバーロードと呼びます。</p>
<p>同名の関数がいくつかあるので、<code>M(0)</code> などと書いた時、実際には「どの<code>M</code>が呼ばれるか」という検索処理が必要になります。
このような同名の関数のうちどれを呼ぶか探す処理を<strong id="overload-resolution" class="keyword">オーバーロード解決</strong>(overload resolution)と呼びます。</p>
<p>本項では、C# がどういうルールでオーバーロード解決を行っているのかについて説明して行きます。</p>
<h2><a id="betterness-rule">「より一致度の高いものを選ぶ」ルール</h2>
<p>オーバーロード解決は、基本方針だけを一言でいうとシンプルで、
「より一致度の高いものを選ぶ」という方針になっています。
詳しくは後々説明して行くことになりますが、例えば以下のようなルールになっています。</p>
<ul>
<li>型変換なしで引数に渡せるなら、それを優先的に呼ぶ</li>
<li>引数の数がピッタリ一致している方を優先的に呼ぶ</li>
</ul>
<h3><a id="parameter-type">引数の型</h3>
<p>引数の型は、以下のリストの上の方ほど「一致度が高い」と判断されます。</p>
<ul>
<li>ぴったり一致する型</li>
<li><a href="http://ufcpp.net/study/csharp/sp2_generics.html">ジェネリック</a>な型</li>
<li>
親クラス
<ul>
<li>多段に派生している場合、近い方ほど優先</li>
</ul>
</li>
<li>
暗黙的に変換できる型
<ul>
<li>その型が実装しているインターフェイス</li>
<li><a href="http://ufcpp.net/study/csharp/fun_WhyExtensions.html#cast">ユーザー定義の型変換</a>がある場合</li>
</ul>
</li>
<li><code>object</code></li>
</ul>
<p>型変換なしで渡せるものほど「一致」、
いろんな型を受け付けるものほど「不一致」です。</p>
<p>例えば以下のようなメソッド <code>M</code> を書いた場合、
上の方に書いたものほど優先的に呼ばれます。</p>
<pre class="source" title="引数の型の「一致度」の高さ">
<code><span class="reserved">using</span> System;

<span class="comment">// A → B → C の型階層</span>
<span class="comment">// IDisposable インターフェイスを実装</span>
<span class="comment">// C には int への暗黙的型変換あり</span>
<span class="reserved">class</span> <span class="type">A</span> : <span class="type">IDisposable</span> { <span class="reserved">public</span> <span class="reserved">void</span> Dispose() { } }
<span class="reserved">class</span> <span class="type">B</span> : A, <span class="type">IDisposable</span> { }
<span class="reserved">class</span> <span class="type">C</span> : B, <span class="type">IDisposable</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="reserved">int</span>(C x) =&gt; 0;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// M のオーバーロードがいくつかある中、C を引数にして呼び出す</span>
        M(<span class="reserved">new</span> C());
    }

    <span class="comment">// 上から順に候補になる。</span>
    <span class="comment">// 上の方を消さないと、下の方が呼ばれることはない。</span>

    <span class="comment">// 「そのもの」が当然1番一致度高い</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">C</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"C"</span>);

    <span class="comment">// 次がジェネリックなやつ。型変換が要らないので一致度が高いという扱い。</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"generic"</span>);

    <span class="comment">// 基底クラスは、階層が近い方が優先。この場合 B が先で、A が後</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">B</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"B"</span>);

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">A</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"A"</span>);

    <span class="comment">// 次に、インターフェイス、暗黙的型変換が同率。</span>
    <span class="comment">// (構造体の時の ValueType と違って、クラスは明確に基底クラスが上。)</span>
    <span class="comment">// この2つが同時に候補になってると ambiguous エラー</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">IDisposable</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"IDisposable"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">int</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int"</span>);

    <span class="comment">// 最後が object。</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">object</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"object"</span>);
}
</code></pre>
<p>型変換に関しては、候補が複数ある場合は、どちらを呼ぶべきか不明瞭なためコンパイル エラーになります。
例えば以下のコードはコンパイルできません。</p>
<pre class="source" title="不明瞭でオーバーロード解決できない例">
<code><span class="reserved">using</span> System;

<span class="comment">// インターフェイス実装とユーザー定義の型変換を持つ</span>
<span class="reserved">class</span> <span class="type">A</span> : <span class="type">IDisposable</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> Dispose() { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="reserved">int</span>(A x) =&gt; 0;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">IDisposable</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"IDisposable"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">int</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int"</span>);

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// インターフェイスへの変換と、ユーザー定義の型変換は同列</span>
        <span class="comment">// どちらを呼ぶべきか、このコードでは解決できない</span>
        <span class="error">M</span>(<span class="reserved">new</span> A());

        <span class="comment">// 明示的にキャストを書けば大丈夫</span>
        M((<span class="type">IDisposable</span>)<span class="reserved">new</span> A());
        M((<span class="reserved">int</span>)<span class="reserved">new</span> A());
    }
}
</code></pre>
<p>型の派生に関してはクラスのみです。
C# では、任意の<a href="/study/csharp/oo_reference.html#valtype">値型</a>は <code>System.ValueType</code> クラスから派生、任意の<a href="/study/csharp/st_enum.html">列挙型</a>は<code>System.Enum</code>クラスから派生しているように振る舞いますが、
これらはあくまで「それっぽく振る舞うようにコンパイラーが特殊対応している」というだけで、
実際には型変換の一種です。
そのため、以下のようなコードはコンパイル エラーになります。</p>
<pre class="source" title="ValueType への変換はインターフェイスへの変換と同列">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">S</span> : <span class="type">IDisposable</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> Dispose() { }
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// S は ValueType から派生しているかのように振る舞うものの、これはあくまで ValueType への型変換になる</span>
        <span class="comment">// インターフェイスへの変換と同列なので、以下の呼び出しは不明瞭</span>
        M(<span class="reserved">new</span> S());
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">IDisposable</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"IDisposable"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">ValueType</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"ValueType"</span>);
}
</code></pre>
<h3><a id="generic-method">ジェネリック メソッド</h3>
<p>C# では、「ジェネリックかどうか」だけの差があるメソッド オーバーロードも可能です。
この場合、非ジェネリックな方が優先的に呼ばれます。</p>
<pre class="source" title="非ジェネリックな方優先">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// M(string) の方が呼ばれる</span>
        M(<span class="string">"abc"</span>);

        <span class="comment">// M&lt;T&gt;(string) の方が呼ばれる</span>
        M&lt;<span class="reserved">int</span>&gt;(<span class="string">"abc"</span>);
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">string</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"M"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="reserved">string</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"M&lt;T&gt;"</span>);
}
</code></pre>
<h3><a id="optional">オプション引数・可変長引数</h3>
<p>C# には<a href="/study/csharp/sp4_optional.html#optional">オプション引数</a>と<a href="/study/csharp/sp_params.html">可変長引数</a>という、引数を省略できる仕組みが2つあります。
この場合、以下のリストの上の方ほど「一致度が高い」と判断されます。</p>
<ul>
<li>省略なくぴったり引数の数が一致しているもの</li>
<li>オプション引数による省略</li>
<li>可変長引数による省略</li>
</ul>
<pre class="source" title="引数の省略">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        M();
    }

    <span class="comment">// これが最優先</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M() =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"void"</span>);

    <span class="comment">// 次がこれ。既定値を与えたもの</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">int</span> x = 0) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int x = 0"</span>);

    <span class="comment">// 最後がこれ。params</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">params</span> <span class="reserved">int</span>[] x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"params int[]"</span>);
}
</code></pre>
<h3><a id="instance">インスタンス メソッド優先</h3>
<p>C# には<a href="/study/csharp/sp3_extension.html">拡張メソッド</a>という、
インスタンス メソッドと同じ書き方で静的メソッドを呼べます。
正確にはオーバーロードとは言わないんですが、
インスタンス メソッドと同名の拡張メソッドも定義できるので、
オーバーロードと同種の「解決」が必要になります。</p>
<p>この場合、インスタンス メソッドの方が優先です。
拡張メソッドの方を呼びたければ、本来の静的メソッドとして呼ぶ必要があります。</p>
<pre class="source" title="拡張メソッド">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> M() =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"instance"</span>);
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Extensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">this</span> A a) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"extension"</span>);
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// instance の方が呼ばれる</span>
        <span class="reserved">new</span> A().M();

        <span class="comment">// A 自身が M を持っている以上、↑の書き方で拡張メソッドの方は呼べない</span>
        <span class="comment">// 以下のように、普通に静的メソッドとして呼ぶ必要がある</span>
        <span class="type">Extensions</span>.M(<span class="reserved">new</span> A());
    }
}
</code></pre>
<h2><a id="inference">型推論とオーバーロード解決</h2>
<p>C# の構文にはいくつか、左辺値からの型推論をするものがあります。</p>
<ul>
<li>
<a href="/study/csharp/sp3_lambda.html">ラムダ式</a>
<ul>
<li>どのデリゲート型かの決定</li>
<li>デリゲートと、<a href="/study/csharp/sp3_lambda.html#expression">式ツリー</a></li>
</ul>
</li>
<li><a href="/study/csharp/st_string.html#string-interpolation">文字列補間</a></li>
<li><a href="/study/csharp/rm_default.html#default-expr"><code>default</code> 式</a></li>
</ul>
<p>推論に推論を重ねることになるので、これらの型を引数にした場合、オーバーロード解決ができない場合が増えます。</p>
<pre class="source" title="型推論が働かなくなる例">
<code><span class="reserved">using</span> System;

<span class="comment">// 引数が完全に一致しているデリゲート型を2個用意</span>
<span class="reserved">delegate</span> <span class="reserved">int</span> <span class="type">A</span>(<span class="reserved">int</span> x);
<span class="reserved">delegate</span> <span class="reserved">int</span> <span class="type">B</span>(<span class="reserved">int</span> x);

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// 2個以上候補があるときに default は使えない</span>
        <span class="error">M</span>(<span class="reserved">default</span>);

        <span class="comment">// 型推論とはちょっと違うものの、null (型がない。どの型にでも代入可)でも同様</span>
        <span class="error">M</span>(<span class="reserved">null</span>);

        <span class="comment">// 型指定ありの default なら大丈夫</span>
        M(<span class="reserved">default</span>(<span class="type">A</span>));

        <span class="comment">// A なのか B なのか区別がつかない</span>
        <span class="error">M</span>(x =&gt; x);

        <span class="comment">// キャストがあれば大丈夫</span>
        <span class="comment">// new でも可</span>
        M((<span class="type">A</span>)(x =&gt; x));
        M(<span class="reserved">new</span> <span class="type">A</span>(x =&gt; x));
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">A</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"A"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">B</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"B"</span>);
}
</code></pre>
<p>文字列補完では、<code>string</code>型で受け取る場合と<code>FormattableString</code>で受け取る場合で異なる挙動になりますが、
<code>var</code>を使った暗黙的変数宣言では自動的に<code>string</code>扱いされます。
そのため、オーバーロード解決でも特にキャストがない場合、<code>string</code>が優先されます。</p>
<pre class="source" title="文字列補間">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> (a, b) = (1, 2);

        <span class="comment">// M(string) の方が呼ばれる</span>
        M(<span class="string">$"</span>{a}<span class="string">, </span>{b}<span class="string">"</span>);

        <span class="comment">// こう書けば M(FormattableString) の方</span>
        M((<span class="type">FormattableString</span>)<span class="string">$"</span>{a}<span class="string">, </span>{b}<span class="string">"</span>);
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">string</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"string"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">FormattableString</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"FormattableString"</span>);
}
</code></pre>
<p>同様に、ラムダ式は、デリゲート型で受け取る場合と式ツリーで受け取る場合で異なる挙動になります。
こちらは推論は効かず、オーバーロード解決もできなくなります。</p>
<pre class="source" title="式ツリー">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Linq.Expressions;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        M(x =&gt; x);
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; f) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Func"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Expression</span>&lt;<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;&gt; f) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Expression"</span>);
}
</code></pre>
<p>ただし、次節で説明しますが、ラムダ式の型推論は結構優秀で、
ちゃんと推論が働きつつ、オーバーロード解決できる場合も多いです。</p>
<h2><a id="lambda">ラムダ式</h2>
<p>ラムダ式の型推論は相当優秀で、結構複雑なオーバーロード解決もできたりします。
例えば、以下の <code>M(x =&gt; x)</code> はちゃんとコンパイルできます。</p>
<pre class="source" title="ラムダ式とオーバーロード解決">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// x の素通し = 引数と戻り値が一致 = Fucn&lt;int, int&gt; の方だけなのでそっちが選ばれる</span>
        <span class="comment">// x の型は int に</span>
        M(x =&gt; x);

        <span class="comment">// 明示的に double を返すと Func&lt;int, double&gt; の方が選ばれる</span>
        <span class="comment">// x の型は int に</span>
        M(x =&gt; (<span class="reserved">double</span>)x);

        <span class="comment">// この場合、引数と戻り値が一致してるという条件では int なのか string なのか区別できなくてエラー</span>
        <span class="error">N</span>(x =&gt; x);
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int → int"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">double</span>&gt; x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int → double"</span>);

    <span class="reserved">static</span> <span class="reserved">void</span> N(<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int → int"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> N(<span class="type">Func</span>&lt;<span class="reserved">string</span>, <span class="reserved">string</span>&gt; x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int → int"</span>);
}
</code></pre>
<h5 class="version version6">Ver. 6.0</h5>
<p>ちなみに、ラムダ式がらみの型推論/オーバーロード解決は、C# 6.0 で少し改良がありました。
以下のように、多段のラムダ式でちゃんとオーバーロード解決できるようになったのは C# 6.0 からです。
また、「匿名メソッド式はラムダ式と違って式ツリーにならない」という条件が加味されたのも C# 6.0 からです。</p>
<pre class="source" title="多段のラムダ式など">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Linq.Expressions;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// M(() =&gt; { }) だと Action か Expression&lt;Action&gt; か区別つかないものの</span>
        <span class="comment">// 匿名メソッド式の場合は式ツリー化できない仕様なので、M(Action) で確定</span>
        <span class="comment">// なのに以前はこれもエラーになってた(C# 6.0 からは M(Action) が呼ばれる)</span>
        M(<span class="reserved">delegate</span> () { });

        <span class="comment">// 以下のような、多段のラムダ式でちゃんとオーバーロード解決できるのは C# 6.0 から</span>
        <span class="comment">// Func&lt;int, Func&lt;int&gt;&gt; の方</span>
        M(() =&gt; () =&gt; 1);
        <span class="comment">// Func&lt;int, Func&lt;double&gt;&gt; の方</span>
        M(() =&gt; () =&gt; 1.0);
    }

    <span class="comment">// ラムダ式だと区別できないものの、匿名メソッド式なら Action で確定</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Action</span>x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Action"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Expression</span>&lt;<span class="type">Action</span>&gt; x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Expression"</span>);

    <span class="comment">// () =&gt; () =&gt; 1 みたいな、多段のラムダ式</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="type">Func</span>&lt;<span class="reserved">int</span>&gt;&gt; x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"() → () → int"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="type">Func</span>&lt;<span class="reserved">double</span>&gt;&gt; x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"() → () → int"</span>);
}
</code></pre>
<!-- pageBreak -->
<h2><a id="remove-redundant">オーバーロード候補の絞り込み</h2>
<h5 class="version version7">Ver. 7.3</h5>
<p>C# 7.3で、オーバーロード解決の改善がありました。
以下の3つの改善があります。</p>
<ul>
<li>静的メソッドかインスタンス メソッドかの違いで解決できるようになった</li>
<li>ジェネリック型制約の違いで解決できるようになった</li>
<li><a href="/study/csharp/st_function.html#key-method-group">メソッド グループ</a>を引数にするとき、メソッドの戻り値を見るようになった</li>
</ul>
<p>実のところ、これらの改善は「処理手順の順序変更」だそうです。
(今までも、これからも)オーバーロード解決に際して、C# コンパイラーは以下の2つの処理を行っていますが、
この順序を入れ替えることで上記のような区別がつくようになります。</p>
<ol>
<li>前述のような、引数の数や型の一致度を調べて最も一致するものを探す</li>
<li>本当にそのメソッドを呼べるかどうかを調べる(上記の、静的/インスタンスの差や、型制約を調べる)</li>
</ol>
<p>例えば、以下のコードを見てください。
同名の静的メソッドとインスタンス メソッドを1つずつ定義していますが、
間違った引数で呼び出しています。</p>
<pre class="source" title="同名の静的メソッドとインスタンス メソッド">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Static</span> { }
<span class="reserved">struct</span> <span class="type">Instance</span> { }

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// 同名で、片方は静的メソッドで、もう片方はインスタンス メソッド。</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Static</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Static"</span>);
    <span class="reserved">void</span> M(<span class="type">Instance</span> x) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Instance"</span>);

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// 型名.M() で呼べるのは静的メソッドだけのはず。</span>
        <span class="comment">// でも、エラー メッセージとしては「M(Instance) を呼ぶにはインスタンスが必要」の類。</span>
        <span class="error"><span class="type">Program</span>.M</span>(<span class="reserved">new</span> <span class="type">Instance</span>());

        <span class="comment">// インスタンス.M() で呼べるのはインスタンス メソッドだけのはず。</span>
        <span class="comment">// でも、エラー メッセージとしては「M(Static) を呼ぶにはインスタンス越しじゃダメ」の類。</span>
        <span class="error"><span class="reserved">new</span> <span class="type">Program</span>().M</span>(<span class="reserved">new</span> <span class="type">Static</span>());

        <span class="comment">// つまり、引数の型でのオーバーロード解決を先にやって、その後、静的/インスタンスの区別を調べてる。</span>
    }
}
</code></pre>
<p>静的かインスタンスかの差をよりも先に、引数の型だけでオーバーロード解決しています。
なので、<code>Program.M(new Instance())</code>と呼ぼうが、<code>M(Instance x)</code>の方がまず選ばれます。
そして、「<code>M(Instance x)</code>はインスタンス メソッドなので、<code>型名.M</code>では呼べない」というエラーになります。</p>
<p>C# 7.3でこの順を逆にして、引数の型でオーバーロード解決をする前に、静的かインスタンスかなどの条件を先に見るようになりました。
呼べないことがわかるんだったら最初からオーバーロード解決候補から外して欲しいわけで、
ある意味当然の変更でしょう。</p>
<h3><a id="static-instance">静的メソッドかインスタンス メソッドか</h3>
<p>前節の例に、引数の既定値を足してみましょう。
2つのメソッド<code>M</code>が、どちらも<code>M()</code>で呼べるようになります。
C# 7.3からは、これらの呼び分けができるようになりました。</p>
<pre class="source" title="静的メソッドかインスタンス メソッドかでオーバーロード解決">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Static</span> { }
<span class="reserved">struct</span> <span class="type">Instance</span> { }

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// 既定値が入っているのでどちらも M() で呼べる。</span>
    <span class="comment">// 片方は静的メソッドで、もう片方はインスタンス メソッド。</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Static</span> x = <span class="reserved">default</span>) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Static"</span>);
    <span class="reserved">void</span> M(<span class="type">Instance</span> x = <span class="reserved">default</span>) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Instance"</span>);

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// 型名.M() で呼べるのは静的メソッドだけのはず。</span>
        <span class="comment">// でも、これまでは、M(Static) か M(Instance) かの区別がつかなかった。</span>
        <span class="comment">// C# 7.3 では M(Static) が選ばれるように。</span>
        <span class="type">Program</span>.M();

        <span class="comment">// インスタンス.M() で呼べるのはインスタンス メソッドだけのはず。</span>
        <span class="comment">// 同上。</span>
        <span class="comment">// C# 7.3 では M(Instance) が選ばれるように。</span>
        <span class="reserved">new</span> <span class="type">Program</span>().M();

        <span class="comment">// Main が静的メソッドなので、何もつけない場合、この M() も静的な方が呼ばれる。</span>
        M();
    }

    <span class="reserved">void</span> InstanceMethod()
    {
        <span class="comment">// でも、これはダメ。</span>
        <span class="comment">// 静的な方もインスタンスの方も M() で呼べるので不明瞭。</span>
        <span class="error">M</span>();

        <span class="comment">// これなら OK。</span>
        <span class="comment">// this. が付いているのでインスタンス メソッドに絞られる。</span>
        <span class="reserved">this</span>.M();
    }
}
</code></pre>
<h4><a id="color-color">余談: Color Color 問題</h4>
<p>C# では、型名とプロパティ名が同じプロパティを作ることができます。
もっともありがちな例が「<code>Color</code>構造体型の<code>Color</code>プロパティ」なので、「Color Color問題」と呼ばれます。</p>
<p>C# 7.3での静的メソッドとインスタンス メソッドの呼び分けによって、
Color Color問題下においても呼び分けできるようになったものもあります。
しかし、C# 7.3でも解決できないものもあります。</p>
<p>例えば以下の例の通りです。
末尾の2つはC# 7.3でだけコンパイルできるコード、
真ん中の <code>Color.M()</code> はC# 7.3でもコンパイルできないコードになります。</p>
<pre class="source" title="">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Color</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> R;
    <span class="reserved">public</span> <span class="reserved">byte</span> G;
    <span class="reserved">public</span> <span class="reserved">byte</span> B;

    <span class="comment">// どちらも M() で呼べるメソッド。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> M(<span class="reserved">int</span> x = 0) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"Instance"</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Color</span> c = <span class="reserved">default</span>) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"static"</span>);

    <span class="comment">// 参考までに、オーバーロードがない場合。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> Instance() { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> Static() { }
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// C# では、型名とプロパティ名が同じプロパティを作れる。</span>
    <span class="reserved">static</span> Color Color { <span class="reserved">get</span>; <span class="reserved">set</span>; }

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// これは「プロパティのColor」(C# 7.2以前でも行ける)。</span>
        Color.Instance();

        <span class="comment">// これが「型のColor」(C# 7.2以前でも行ける)。</span>
        <span class="type">Color</span>.Static();

        <span class="comment">// これだと、この Color が型名かプロパティかが区別できない。</span>
        <span class="comment">// C# 7.3 でも不明瞭エラー。</span>
        Color.<span class="error">M</span>();

        <span class="comment">// C# 7.3 なら、以下の書き方で呼び分け可能(これまでは不明瞭エラー)。</span>
        <span class="comment">// 「プロパティのColor」。</span>
        <span class="type">Program</span>.Color.M();
        <span class="comment">// 「型のColor」。</span>
        <span class="reserved">global</span>::<span class="type">Color</span>.M();
    }
}
</code></pre>
<h3><a id="constraints">ジェネリック型制約</h3>
<p>ジェネリック メソッドで、型制約だけが違うメソッドのオーバーロード解決ができるようにもなりました。</p>
<pre class="source" title="型制約での呼び分け">
<code><span class="reserved">using</span> System;

<span class="comment">// オーバーロード用のダミー型</span>
<span class="reserved">struct</span> <span class="type">A</span> { }
<span class="reserved">struct</span> <span class="type">B</span> { }

<span class="comment">// IDisposable, IComparable な型を用意</span>
<span class="reserved">struct</span> <span class="type">Disposable</span> : <span class="type">IDisposable</span> { <span class="reserved">public</span> <span class="reserved">void</span> Dispose() { } }
<span class="reserved">struct</span> <span class="type">Comparable</span> : <span class="type">IComparable</span> { <span class="reserved">public</span> <span class="reserved">int</span> CompareTo(<span class="reserved">object</span> x) =&gt; 0; }

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// M(x) で呼べるメソッドが2つ。</span>
    <span class="comment">// 差は、T の型制約のみ。</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="type">A</span> _ = <span class="reserved">default</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="type">IDisposable</span> { }
    <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="type">B</span> _ = <span class="reserved">default</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="type">IComparable</span> { }

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// C# 7.3 からこの呼び出し方ができるように。</span>
        M(<span class="reserved">new</span> <span class="type">Disposable</span>());
        M(<span class="reserved">new</span> <span class="type">Comparable</span>());

        <span class="comment">// この書き方も C# 7.3 から。</span>
        M(<span class="reserved">new</span> <span class="type">Disposable</span>(), <span class="reserved">default</span>); <span class="comment">// default は default(A) に推論される</span>
        M(<span class="reserved">new</span> <span class="type">Comparable</span>(), <span class="reserved">default</span>); <span class="comment">// default は default(B) に推論される</span>

        <span class="comment">// C# 7.2 以前の場合、こう書くのが必須。</span>
        M(<span class="reserved">new</span> <span class="type">Disposable</span>(), <span class="reserved">default</span>(<span class="type">A</span>));
        M(<span class="reserved">new</span> <span class="type">Comparable</span>(), <span class="reserved">default</span>(<span class="type">B</span>));
    }
}
</code></pre>
<p>特に、参照型(class)か値型(struct)かによるオーバーロード解決は便利そうです。
例えば、「条件を満たさなければnullを返す」みたいなメソッドを書きたい場合、
値型の時だけ<a href="/study/csharp/sp2_nullable.html">null許容型</a>にして、<code>?</code>を付ける必要があります。
この呼び分けが、これまでだとなかなか難しかったですが、C# 7.3ではできるようになります。</p>
<pre class="source" title="class 制約と struct 制約の呼び分け">
<code><span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Linq;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">ClassExtensions</span>
{
    <span class="comment">// クラスの場合は LINQ の FirstOrDefault そのまま。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">T</span> FirstOrNull&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source)
        <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span>
        =&gt; source.FirstOrDefault();
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">StructExtensions</span>
{
    <span class="comment">// 構造体の場合は null 許容型に変える必要がある。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">T</span>? FirstOrNull&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source)
        <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span>
        =&gt; source.Select(x =&gt; (<span class="type">T</span>?)x).FirstOrDefault();
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// ClassExtensions の方のが呼ばれる。</span>
        <span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"b"</span>, <span class="string">"c"</span> }.FirstOrNull();

        <span class="comment">// StructExtensions の方のが呼ばれる。</span>
        <span class="reserved">new</span>[] { 1, 2, 3 }.FirstOrNull();
    }
}
</code></pre>
<h3><a id="method-return">メソッドの戻り値</h3>
<p>C# (というか、.NET)のメソッドは、戻り値の型を<a href="/study/csharp/st_function.html#key-signature">シグネチャ</a>に含みません。
基本的に、戻り値だけが違うメソッドは定義できませんし、呼び分けもできません。</p>
<p>ただ、これまでの例でもたびたび出てきたように、引数の規定値を与えることで戻り値だけが違う「っぽく見える」メソッド オーバーロードはできます。
また、以下のように、「戻り値違いのデリゲートを受け取るメソッド」は作れます。</p>
<pre class="source" title="戻り値違いのデリゲートを受け取るメソッド オーバーロード">
<code><span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="reserved">int</span>&gt; f) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int"</span>);
<span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="reserved">string</span>&gt; f) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"string"</span>);
</code></pre>
<p><a href="/study/csharp/structured/miscoverloadresolution#lambda">前述の通り</a>、
ラムダ式であれば、ラムダ式の型推論が賢くて、この2つのメソッドの呼び分けができました。</p>
<pre class="source" title="ラムダ式は賢い">
<code>M(() =&gt; 0); <span class="comment">// int の方</span>
M(() =&gt; <span class="string">"abc"</span>); <span class="comment">// string の方</span>
</code></pre>
<p>しかし、メソッド グループを引数に渡した場合、これまではオーバーロード解決できませんでした。
それが、以下のように、C# 7.3からはオーバーロード解決できるようになります。</p>
<pre class="source" title="メソッドの戻り値でオーバーロード解決">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="reserved">int</span>&gt; f) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"int"</span>);
    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Func</span>&lt;<span class="reserved">string</span>&gt; f) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"string"</span>);

    <span class="reserved">static</span> <span class="reserved">int</span> IntReturn() =&gt; 0;
    <span class="reserved">static</span> <span class="reserved">string</span> StringReturn() =&gt; <span class="string">""</span>;

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// ラムダ式賢い。</span>
        M(() =&gt; 0); <span class="comment">// int の方</span>
        M(() =&gt; <span class="string">"abc"</span>); <span class="comment">// string の方</span>

        <span class="comment">// こういう書き方なら C# 7.2 まででもできた。</span>
        M(() =&gt; IntReturn());
        M(() =&gt; StringReturn());

        <span class="comment">// なのに、以下のような書き方はこれまでできなかった。</span>
        <span class="comment">// C# 7.3 からできるように。</span>
        M(IntReturn);
        M(StringReturn);
    }
}
</code></pre>
<h3><a id="signature-trick">余談: 同一シグネチャのメソッド オーバーロード</h3>
<p>ここで説明してきたように、C# 7.3から静的メソッドかインスタンス メソッドかや、
ジェネリック型制約の差でオーバーロード解決できるようになりました。</p>
<p>呼び分けできるようになったんなら、そもそもオーバーロードもできていいはずではあります。
しかし、静的/インスタンス違いや型制約違いでオーバーロードを作れないのは、
C# ではなく、.NET 型システムの制約です。
単に C# コンパイラーだけの仕事ではないので、これを修正するのは少し難しいです。
そのため、これは引き続き認められていません。</p>
<pre class="source" title="制約違いのオーバーロードは不可">
<code><span class="comment">// 以下の2つは呼び分けできるようになった。</span>
<span class="comment">// なのに、定義はできない(C# コンパイラーだけの問題じゃないので直せない)。</span>
<span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span> { }
<span class="reserved">static</span> <span class="reserved">void</span> <span class="error">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span> { }
</code></pre>
<p>ただし、これまで挙げてきた例で少し出てきていますが、
「ごまかす」方法がいくつかあります。</p>
<p>1つは<a href="/study/csharp/sp4_optional.html#optional">オプション引数</a>(引数の規定値)や<a href="/study/csharp/sp_params.html">可変長引数</a>を使う方法で、以下のような書き方で「違うオーバーロードなんだけど、実質的には同じ呼び方ができる」と言うようなメソッドを定義できます。</p>
<pre class="source" title="オプション引数をダミーにして疑似的に同シグネチャ オーバーロードを実現">
<code><span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// 呼び分け用のダミー型</span>
    <span class="reserved">struct</span> <span class="type">Struct</span> { }
    <span class="reserved">struct</span> <span class="type">Class</span> { }

    <span class="comment">// ダミー引数を足すことでオーバーロードする。</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="type">Struct</span> _ = <span class="reserved">default</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span> { }
    <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="type">Class</span> _ = <span class="reserved">default</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span> { }

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        M(1);     <span class="comment">// M(T, Struct) が呼ばれる</span>
        M(<span class="string">"abc"</span>); <span class="comment">// M(T, Class) が呼ばれる</span>
    }
}
</code></pre>
<p>もう1つは拡張メソッドを使う方法です。
拡張メソッドであれば、別のクラス中で定義してやれば、同じ型を対象とした全く同じシグネチャのメソッドを定義できます。</p>
<pre class="source" title="拡張メソッドで同シグネチャ オーバーロードを実現">
<code><span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Linq;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">ClassExtensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">T</span> FirstOrNull&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source)
        <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span>
        =&gt; source.FirstOrDefault();
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">StructExtensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">T</span>? FirstOrNull&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source)
        <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span>
        =&gt; source.Select(x =&gt; (<span class="type">T</span>?)x).FirstOrDefault();
}
</code></pre>
<p>また、<code>ref</code>の有無が違うだけの拡張メソッドでもオーバーロード可能です。</p>
<pre class="source" title="ref の有無でオーバーロード">
<code><span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Extensions</span>
{
    <span class="comment">// ref の有無の差 + 型制約</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="reserved">ref</span> <span class="type">T</span> x) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span> { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">T</span> x) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span> { }
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="string">"abc"</span>.M();

        <span class="reserved">var</span> x = 123;
        x.M();
        <span class="comment">// ただ、ref 拡張メソッドの性質上、123.M() とは呼べない(リテラルがダメ)</span>
        <span class="comment">// また、DateTime.Now.M() とかもダメ(プロパティ越しがダメ)</span>
    }
}
</code></pre>
<p>いずれも疑似的なもので、ダミーなしのオーバーロードと比べると利便性は下がりますが、
C# 7.3で呼び分けができるようになったことで、少し使い勝手はよくなりました。</p>
<!-- pageBreak -->
<h2><a id="overload-resolution-priority">OverloadResolutionPriority 属性</a></h2>
<p>C# 13 で、オーバーロードの解決優先度を属性を付けて明示できる機能が入りました。
<code>OverloadResolutionPriority</code> 属性(<code>System.Runtime.CompilerServices</code> 名前空間)を使います。
名前通り優先度を指定できて、正の整数を指定すると優先度が上がって、負の整数なら下がります。</p>
<pre class="source" title="オーバーロード解決の優先度を変更する例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// IEnumerable&lt;char&gt; の方が選ばれる。</span>
<span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">M1</span></span>(<span class="string">&quot;&quot;</span>);
<span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">M2</span></span>(<span class="string">&quot;&quot;</span>);

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// 通常、インターフェイスよりも具体的な型の方が優先。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M1</span></span>(<span class="reserved">string</span> <span class="variable local">_</span>) { }

    <span class="comment">// 属性を付けて優先度を上げる。</span>
    [<span class="type">OverloadResolutionPriority</span>(<span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M1</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">_</span>) { }

    <span class="comment">// 属性を付けて優先度を下げる。</span>
    [<span class="type">OverloadResolutionPriority</span>(<span class="operator">-</span><span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M2</span></span>(<span class="reserved">string</span> <span class="variable local">_</span>) { }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M2</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<p>ちなみに、オーバーロードできないメンバーにこの属性を付けるとコンパイル エラーになります。</p>
<pre class="source" title="オーバーロードできないメンバーに OverloadResolutionPriority を付けるとコンパイラーに怒られる">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">namespace</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices
{
    <span class="comment">// .NET 標準ライブラリ中の OverloadResolutionPriorityAttribute には</span>
    <span class="comment">// AttributeTargets.Method | Constructor | Property がついてる。</span>
    <span class="comment">// ここではあえてターゲットの制限を外した同名・同名前空間の型を定義。</span>
    <span class="reserved">public</span> <span class="reserved">sealed</span> <span class="reserved">class</span> <span class="type">OverloadResolutionPriorityAttribute</span>(<span class="reserved">int</span> <span class="variable local">priority</span>) : <span class="type">Attribute</span>
    {
        <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Priority</span> <span class="operator">=&gt;</span> <span class="variable local">priority</span>;
    }
}

<span class="reserved">class</span> <span class="type">C</span>
{
    [<span class="error" title="CS9262"><span class="type">OverloadResolutionPriority</span>(<span class="number">0</span>)</span>]
    <span class="reserved">static</span> <span class="static"><span class="type">C</span></span>() { }

    [<span class="error" title="CS9262"><span class="type">OverloadResolutionPriority</span>(<span class="number">0</span>)</span>]
    <span class="operator">~</span><span class="type">C</span>() { }

    [<span class="error" title="CS9262"><span class="type">OverloadResolutionPriority</span>(<span class="number">0</span>)</span>]
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">X</span> { <span class="reserved">get</span>; }

    [<span class="error" title="CS9262"><span class="type">OverloadResolutionPriority</span>(<span class="number">0</span>)</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="reserved">int</span>(<span class="type">C</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span><span class="operator">!</span>;
}
</pre>
<h3><a id="binary-compat">互換性問題</a></h3>
<p>C# の言語機能が増えるにつれて、例えば「<code>IEnumerable&lt;T&gt;</code> よりも、<code>ReadOnlySpan&lt;T&gt;</code> 引数を使いたい」みたいなことが多々あります。
しかし、以前からあるメソッドを消すことができなくて、それは残したまま新しいオーバーロードを追加することになったりします。
(ライブラリ作者、特に、プラグイン提供するような場合、バイナリ互換(ソースコードの再コンパイルなしでも動く保証)を残すため、メソッドの削除はできなくなります。)
ところが、互換性のために消すに消せない方のメソッドが、優先度が高すぎて困ったり、
オーバーロード解決できなくなって困るということが起こるようになってきました。</p>
<p><code>IEnumerable&lt;T&gt;</code> と <code>ReadOnlySpan&lt;T&gt;</code> の場合、C# 13 時点ではオーバーロード解決できなくなって困ります。
(この2者の問題であれば、C# 14 で <code>Span&lt;T&gt;</code>/<code>ReadOnlySpan&lt;T&gt;</code> の特別扱いが入って問題解消する予定です。)</p>
<pre class="source" title="">
<span class="comment">// C# 13 時点だと IEnumerable と ReadOnlySpan を選べなくてコンパイル エラーになる。</span>
<span class="type">C</span><span class="operator">.</span><span class="method"><span class="error" title="CS0121"><span class="static">M</span></span></span>(<span class="reserved">new</span> <span class="reserved">int</span>[<span class="number">1</span>]);

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }

    <span class="comment">// ReadOnlySpan は C# 7.2 / .NET Core 2.1 / 2017年頃に入った。</span>
    <span class="comment">// パフォーマンス的に有利なので IEnumerable を置き換えたいことがある。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<p>他に、デフォルト引数が絡んだ場合に困ったりします。
具体的には、<code>Debug.Assert</code> や文字列がらみで困っているみたいです。</p>
<p><code>Debug.Assert</code> は、C# 10 で導入された <a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver10/#CallerArgumentExpression"><code>CallerArgumentExpression</code></a> を使いたいものの、既存のオーバーロードに阻害されて呼びようがないという問題が出ています。</p>
<pre class="source" title="CallerArgumentExpression 付きのオーバーロードを呼べない問題">
<span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">int</span><span class="operator">.</span><span class="method"><span class="static">Parse</span></span>(<span class="static"><span class="type">Console</span><span class="operator">.</span><span class="static"><span class="method">ReadLine</span></span>()</span>);

<span class="comment">// Debug.Assert(x &gt; 0, &quot;x &gt; 0&quot;) になってほしいのに、1引数の方が呼ばれちゃう。</span>
<span class="type">Debug</span><span class="operator">.</span><span class="static"><span class="method">Assert</span></span>(<span class="variable">x</span> <span class="operator">&gt;</span> <span class="number">0</span>);

<span class="comment">// System.Diagnostics.Debug からの抜粋</span>
<span class="reserved">class</span> <span class="type">Debug</span>
{
    <span class="comment">// 元々 bool 1引数のオーバーロードがある。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Assert</span></span>(<span class="reserved">bool</span> <span class="variable local">condition</span>) { }

    <span class="comment">// C# 10 で導入された CallerArgumentExpression を使いたい。</span>
    <span class="comment">// けど、 Assert(condition) では1引数オーバーロードの方が優先されて、CallerArgumentExpression が役に立たない。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Assert</span></span>(<span class="reserved">bool</span> <span class="variable local">condition</span>, [<span class="type">CallerArgumentExpression</span>(<span class="reserved">nameof</span>(<span class="variable local">condition</span>))] <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">message</span> <span class="operator">=</span> <span class="reserved">null</span>) { }
}
</pre>
<p>文字列がらみは、
.NET の負の遺産として有名なカルチャー依存問題(参考: <a href="https://ufcpp.net/blog/2023/3/string-order/">遅い</a>、<a href="https://ufcpp.net/blog/2020/11/net5_0ga/">環境依存</a>)への対処として、<code>IndexOf</code> などのメソッドにデフォルト引数 <code>StringComparison comparisonType = StringComparison.Ordinal</code> を付けて、無指定の時の挙動を <code>Ordinal</code> に変えたいという話があります。
しかしこれも、1引数オーバーロードの方が優先度が高くてうまく働きません。</p>
<pre class="source" title="">
<span class="comment">// IndexOf(value, StringComparison.Ordinal) で呼ばれてほしいけど、</span>
<span class="comment">// 残念ながら IndexOf(value) にしかならない。</span>
<span class="type"><span class="static">String</span></span><span class="operator">.</span><span class="method"><span class="static">IndexOf</span></span>(<span class="string">&quot;àèò&quot;</span>, <span class="string">&quot;a&quot;</span>);

<span class="comment">// 本来は string クラスのインスタンスメソッド。デモ用に静的メソッド。</span>
<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">String</span></span>
{
    <span class="comment">// 1引数オーバーロードがいるので…</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">IndexOf</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">string</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="variable local">s</span><span class="operator">.</span><span class="method">IndexOf</span>(<span class="variable local">value</span>);

    <span class="comment">// デフォルト引数を付けたところで IndexOf(string value) の方が優先される。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">IndexOf</span></span>(
        <span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">string</span> <span class="variable local">value</span>,
        <span class="type">StringComparison</span> <span class="variable local">comparisonType</span> <span class="operator">=</span> <span class="type">StringComparison</span><span class="operator">.</span>Ordinal) <span class="comment">// Ordinal をデフォルトに変えたい。</span>
        <span class="operator">=&gt;</span> <span class="variable local">s</span><span class="operator">.</span><span class="method">IndexOf</span>(<span class="variable local">value</span>, <span class="variable local">comparisonType</span>);
}
</pre>
<p>これらの問題に <code>OverloadResolutionPriority</code> 属性が使えます。</p>
<pre class="source" title="IEnumerable の優先度を下げる">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>(<span class="reserved">new</span> <span class="reserved">int</span>[<span class="number">1</span>]); <span class="comment">// 無事、ReadOnlySpan の方が選ばれる。</span>

<span class="reserved">class</span> <span class="type">C</span>
{
    [<span class="type">OverloadResolutionPriority</span>(<span class="operator">-</span><span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<pre class="source" title="1引数オーバーロードの優先度を下げる">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">int</span><span class="operator">.</span><span class="method"><span class="static">Parse</span></span>(<span class="static"><span class="type">Console</span><span class="operator">.</span><span class="method"><span class="static">ReadLine</span></span>()</span>);

<span class="comment">// 無事、 Debug.Assert(x &gt; 0, &quot;x &gt; 0&quot;) で呼ばれる。</span>
<span class="type">Debug</span><span class="operator">.</span><span class="method"><span class="static">Assert</span></span>(<span class="variable">x</span> <span class="operator">&gt;</span> <span class="number">0</span>);

<span class="reserved">class</span> <span class="type">Debug</span>
{
    [<span class="type">OverloadResolutionPriority</span>(<span class="operator">-</span><span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Assert</span></span>(<span class="reserved">bool</span> <span class="variable local">condition</span>) { }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">Assert</span></span>(<span class="reserved">bool</span> <span class="variable local">condition</span>, [<span class="type">CallerArgumentExpression</span>(<span class="reserved">nameof</span>(<span class="variable local">condition</span>))] <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">message</span> <span class="operator">=</span> <span class="reserved">null</span>) { }
}
</pre>
<pre class="source" title="1引数オーバーロードの優先度を下げる">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// 無事、IndexOf(value, StringComparison.Ordinal) で呼ばれる。</span>
<span class="static"><span class="type">String</span></span><span class="operator">.</span><span class="static"><span class="method">IndexOf</span></span>(<span class="string">&quot;àèò&quot;</span>, <span class="string">&quot;a&quot;</span>);

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">String</span></span>
{
    [<span class="type">OverloadResolutionPriority</span>(<span class="operator">-</span><span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">IndexOf</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">string</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="variable local">s</span><span class="operator">.</span><span class="method">IndexOf</span>(<span class="variable local">value</span>);

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">IndexOf</span></span>(
        <span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">string</span> <span class="variable local">value</span>,
        <span class="type">StringComparison</span> <span class="variable local">comparisonType</span> <span class="operator">=</span> <span class="type">StringComparison</span><span class="operator">.</span>Ordinal) <span class="comment">// Ordinal をデフォルトに変えたい。</span>
        <span class="operator">=&gt;</span> <span class="variable local">s</span><span class="operator">.</span><span class="method">IndexOf</span>(<span class="variable local">value</span>, <span class="variable local">comparisonType</span>);
}
</pre>
<p>ちなみに、<code>OverloadResolutionPriority</code> で優先度を下げたメソッドを呼び出すのはかなり困難になったりします。
場合によっては真っ当な方法で呼ぶ手段がなく、リフレクションや unsafe な手段でしか呼べなくなります。</p>
<pre class="source" title="優先度を下げたせいで真っ当な手段では呼べず &amp; 真っ当じゃない手段で呼ぶ例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// OverloadResolutionPriority(-1) のせいで、真っ当な方法ではどうやっても M(string) の方を呼べない。</span>
<span class="type">C</span><span class="operator">.</span><span class="static"><span class="method">M</span></span>((<span class="reserved">string</span>)<span class="string">&quot;&quot;</span>);

<span class="comment">// リフレクションとか Unsafe な手段を使えば一応呼べなくはない。</span>
[<span class="type">UnsafeAccessor</span>(<span class="type">UnsafeAccessorKind</span><span class="operator">.</span>StaticMethod, <span class="property">Name</span> <span class="operator">=</span> <span class="reserved">nameof</span>(<span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>))]
<span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">C</span><span class="operator">?</span> <span class="variable local">c</span>, <span class="reserved">string</span> <span class="variable local">_</span>);
<span class="static"><span class="method">M</span></span>(<span class="reserved">default</span>, <span class="string">&quot;&quot;</span>);

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">object</span> <span class="variable local">_</span>) <span class="operator">=&gt;</span> <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;object&quot;</span>);

    [<span class="type">OverloadResolutionPriority</span>(<span class="operator">-</span><span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">string</span> <span class="variable local">_</span>) <span class="operator">=&gt;</span> <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="string">&quot;string&quot;</span>);
}
</pre>
<h3><a id="in-a-type">同一クラス内でのみ有効</a></h3>
<p><code>OverloadResolutionPriority</code> 属性による優先度の変更は、同一クラス内においてのみ有効です。
なので、以下のようなことは<em>できません</em>。</p>
<ul>
<li>拡張メソッドでインスタンス メソッドを乗っ取り</li>
<li>自作の拡張メソッドで他人の拡張メソッドを乗っ取り</li>
<li>派生クラス内のオーバーロードで基底クラスのメソッドを乗っ取り</li>
</ul>
<p>例えば以下のような所業はできません。</p>
<pre class="source" title="Linq 乗っ取りを画策">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// わざと System.Linq.Enumerable と競合するようにして、</span>
<span class="reserved">namespace</span> System<span class="operator">.</span>Linq;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">FakeLinq</span></span>
{
    <span class="comment">// 優先度を最大限引き上げ。</span>
    [<span class="type">OverloadResolutionPriority</span>(<span class="reserved">int</span><span class="operator">.</span><span class="static"><span class="constant">MaxValue</span></span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type param">TResult</span>&gt; <span class="method"><span class="static">Select</span></span>&lt;<span class="type param">TSource</span>, <span class="type param">TResult</span>&gt;(
        <span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type param">TSource</span>&gt; <span class="variable local">source</span>, <span class="type">Func</span>&lt;<span class="type param">TSource</span>, <span class="type param">TResult</span>&gt; <span class="variable local">selector</span>)
        <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>(<span class="string">&quot;Select は乗っ取った&quot;</span>);
}
</pre>
<pre class="source" title="ただし、実際にやってみるとうまくいかない(当然)">
<span class="comment">// FakeLinq の方が優先されたりはしない。</span>
<span class="comment">// 単に「Enumerable と FakeLinq 間で不明瞭」エラーに。</span>
<span class="string">&quot;abc&quot;</span><span class="operator">.</span><span class="method"><span class="error" title="CS0121">Select</span></span>(<span class="variable local">c</span> <span class="operator">=&gt;</span> (<span class="reserved">int</span>)<span class="variable local">c</span>);
</pre>
<p>また、<code>OverloadResolutionPriority</code> を付けることで逆にオーバーロード解決できなくなるようなこともありえます。</p>
<p>例えば、以下のように複数のクラスで複数の拡張メソッドが定義されていて、
全体でみれば1つだけ優先度が高くてオーバーロード解決できる場合を考えます。</p>
<pre class="source" title="複数のクラスの複数の拡張メソッドから1つ選ばれる例">
<span class="comment">// A.M(string), A.M(string, int), B.M(string, int) が同列で比較されて、</span>
<span class="comment">// デフォルト引数なしの A.M(string) が勝つ。</span>
<span class="string">&quot;&quot;</span><span class="operator">.</span><span class="method">M</span>();

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">A</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>) <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">$&quot;</span><span class="string">A.M(</span>{<span class="variable local">s</span>}<span class="string">)</span><span class="string">&quot;</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">int</span> <span class="variable local">i</span> <span class="operator">=</span> <span class="number">0</span>) <span class="operator">=&gt;</span> <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="string">$&quot;</span><span class="string">A.M(</span>{<span class="variable local">s</span>}<span class="string">, </span>{<span class="variable local">i</span>}<span class="string">)</span><span class="string">&quot;</span>);
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">B</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">int</span> <span class="variable local">i</span> <span class="operator">=</span> <span class="number">0</span>) <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="string">$&quot;</span><span class="string">B.M(</span>{<span class="variable local">s</span>}<span class="string">, </span>{<span class="variable local">i</span>}<span class="string">)</span><span class="string">&quot;</span>);
}
</pre>
<p>ここで、<code>A.M</code> のうちの1つに <code>OverloadResolutionPriority</code> を付けて優先度を変えてみます。
<code>OverloadResolutionPriority</code> は1つのクラス内でしか働かないので、<code>A</code> の中のどの <code>M</code> が選ばれるかにだけ影響します。
その結果、以下のように別のクラスの <code>M</code> と競合する可能性があります。</p>
<pre class="source" title="OverloadResolutionPriority を付けたことで他のクラスのメンバーと競合するようになる例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// OverloadResolutionPriority を付けたことで、A.M の中では A.M(string, int) が選ばれる。</span>
<span class="comment">// B.M は元々 B.M(string, int) しかない。</span>
<span class="comment">// A.M(string, int) と B.M(string, int) が競合してオーバーロード解決できなくなる。</span>
<span class="string">&quot;&quot;</span><span class="operator">.</span><span class="method"><span class="error" title="CS0121">M</span></span>();

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">A</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>) <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="string">$&quot;</span><span class="string">A.M(</span>{<span class="variable local">s</span>}<span class="string">)</span><span class="string">&quot;</span>);

    [<span class="type">OverloadResolutionPriority</span>(<span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">int</span> <span class="variable local">i</span> <span class="operator">=</span> <span class="number">0</span>) <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">$&quot;</span><span class="string">A.M(</span>{<span class="variable local">s</span>}<span class="string">, </span>{<span class="variable local">i</span>}<span class="string">)</span><span class="string">&quot;</span>);
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">B</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="reserved">string</span> <span class="variable local">s</span>, <span class="reserved">int</span> <span class="variable local">i</span> <span class="operator">=</span> <span class="number">0</span>) <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="string">$&quot;</span><span class="string">B.M(</span>{<span class="variable local">s</span>}<span class="string">, </span>{<span class="variable local">i</span>}<span class="string">)</span><span class="string">&quot;</span>);
}
</pre>
<h3><a id="overload-by-return">余談: (疑似)戻り値オーバーロード</a></h3>
<p>C# では戻り値だけが異なるオーバーロードを認めていません。
例えば以下のコードはコンパイル エラーになります。</p>
<pre class="source" title="戻り値だけが違うオーバーロードの追加はできない">
<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method"><span class="static">MAsync</span></span>() { <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>(); }

    <span class="comment">// Task を ValueTask に変更したいとして、互換性のために Task MAsync() を残すと…</span>
    <span class="comment">// 戻り値だけが違うオーバーロードは認められない。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type struct">ValueTask</span> <span class="error" title="CS0111"><span class="method"><span class="static">MAsync</span></span></span>() { <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>(); }
}
</pre>
<p>ちょっと気持ち悪い回避策になりますが、デフォルト引数を悪用することでオーバーロードもどきを作れたりはします。
ところが、「引数なし」と「デフォルト引数持ち」なら前者の方が優先されるため、
追加した新しいオーバーロードもどきが呼ばれることはありません。</p>
<pre class="source" title="オーバーロードもどき(おしい)">
<span class="comment">// 残念ながら Task MAsync() の方しか呼ばれない。</span>
<span class="reserved">await</span> <span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">MAsync</span></span>();

<span class="comment">// もちろんこうすれば ValueTask の方が呼ばれるものの、不格好すぎる。</span>
<span class="reserved">await</span> <span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">MAsync</span></span>(<span class="reserved">default</span>);

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="static"><span class="method">MAsync</span></span>() { <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="static"><span class="method">Yield</span></span>(); }

    <span class="comment">// オーバーロードもどきとして、適当に使わないデフォルト値付きの引数を追加。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type struct">ValueTask</span> <span class="static"><span class="method">MAsync</span></span>(<span class="reserved">int</span> <span class="variable local">_</span> <span class="operator">=</span> <span class="number">0</span>) { <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>(); }
}
</pre>
<p>これも一応、<code>OverloadResolutionPriority</code> 属性で解消できます。</p>
<pre class="source" title="OverloadResolutionPriority でごり押し">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// ValueTask 戻り値の方が呼ばれるように。</span>
<span class="reserved">await</span> <span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">MAsync</span></span>();

<span class="reserved">class</span> <span class="type">C</span>
{
    [<span class="type">OverloadResolutionPriority</span>(<span class="operator">-</span><span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method"><span class="static">MAsync</span></span>() { <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>(); }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type struct">ValueTask</span> <span class="static"><span class="method">MAsync</span></span>(<span class="reserved">int</span> <span class="variable local">_</span> <span class="operator">=</span> <span class="number">0</span>) { <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>(); }
}
</pre> ]]></description>
				<pubDate>Thu, 14 Nov 2024 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>型の分割定義 (partial)</title>
				<link>http://www.ufcpp.net/study/csharp/misc/partial-type/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<h5 class="version version2">Ver. 2.0</h5>
<p>C# 2.0 で、<code>partial</code> 修飾子を付けることで、クラスや構造体、インターフェイスを複数のファイルに分けて型を定義できるようになりました。
この <code>partial</code> によるファイルの分割は、
「片方のファイルを手書き、もう片方のファイルを開発ツールなどによって自動生成」みたいな状況を想定しています。</p>
<p>(それ以外の用途でむやみに複数のファイル分けると、どのファイルに何のメソッドがあるのか探しにくくなるので、
通常は、むしろ、クラス定義を複数のファイルに分割しない方がいいです。)</p>
<h2><a id="tool-generated-code">背景: ツール生成のソースコード</a></h2>
<p>Visual Studio などの統合開発環境を利用していると分かると思いますが、
ソースファイルの一部分はプログラマーの手書きではなく、
開発ツールが自動的に生成してくれる部分があります。</p>
<p>例えば、データベースのテーブル定義から C# のクラスを生成するみたいなツールがあります。
仮に、<code>Id</code> と <code>Name</code> の2つの列がある <code>Entity</code> という名前のテーブルから、以下のようなクラスをツール生成したとします。</p>
<pre class="source" title="データベース テーブルの Id, Name 列からのプロパティ生成">
<span class="reserved">class</span> <span class="type">Entity</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Id</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">string</span><span class="operator">?</span> <span class="property">Name</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</pre>
<p>これに対して、プロパティの値の書き換え時に処理を挟みたいとします。
一応、ツール生成のソースコードを書き換えれば目的を達成することは可能ではあります。</p>
<pre class="source" title="ツール生成物をもし手で書き換えたとすると…">
<span class="reserved">class</span> <span class="type">Entity</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_id</span>;
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Id</span> { <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="field">_id</span>; <span class="reserved">set</span> { <span class="control">if</span> (<span class="field">_id</span> <span class="operator">!=</span> <span class="reserved">value</span>) { <span class="field">_id</span> <span class="operator">=</span> <span class="reserved">value</span>; <span class="field">_changed</span> <span class="operator">=</span> <span class="reserved">true</span>; } } }

    <span class="reserved">private</span> <span class="reserved">string</span><span class="operator">?</span> <span class="field">_name</span>;
    <span class="reserved">public</span> <span class="reserved">string</span><span class="operator">?</span> <span class="property">Name</span> { <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="field">_name</span>; <span class="reserved">set</span> { <span class="control">if</span> (<span class="field">_name</span> <span class="operator">!=</span> <span class="reserved">value</span>) { <span class="field">_name</span> <span class="operator">=</span> <span class="reserved">value</span>; <span class="field">_changed</span> <span class="operator">=</span> <span class="reserved">true</span>; } } }

    <span class="reserved">private</span> <span class="reserved">bool</span> <span class="field">_changed</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Flush</span>() <span class="operator">=&gt;</span> <span class="field">_changed</span> <span class="operator">=</span> <span class="reserved">false</span>;
}
</pre>
<p>ここで、データベースのテーブルに列 <code>X</code> を追加したので、ツール生成の C# コードも更新したいとします。
「手書きで書き方部分は残して新たに追加したものだけをソースコード生成」なんてことは難しく、普通はすべて上書きされます。</p>
<pre class="source" title="残念ながら、手書きで書き換えた分は紛失する">
<span class="reserved">class</span> <span class="type">Entity</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Id</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">string</span><span class="operator">?</span> <span class="property">Name</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">X</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</pre>
<p>ソースコードの一部分を「ここはツール生成だから書き換えないで」領域にすることもできなくはないですが、なかなかに危険です。
例えば、WinForms (C# 1.1 時代からある GUI フレームワーク)開発がまさにそういう方式で、
WinForms アプリを作ると、ソースコード中に以下のような領域ができます。</p>
<pre class="source" title="WinForms アプリで、Visual Studio が生成するコード">
<span class="reserved">namespace</span> WinFormsApp1;

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Form1</span>
{
    <span class="comment">// 前略</span>
    <span class="comment">// この部分は手書きで書き換える想定。</span>

    <span class="preprocess">#</span><span class="preprocess">region</span> Windows Form Designer generated code

    <span class="comment">///</span><span class="comment"> </span><span class="comment">&lt;</span><span class="comment">summary</span><span class="comment">&gt;</span>
    <span class="comment">///</span><span class="comment">  Required method for Designer support - do not modify</span>
    <span class="comment">///</span><span class="comment">  the contents of this method with the code editor.</span>
    <span class="comment">///</span><span class="comment"> </span><span class="comment">&lt;/</span><span class="comment">summary</span><span class="comment">&gt;</span>
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">InitializeComponent</span>()
    {
        <span class="reserved">this</span><span class="operator">.</span><span class="field">components</span> <span class="operator">=</span> <span class="reserved">new</span> System<span class="operator">.</span>ComponentModel<span class="operator">.</span><span class="type">Container</span>();
        <span class="reserved">this</span><span class="operator">.</span>AutoScaleMode <span class="operator">=</span> System<span class="operator">.</span>Windows<span class="operator">.</span>Forms<span class="operator">.</span>AutoScaleMode<span class="operator">.</span>Font;
        <span class="reserved">this</span><span class="operator">.</span>ClientSize <span class="operator">=</span> <span class="reserved">new</span> System<span class="operator">.</span>Drawing<span class="operator">.</span><span class="type struct">Size</span>(<span class="number">800</span>, <span class="number">450</span>);
        <span class="reserved">this</span><span class="operator">.</span>Text <span class="operator">=</span> <span class="string">&quot;Form1&quot;</span>;
    }

    <span class="preprocess">#</span><span class="preprocess">endregion</span>
}
</pre>
<p>まさに「書き換えないで」(do not modify)と書かれていますし、
実際、書き換えても Visual Studio によって元に戻されたりします。
手で書き換える想定のコードとツール生成コードが1ファイルに混ざっていることで、
例えば、「ファイル内で一斉置換」みたいな作業をしたときにツール生成部分を壊したりといった事故もありました。</p>
<h2><a id="partial-class">型の分割</a></h2>
<p>このように、手書きとツール生成の混在は危険なので、別ファイルに分かれている方が安心です。
そこで、C# 2.0 では、クラス定義時に <code>partial</code> というキーワードを付けることで、
クラス定義を複数に分割することができるようになりました。
これを <strong id="partial_class" class="keyword">部分クラス</strong>(partial class)と言います。</p>
<p>例えば前節のツール生成例に <code>partial</code> を付けてみましょう。</p>
<pre class="source" title="partial の例">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Entity</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Id</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">string</span><span class="operator">?</span> <span class="property">Name</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</pre>
<p>この型に手で何かコードを足したい場合、別ファイルに以下のような感じでコードを書きます。</p>
<pre class="source" title="partial を使えば、別ファイルでクラスに処理を足せる">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Entity</span>
{
    <span class="reserved">private</span> <span class="reserved">bool</span> <span class="field">_changed</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Flush</span>() <span class="operator">=&gt;</span> <span class="field">_changed</span> <span class="operator">=</span> <span class="reserved">false</span>;
}
</pre>
<p>(プロパティ <code>Id</code> や <code>Name</code> の中の処理を変更したい場合の話は次節の「<a href="partial_method">メソッドの実装の分離</a>」で説明します。)</p>
<p><code>partial</code> はクラスの他に、構造体、インターフェイスにもつけれます。</p>
<pre class="source" title="構造体、インターフェイスにも partial">
<span class="reserved">partial</span> <span class="reserved">struct</span> <span class="type struct">S</span> { }
<span class="reserved">partial</span> <span class="reserved">struct</span> <span class="type struct">S</span> { }

<span class="reserved">partial</span> <span class="reserved">interface</span> <span class="type">I</span> { }
<span class="reserved">partial</span> <span class="reserved">interface</span> <span class="type">I</span> { }

<span class="reserved">partial</span> <span class="reserved">record</span> <span class="type">R</span> { }
<span class="reserved">partial</span> <span class="reserved">record</span> <span class="type">R</span> { }

<span class="reserved">partial</span> <span class="reserved">record</span> <span class="reserved">class</span> <span class="type">RC</span> { }
<span class="reserved">partial</span> <span class="reserved">record</span> <span class="reserved">class</span> <span class="type">RC</span> { }

<span class="reserved">partial</span> <span class="reserved">record</span> <span class="reserved">struct</span> <span class="type struct">RS</span> { }
<span class="reserved">partial</span> <span class="reserved">record</span> <span class="reserved">struct</span> <span class="type struct">RS</span> { }
</pre>
<p>ただ、部分クラスにしたい場合、すべての型定義に <code>partial</code> 修飾子を付ける必要があります。
これは、「ファイルを分けるつもりがなかったのに、他の誰かに勝手に部分定義を足された」みたいなことを避けるためです。</p>
<pre class="source" title="partial はすべての型定義に付ける必要あり">
<span class="comment">// 片方に partial が付いてないとエラー。</span>
<span class="reserved">class</span> <span class="type"><span class="error" title="CS0260">C</span></span> { }

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">C</span> { }
</pre>
<p>ちなみに、<code>partial</code> 以外の修飾子に関しては、複数ある型定義についてる修飾子すべてを統合したものになります。
例えば、以下のように「片方が <code>public</code>、もう片方が <code>static</code>」な場合、この型は <code>public static</code> 扱いです。</p>
<pre class="source" title="修飾子は統合される">
<span class="comment">// この型は public static class C 扱い。</span>
<span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">C</span> { }
<span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type"><span class="static">C</span></span> { }
</pre>
<p>ここで実例として、WPF アプリを紹介します。
WinForms とは違って、WPF (C# 3.0 世代の GUI フレームワーク)は <code>partial</code> を使ってツール生成のコードと手書きコードを分けています。
WPF アプリでは、手での書き換えを前提とした以下のようなコードを書く一方で、</p>
<pre class="source" title="WPF で手書きするべきコード例">
<span class="reserved">using</span> System<span class="operator">.</span>Windows;

<span class="reserved">namespace</span> WpfApp1;

<span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">MainWindow</span> : <span class="type">Window</span>
{
    <span class="reserved">public</span> <span class="type">MainWindow</span>()
    {
        <span class="method">InitializeComponent</span>();
    }
}
</pre>
<p>ツール生成で以下のようなコードが作られます(実物はだいぶ長いので一部抜粋)。</p>
<pre class="source" title="WPF で、XAML から生成されるコード例">
<span class="comment">//------------------------------------------------------------------------------</span>
<span class="comment">// &lt;auto-generated&gt;</span>
<span class="comment">//     This code was generated by a tool.</span>
<span class="comment">//     Runtime Version:4.0.30319.42000</span>
<span class="comment">//</span>
<span class="comment">//     Changes to this file may cause incorrect behavior and will be lost if</span>
<span class="comment">//     the code is regenerated.</span>
<span class="comment">// &lt;/auto-generated&gt;</span>
<span class="comment">//------------------------------------------------------------------------------</span>

<span class="reserved">using</span> System;
<span class="reserved">using</span> System<span class="operator">.</span>Diagnostics;
<span class="reserved">using</span> System<span class="operator">.</span>Windows;
<span class="comment">// 中略</span>

<span class="reserved">namespace</span> WpfApp1
{
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">MainWindow</span> : System<span class="operator">.</span>Windows<span class="operator">.</span><span class="type">Window</span>, System<span class="operator">.</span>Windows<span class="operator">.</span>Markup<span class="operator">.</span><span class="type">IComponentConnector</span>
    {
        <span class="reserved">private</span> <span class="reserved">bool</span> <span class="field">_contentLoaded</span>;

        <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">InitializeComponent</span>()
        {
            <span class="control">if</span> (<span class="field">_contentLoaded</span>)
            {
                <span class="control">return</span>;
            }
            <span class="field">_contentLoaded</span> <span class="operator">=</span> <span class="reserved">true</span>;
            System<span class="operator">.</span><span class="type">Uri</span> <span class="variable">resourceLocater</span> <span class="operator">=</span> <span class="reserved">new</span> System<span class="operator">.</span><span class="type">Uri</span>(<span class="string">&quot;/WpfApp1;V1.0.0.0;component/mainwindow.xaml&quot;</span>, System<span class="operator">.</span><span class="type">UriKind</span><span class="operator">.</span>Relative);

<span class="preprocess">#</span><span class="preprocess">line</span> <span class="number">1</span> <span class="string">&quot;..\..\..\MainWindow.xaml&quot;</span>
            System<span class="operator">.</span>Windows<span class="operator">.</span>Application<span class="operator">.</span>LoadComponent(<span class="reserved">this</span>, <span class="variable">resourceLocater</span>);
        }
<span class="comment">// 中略</span>
    }
}
</pre>
<p>こちらのツール生成のコードは、通常、どこに生成されたのかすら意識せず、中身を覗くこともほとんどありません。</p>
<h2><a id="partial_method">メソッドの実装の分離</a></h2>
<h5 class="version version3">Ver. 3.0</h5>
<p>C# 3.0 で
<strong id="partial_method" class="keyword">部分メソッド</strong>（partial method）という機能も追加されました。</p>
<p>どういうものかというと、
<a href="/study/csharp/oop/oo_class?key=partial_class">部分クラス</a>内限定で、
メソッドに <code>partial</code> を付けることでメソッドの宣言と定義を分けれるというものです。</p>
<p>定義の仕方と、制限事項は以下の通り。</p>
<ul>
<li>
<p><code>partial</code> 修飾子を付けてメソッドを宣言する。</p>
</li>
<li>
<p>必ず部分クラス内になければならない。</p>
</li>
<li>
<p><a href="/csharp/oo_conceal.html?sec=level#level">アクセシビリティ</a>の指定はできない(自動的に必ず <code>private</code> 扱い)。</p>
</li>
<li>
<p>戻り値は <code>void</code> 以外不可。</p>
</li>
<li>
<p>引数は自由に取れる。<code>ref</code>, <code>this</code>, <code>params</code> も利用可能。ただし、<code>out</code> 引数は不可。</p>
</li>
<li>
<p>静的メソッド（<code>static</code>）でもインスタンス メソッド（非 <code>static</code>）でも OK。</p>
</li>
</ul>
<p>例として、前節の <code>Entity</code> の例で出てきた
「プロパティ <code>Id</code> や <code>Name</code> の中の処理を変更したい場合の話」をしましょう。</p>
<p>用途的に、「プロパティの値が変わったときに何かはしたい」、
「ただ、何をするかはアプリごとに異なる」
みたいなことがあります。
そういった場合、「プロパティの値が変わった」のタイミングを拾えるよう、
以下のように、部分メソッドを含むコードをツール生成してもらっておきます。</p>
<pre class="source" title="ツール生成で partial メソッドを生成">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Entity</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_id</span>;
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Id</span> { <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="field">_id</span>; <span class="reserved">set</span> { <span class="control">if</span> (<span class="field">_id</span> <span class="operator">!=</span> <span class="reserved">value</span>) { <span class="field">_id</span> <span class="operator">=</span> <span class="reserved">value</span>; <span class="method">OnIdChanged</span>(); } } }
    <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">OnIdChanged</span>();

    <span class="reserved">private</span> <span class="reserved">string</span><span class="operator">?</span> <span class="field">_name</span>;
    <span class="reserved">public</span> <span class="reserved">string</span><span class="operator">?</span> <span class="property">Name</span> { <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="field">_name</span>; <span class="reserved">set</span> { <span class="control">if</span> (<span class="field">_name</span> <span class="operator">!=</span> <span class="reserved">value</span>) { <span class="field">_name</span> <span class="operator">=</span> <span class="reserved">value</span>; <span class="method">OnNameChanged</span>(); } } }
    <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">OnNameChanged</span>();
}
</pre>
<p><code>OnIdChanged</code> と <code>OnNameChanged</code> が部分メソッドです。
このまま何も手書きコードを足さなければ、これらのメソッドは何もしません。
(空のメソッドが呼ばれるとかですらなく、メソッドを呼んだ痕跡すらも完全に消えます。)
（さらにいうと、メタデータすら残さず、完全に消えます。
<a href="/study/csharp/sp_attribute.html#compiler_attribute"><code>Conditional</code> 属性</a>でも似たようなことができますが、こちらは少なくともメタデータは残ります。）</p>
<p>一方、手書きコードで処理を足したければ以下のような感じのコードを書きます。</p>
<pre class="source" title="partial メソッドに実装を足す例">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Entity</span>
{
    <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">OnIdChanged</span>() <span class="operator">=&gt;</span> <span class="field">_changed</span> <span class="operator">=</span> <span class="reserved">true</span>;
    <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">OnNameChanged</span>() <span class="operator">=&gt;</span> <span class="field">_changed</span> <span class="operator">=</span> <span class="reserved">true</span>;

    <span class="reserved">private</span> <span class="reserved">bool</span> <span class="field">_changed</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Flush</span>() <span class="operator">=&gt;</span> <span class="field">_changed</span> <span class="operator">=</span> <span class="reserved">false</span>;
}
</pre>
<p>こうすると、追加した <code>OnIdChanged</code> や <code>OnNameChanged</code> の実装が呼び出されるようになります。</p>
<h3><a id="partial_method-side-effect">部分メソッドの引数で副作用を起こす場合</a></h3>
<p>「不要な場合は完全削除」という仕様には、1つ奇妙な動作を招く点があります。
問題が起こり得るのは、部分メソッドの呼び出しの際に引数で副作用を起こす場合です。</p>
<p>例えば、以下のコードの実行結果はどうなるでしょう。</p>
<pre class="source" title="">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">Main</span></span>(<span class="reserved">string</span>[] <span class="variable local">args</span>)
    {
        <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>;
        <span class="method"><span class="static">A</span></span>(<span class="variable">x</span> <span class="operator">=</span> <span class="number">2</span>);
        <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">Write</span></span>(<span class="string">&quot;{0}\n&quot;</span>, <span class="variable">x</span>);
    }

    <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="static"><span class="method">A</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>);
}
</pre>
<p><code>A</code> の実装がある場合には 2 に、ない場合には 1 になります。
部分クラスなので、当然、実装は別ファイルにあってもかまいません。
自分以外の誰かがどこか別のところで実装を書くかもしれませんし、
誰も書かないかもしれません。
要するに、自分の知らないところで実行結果が変えられてしまう可能性がある。</p>
<p>まあ、メソッド呼び出しの <code>()</code> 内で代入なんてするなよって話ではあるんですが。
こういう副作用があることも覚えておいてください。
（あるいは、この副作用を積極的に利用したトリッキーなコードも書けるでしょうが・・・。
個人的には非推奨。）</p>
<h2><a id="extended_partial_method">部分メソッドの拡張</a></h2>
<h5 class="version version9">Ver. 9</h5>
<p><a href="#partial_method">前節で説明した部分メソッド</a>は「開発ツールが生成したコードが先にあって、そこに手書き処理を足したいときに使う物」です。</p>
<p>一方、C# 9.0 世代では<a href="https://ufcpp.net/study/csharp/misc/analyzer-generator/">ソースコード生成機能</a>が入ったことでこの逆があり得ます。
すなわち、「ソースコード生成してもらう前提で、手書きでは不完全な C# コードを書きたい」という場面が出てきました。</p>
<p>C# 9.0 では、そのための「不完全なメソッド」を書く方法として <code>partial</code> キーワードを再利用することにしました。
旧来の部分メソッドとの文法上の差は<a href="/study/csharp/oo_conceal.html#level">アクセシビリティ</a>修飾子(<code>public</code> とか <code>private</code> とか)を持つかどうかです。</p>
<pre class="source" title="新旧・部分メソッド">
<span class="comment">// (1) ツールが事前に生成する想定のコード</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">PreGeneratedMethod</span>()
    {
        <span class="method">OnPreGeneratedMethod</span>();
 
        <span class="comment">// ツール生成のコード</span>
    }
 
    <span class="comment">// ツール生成のコードの前に何か手書き処理を足したければこのメソッドの中身を書く</span>
    <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">OnPreGeneratedMethod</span>();
}
 
<span class="comment">// (2) 手書き前提のコード</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
<span class="inactive">#if</span> DEBUG
    <span class="comment">// ツール生成コード前に、Debug 時のみログを仕込む。</span>
    <span class="comment">// これを書かなければ OnPreGeneratedMethod は呼ばれる痕跡すら残らない。</span>
    <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">OnPreGeneratedMethod</span>()
    {
        System.<span class="type">Console</span>.<span class="method">WriteLine</span>(
            <span class="string">&quot;PreGeneratedMethod が呼ばれた直後&quot;</span>
            + <span class="method">WantSourceGenerated</span>());
    }
<span class="inactive">#endif</span>
 
    <span class="comment">// 手書き C# コードが先にあって、これを元にソースコード生成してほしいメソッド。</span>
    <span class="reserved"><em>private</em></span> <span class="reserved">partial</span> <span class="reserved">string</span> <span class="method">WantSourceGenerated</span>();
}
 
<span class="comment">// (3) C# からのソースコード生成が前提のコード</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">private</span> <span class="reserved">partial</span> <span class="reserved">string</span> <span class="method">WantSourceGenerated</span>() =&gt; <span class="string">&quot;手書きはしづらしくて、ソースコード生成なら楽な文字列&quot;</span>;
}
</pre>
<p><a href="/study/csharp/misc/analyzer-generator/#usage">コード解析・コード生成の利用</a>で紹介している <a href="https://github.com/ufcpp/StringLiteralGenerator">StringLiteralGenerator</a> はこの新しい部分メソッドを使っています。</p>
<p>ちなみに、コード生成と手書きの期待される順序が逆になっただけ(しかも文法上は非常に小さな差)ですが、結果的には結構できること・できないことが変わります。
以下の表に違いをまとめます。</p>
<table>
<caption>新旧・部分メソッドの比較</caption>
<tr>
  <th>旧(アクセス修飾子なし)</th>
  <th>新(アクセス修飾子あり)</th>
</tr>
<tr>
  <td>アクセシビリティの指定は不可</td>
  <td>アクセシビリティの指定が必須(private 含む)</td>
</tr>
<tr>
  <td>戻り値は void のみ</td>
  <td>任意の戻り値を使える</td>
</tr>
<tr>
  <td>ref 引数、out 引数を持てない</td>
  <td>ref 引数、out 引数を持てる</td>
</tr>
<tr>
  <td>本体を持っていなくてもいい。なければ完全に消える。</td>
  <td>どこか1か所で本体を持たないとダメ。なければコンパイル エラー。</td>
</tr>
</table>
<p>アクセシビリティ修飾子の有無だけでここまで差があることには少し抵抗があって、
文法をどうするかは C# チームも結構迷ったようです。
ただ、最終的には、下手にキーワードを追加したり全然違う文法を導入するよりはマシという判断が下りました。</p>
<h4>シグネチャの一致</h4>
<p>部分メソッドは、宣言側と実装側でシグネチャ(引数リスト、戻り値の型、修飾子)が一致している必要があります。</p>
<p>アクセシビリティ、<code>static</code>, <code>readonly</code>, <code>ref</code> の有無が違うとエラーになります。</p>
<pre class="source" title="シグネチャが合わなくてエラーになる例">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="static"><span class="method">M0</span></span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="static"><span class="method">M1</span></span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="method"><span class="static">M2</span></span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="static"><span class="method">M3</span></span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="static"><span class="method">M4</span></span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="static"><span class="method">M5</span></span>();
}

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="comment">// 全部一致。これは大丈夫。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="method"><span class="static">M0</span></span>() <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();

    <span class="comment">// 戻り値の型が違うのは当然ダメ。エラー。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">byte</span> <span class="static"><span class="error" title="CS8817"><span class="method">M1</span></span></span>() <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();

    <span class="comment">// 以下、修飾子のどこかが違う。全部エラー。</span>
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="method"><span class="static"><span class="error" title="CS8799">M2</span></span></span>() <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="error" title="CS0763"><span class="method">M3</span></span>() <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="method"><span class="static"><span class="error" title="CS8818"><span class="warning" title="CS8826">M4</span></span></span></span>() <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="error" title="CS8818"><span class="static"><span class="method"><span class="warning" title="CS8826">M5</span></span></span></span>() <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();
}
</pre>
<p>タプル要素名の差もエラーになります。</p>
<pre class="source" title="タプル要素名が違うとエラー">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">public</span> <span class="reserved">partial</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="method">M0</span>((<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="variable local">t</span>);
    <span class="reserved">public</span> <span class="reserved">partial</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="method">M1</span>((<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="variable local">t</span>);
    <span class="reserved">public</span> <span class="reserved">partial</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="method">M2</span>((<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="variable local">t</span>);
}

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="comment">// 全部一致。これは大丈夫。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="method">M0</span>((<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="variable local">t</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;

    <span class="comment">// タプル要素名が違うとエラーに。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="method"><span class="error" title="CS8142">M1</span></span>((<span class="reserved">int</span> a, <span class="reserved">int</span> b) <span class="variable local">t</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
    <span class="reserved">public</span> <span class="reserved">partial</span> (<span class="reserved">int</span> a, <span class="reserved">int</span> b) <span class="error" title="CS8142"><span class="method">M2</span></span>((<span class="reserved">int</span> x, <span class="reserved">int</span> y) <span class="variable local">t</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
}
</pre>
<p>引数名、<a href="https://ufcpp.net/study/csharp/resource/nullablereferencetype/">null 許容参照型</a>のアノテーションの差は警告になります。</p>
<pre class="source" title="引数名、nullability の差は警告に">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">M0</span>(<span class="reserved">int</span> <span class="variable local">x</span>, <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">y</span>);
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">int</span> <span class="variable local">x</span>, <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">y</span>);
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">M2</span>(<span class="reserved">int</span> <span class="variable local">x</span>, <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">y</span>);
}

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="comment">// 全部一致。これは大丈夫。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">M0</span>(<span class="reserved">int</span> <span class="variable local">x</span>, <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">y</span>) { }

    <span class="comment">// 引数名が違う。警告。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method"><span class="warning" title="CS8826">M1</span></span>(<span class="reserved">int</span> <span class="variable local">a</span>, <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">y</span>) { }

    <span class="comment">// nullability が違う。警告。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="warning" title="CS8611"><span class="warning" title="CS8826"><span class="method">M2</span></span></span>(<span class="reserved">int</span> <span class="variable local">a</span>, <span class="reserved">string</span> <span class="variable local">y</span>) { }
}
</pre>
<p>一方で、属性は統合されます。</p>
<pre class="source" title="属性は統合">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    [<span class="type">A</span>] <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">M</span>([<span class="type">A</span>] <span class="reserved">int</span> <span class="variable local">x</span>);
}

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    [<span class="type">B</span>] <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">void</span> <span class="method">M</span>([<span class="type">B</span>] <span class="reserved">int</span> <span class="variable local">x</span>) { }
}

<span class="comment">// [A, B] public partial void M([A, B] int x) { } と書いたのと同じになる。</span>

<span class="reserved">class</span> <span class="type">A</span> : <span class="type">Attribute</span> { }
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">Attribute</span> { }
</pre>
<h3><a id="partial_property">部分プロパティ</a></h3>
<h5 class="version version13">Ver. 13</h5>
<p><a href="#partial_method">C# 3.0 からある方の部分メソッド</a> は「戻り値なし(<code>void</code>)でないとダメ」という制約があって、
メソッド以外では元々役に立ちません。</p>
<p>一方、<a href="#extended_partial_method">C# 9.0 で拡張された方の部分メソッド</a> は、
制約的にも用途的にも、<a href="https://ufcpp.net/study/csharp/oo_property.html">プロパティ</a>や<a href="https://ufcpp.net/study/csharp/oo_indexer.html">インデクサー</a>でも使えるはずです。
実際、工数の問題で後回しになっていただけで、C# 13 でめでたく部分プロパティ・部分インデクサーが実装されました。</p>
<pre class="source" title="">
<span class="comment">// 元コード。</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="comment">// 部分プロパティ。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="property">PartialProprty</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }

    <span class="comment">// 部分インデクサー。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="reserved">this</span>[<span class="reserved">int</span> <span class="variable local">index</span>] { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}

<span class="comment">// コード生成で作ってもらう前提のコード。</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_field</span>;
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="property">PartialProprty</span> { <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="field">_field</span>; <span class="reserved">set</span> <span class="operator">=&gt;</span> <span class="field">_field</span> <span class="operator">=</span> <span class="reserved">value</span>; }

    <span class="reserved">private</span> <span class="reserved">int</span>[] <span class="field">_array</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="reserved">int</span>[<span class="number">10</span>];
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="reserved">this</span>[<span class="reserved">int</span> <span class="variable local">index</span>] { <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="field">_array</span>[<span class="variable local">index</span>]; <span class="reserved">set</span> <span class="operator">=&gt;</span> <span class="field">_array</span>[<span class="variable local">index</span>] <span class="operator">=</span> <span class="reserved">value</span>; }
}
</pre>
<p>この機能の追加で特にうれしいのは <a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.text.regularexpressions.generatedregexattribute"><code>GeneratedRegex</code></a> の存在でしょう。
C# 12 までは、以下のようにメソッドにする必要がありました。</p>
<pre class="source" title="GeneratedRegex">
<span class="reserved">using</span> System<span class="operator">.</span>Text<span class="operator">.</span>RegularExpressions;

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">MyPatterns</span>
{
    [<span class="type">GeneratedRegex</span>(<span class="string">@&quot;\d{4}&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="type">Regex</span> <span class="static"><span class="method">FourDigits</span></span>();
}
</pre>
<p>この属性を付けると、正規表現 <code>\d{4}</code> のマッチ処理を<a href="https://ufcpp.net/study/csharp/misc/analyzer-generator/">ソースコード生成</a>で作ってくれます。
(普通に <code>new Regex(@&quot;\d{4}&quot;)</code> と書くよりもだいぶパフォーマンスがよくなります。)</p>
<p>ただ、生成されるコードはメソッドよりもプロパティっぽいコード
(呼ぶたびに何か処理をするのではなく、最初の1回で作ったインスタンスをキャッシュして持っておいて、2回目からはほとんどノーコスト)になっています。
これまでは「部分プロパティがなかったからやむなくメソッドに付けていた」というだけで、
C# 13 と同世代の .NET 9 からはプロパティで同じことができるようになりました。</p>
<pre class="source" title="GeneratedRegex をプロパティに付けれるようになった">
<span class="reserved">using</span> System<span class="operator">.</span>Text<span class="operator">.</span>RegularExpressions;

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">MyPatterns</span>
{
    [<span class="type">GeneratedRegex</span>(<span class="string">@&quot;\d{4}&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="type">Regex</span> <span class="property"><span class="static">FourDigits</span></span> { <span class="reserved">get</span>; } <span class="comment">// プロパティになった。</span>
}
</pre>
<h4><a id="auto-property">プロパティの宣言と自動実装</a></h4>
<p>C# の文法上の紛らわしさなんですが、
プロパティに対して <code>{ get; set; }</code> などと書いたときの扱いには2種類あるので注意が必要です。</p>
<p>普通のクラスや構造体で <code>{ get; set; }</code> を書くとき、これは<a href="https://ufcpp.net/study/csharp/oo_property.html#auto">自動実装</a>になります。</p>
<pre class="source" title="自動実装の get; set;">
<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// 自動実装の意味。</span>
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">X</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }

    <span class="comment">// コンパイラーが裏でフィールドを1個作って、</span>
    <span class="comment">// public int X { get =&gt; field; set =&gt; field = value; }</span>
    <span class="comment">// みたいなコードとして扱われる。</span>
}
</pre>
<p>一方、<a href="https://ufcpp.net/study/csharp/oo_interface.html">インターフェイス</a>や、<a href="https://ufcpp.net/study/csharp/oo_abstract.html">抽象メンバー</a>の場合、「宣言だけある」という扱いになります。</p>
<pre class="source" title="abstract の get; set;">
<span class="reserved">interface</span> <span class="type">I</span>
{
    <span class="comment">// 宣言(「このプロパティは get も set も持っていてほしい」という意思表示のみ)。</span>
    <span class="reserved">int</span> <span class="property">X</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}

<span class="reserved">abstract</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// これも宣言のみ。</span>
    <span class="reserved">public</span> <span class="reserved">abstract</span> <span class="reserved">int</span> <span class="property">X</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</pre>
<p>部分プロパティの場合は後者の意味になります。</p>
<pre class="source" title="partial の get; set;">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// 宣言(「partial の片割れで get も set も実装してほしい」という意思表示)。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="property"><span class="error" title="CS9248">X</span></span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</pre>
<p>「片方が宣言、片方が自動実装」みたいなことにはならないので、
以下のコードはコンパイル エラーを起こします。</p>
<pre class="source" title="実装がいない問題">
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// 宣言。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="property"><span class="error" title="CS9248">X</span></span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// こっちも宣言。</span>
    <span class="comment">// なので、実装がいなくてエラーになる。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">int</span> <span class="error" title="CS0102"><span class="error" title="CS9250"><span class="property">X</span></span></span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</pre>
<h3><a id="partial-event">部分イベントと部分コンストラクター</a></h3>
<p><a href="#partial_property">部分プロパティ</a> (C# 13)に続いて、
C# 14 では<a href="https://ufcpp.net/study/csharp/sp_event.html">イベント</a>と<a href="https://ufcpp.net/study/csharp/oo_construct.html">コンストラクター</a>も部分定義できるようになりました。
(これも「工数の問題で後回しになっていただけ」の類です。)</p>
<pre class="source" title="部分イベントと部分コンストラクターの例">
<span class="comment">// 元コード(手書き想定)。</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="comment">// 部分イベント。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">event</span> <span class="type">Action</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> PartialEvent;

    <span class="comment">// 部分コンストラクター。</span>
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="type">PartialClass</span>();
}

<span class="comment">// コード生成で作ってもらう前提のコード。</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">private</span> <span class="type">Action</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="field">_partialEvent</span>;
    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">event</span> <span class="type">Action</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> PartialEvent
    {
        <span class="reserved">add</span> <span class="operator">=&gt;</span> <span class="field">_partialEvent</span> <span class="operator">+=</span> <span class="reserved">value</span>;
        <span class="reserved">remove</span> <span class="operator">=&gt;</span> <span class="field">_partialEvent</span> <span class="operator">-=</span> <span class="reserved">value</span>;
    }

    <span class="reserved">public</span> <span class="reserved">partial</span> <span class="type">PartialClass</span>() { }
}
</pre>
<h2><a id="contextual-partial-keyword">partial キーワードの位置</a></h2>
<p>部分クラス・部分メソッドの仕様は C# 2.0 から追加されたものです。
<code>partial</code>というキーワードも 2.0 からの後付けなわけで、完全に予約語(変数などの名前に使えない単語)にしてしまうと、1.0 時代に書かれたコードを壊す可能性がありました。</p>
<p>そこで、<code>partial</code> は<a href="/study/csharp/ap_reserved.html#context">文脈キーワード</a>になっています。
<code>partial</code>という単語がキーワード扱いされるのは、<code>class</code>、<code>struct</code>、<code>interface</code>、<code>void</code>の直前だけです。
(前節の<a href="https://ufcpp.net/study/csharp/oo_class.html#extended_partial_method">拡張部分メソッド</a>の場合は戻り値の型の直前だけ。)
その結果、以下のように、語順に制約があります。</p>
<pre class="source" title="partial には語順に制約がある">
<span class="comment">// OK</span>
<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Ok1</span> { }
<span class="reserved">static</span> <span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Ok2</span> { }

<span class="comment">// コンパイル エラー</span>
<span class="reserved">public</span> <span class="reserved"><span class="error">partial</span></span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Ng1</span> { }
<span class="reserved"><span class="error">partial</span></span> <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Ng2</span> { }
<span class="reserved">static</span> <span class="reserved"><span class="error">partial</span></span> <span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Ng3</span> { }

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">X</span>
{
    <span class="comment">// OK</span>
    <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">void</span> Ok();

    <span class="comment">// コンパイル エラー</span>
    <span class="reserved"><span class="error">partial</span></span> <span class="reserved">static</span> <span class="reserved">void</span> Ng();
}
</pre> ]]></description>
				<pubDate>Sat, 31 Aug 2024 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 13.0 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver13/</link>
				<description><![CDATA[ <div class="version version13">Ver. 13.0</div>
<table>
<tr>
<th>リリース時期</th>
<td>2024/11</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>.NET 9.0</li>
<li>Visual Studio 2022 17.12</li>
</td>
</tr>
</table>
<p>執筆予定: <a href="https://github.com/ufcpp/UfcppSample/issues/462">C# 13.0 トラッキング issue</a></p>
<h2><a id="params-collections">params コレクション</a></h2>
<p><a href="https://ufcpp.net/study/csharp/datatype/collection-expression/">コレクション式</a>で使える型であれば何でも <code>params</code> にできるようになりました。</p>
<pre class="source" title="任意のコレクションに対して params を付ける例">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M1</span></span>(<span class="reserved">params</span> <span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">x</span>) { }
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M2</span></span>(<span class="reserved">params</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">x</span>) { }
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M3</span></span>(<span class="reserved">params</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">x</span>) { }
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M4</span></span>(<span class="reserved">params</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">x</span>) { }

<span class="method"><span class="static">M1</span></span>(<span class="number">1</span>, <span class="number">2</span>);
<span class="static"><span class="method">M2</span></span>(<span class="number">1</span>, <span class="number">2</span>);
<span class="method"><span class="static">M3</span></span>(<span class="number">1</span>, <span class="number">2</span>);
<span class="static"><span class="method">M4</span></span>(<span class="number">1</span>, <span class="number">2</span>);
</pre>
<p>需要が高いのは <code>ReadOnlySpan</code> で、
<code>params T[]</code> を <code>params ReadOnlySpan&lt;T&gt;</code> に変更すればそれだけでパフォーマンスの改善が見込めます。</p>
<p>実際、 .NET 9 では、<code>string.Join</code> や <code>Task.WhenAll</code> などのメソッドに
<code>params ReadOnlySpan&lt;T&gt;</code> なオーバーロードが増えています。</p>
<pre class="source" title="params ReadOnlySpan オーバーロードが増えている例">
<span class="comment">// .NET 8 以前なら Join(string, string[])</span>
<span class="comment">// .NET 9 以降なら Join(string, ReadOnlySpan&lt;string&gt;)</span>
<span class="reserved">var</span> <span class="variable">joiend</span> <span class="operator">=</span> <span class="reserved">string</span><span class="operator">.</span><span class="method"><span class="static">Join</span></span>(<span class="string">&quot;,&quot;</span>, <span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>);
</pre>
<p>このため、自分で <code>params</code> を使わない場合でも、
「.NET 9 にアップグレードして再コンパイルするだけでアプリのパフォーマンスがちょっと改善する」という間接的なメリットがあります。</p>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_params.html#params-collections"><code>params</code> コレクション</a>」で説明しています。</p>
<h2><a id="partial-property">部分プロパティ</a></h2>
<p>プロパティとインデクサーも <code>partial</code> にできるようになりました。</p>
<p>例えば、C# 13 と同世代の .NET 9 では、<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.text.regularexpressions.generatedregexattribute"><code>GeneratedRegex</code></a> をプロパティにできるようになりました。</p>
<pre class="source" title="GeneratedRegex をプロパティに付けれるようになった">
<span class="reserved">using</span> System<span class="operator">.</span>Text<span class="operator">.</span>RegularExpressions;

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">MyPatterns</span>
{
    [<span class="type">GeneratedRegex</span>(<span class="string">@&quot;\d{4}&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="type">Regex</span> <span class="property"><span class="static">FourDigits</span></span> { <span class="reserved">get</span>; } <span class="comment">// プロパティになった。</span>
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/misc/partial-type/#partial_property">部分プロパティ</a>」で説明します。</p>
<h2><a id="ref-struct-interface">ref 構造体のインターフェイス実装</a></h2>
<p>ref 構造体にインターフェイスを実装できるようになりました。
また、このインターフェイスのメンバーを呼び出すために、
ジェネリック型引数に ref 構造体を渡せるようにする仕組みとして <code>allows ref struct</code> アンチ制約が追加されました。</p>
<pre class="source" title="allows ref struct なジェネリック メソッドを介して、ref 構造体のインターフェイス実装を呼ぶ">
<span class="type struct">S</span> <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">new</span>(); <span class="comment">// S は IFormattable を実装してる。</span>

<span class="comment">// これはボックス化を起こすから C# 13 でもエラーになる。</span>
<span class="type">IFormattable</span> <span class="variable">f</span> <span class="operator">=</span> <span class="variable"><span class="error" title="CS0029">x</span></span>;
<span class="variable">f</span><span class="operator">.</span><span class="method">ToString</span>(<span class="string">&quot;X&quot;</span>, <span class="reserved">null</span>);

<span class="comment">// allows ref struct なジェネリックメソッドを介して、</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span> <span class="variable local">f</span>) <span class="reserved">where</span> <span class="type param">T</span> : <span class="type">IFormattable</span>, <span class="reserved">allows</span> <span class="reserved">ref</span> <span class="reserved">struct</span>
    <span class="operator">=&gt;</span> <span class="variable local">f</span><span class="operator">.</span><span class="method">ToString</span>(<span class="string">&quot;X&quot;</span>, <span class="reserved">null</span>);

<span class="comment">// こうやって IFormattable.ToString を呼べば大丈夫になった。</span>
<span class="method"><span class="static">M</span></span>(<span class="variable">x</span>);

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">S</span> : <span class="type">IFormattable</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="method">ToString</span>(<span class="reserved">string</span><span class="operator">?</span> <span class="variable local">format</span>, <span class="type">IFormatProvider</span><span class="operator">?</span> <span class="variable local">formatProvider</span>) <span class="operator">=&gt;</span> <span class="string">&quot;&quot;</span>;
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/resource/refstruct/#ref-struct-interface">ref 構造体のインターフェイス実装</a>」で説明します。
また、「アンチ制約」という言葉については「<a href="https://ufcpp.net/study/csharp/sp2_generics.html#anti-constraint">アンチ制約</a>」で説明しています。</p>
<h2><a id="overload-resolution-priority">OverloadResolutionPriority</a></h2>
<p>C# 13 で、オーバーロードの解決優先度を属性を付けて明示できる機能が入りました。</p>
<pre class="source" title="オーバーロード解決の優先度を変更する例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// IEnumerable&lt;char&gt; の方が選ばれる。</span>
<span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">M1</span></span>(<span class="string">&quot;&quot;</span>);
<span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">M2</span></span>(<span class="string">&quot;&quot;</span>);

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// 通常、インターフェイスよりも具体的な型の方が優先。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M1</span></span>(<span class="reserved">string</span> <span class="variable local">_</span>) { }

    <span class="comment">// 属性を付けて優先度を上げる。</span>
    [<span class="type">OverloadResolutionPriority</span>(<span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M1</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">_</span>) { }

    <span class="comment">// 属性を付けて優先度を下げる。</span>
    [<span class="type">OverloadResolutionPriority</span>(<span class="operator">-</span><span class="number">1</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M2</span></span>(<span class="reserved">string</span> <span class="variable local">_</span>) { }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M2</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/structured/miscoverloadresolution/?p=3#overload-resolution-priority">オーバーロード解決</a>」で説明します。</p>
<p>トラッキングissue: <a href="https://github.com/ufcpp/UfcppSample/issues/478">#478</a></p>
<h2><a id="lock-class">Lock クラスに対する lock</a></h2>
<p>.NET 9 で <code>Lock</code> クラス(<code>System.Threading</code> 名前空間)という新しい lock 用の型が追加されたことに伴って、
<code>lock</code> ステートメントでこの <code>Lock</code> クラスを特別扱いするようになりました。
既存の <code>lock</code> (<code>Monitor.Enter</code> に展開される)と異なり、以下のようなコードに展開されます。</p>
<pre class="source" title="lock (x) は using (x.EnterSceop()) になる">
<span class="reserved">var</span> <span class="variable">syncObject</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">Lock</span>();

<span class="comment">// lock (syncObject)</span>
<span class="reserved">using</span> (<span class="variable">syncObject</span><span class="operator">.</span><span class="method">EnterScope</span>())
{
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_thread.html#lock-class">Lock クラス</a>」で説明しています。</p>
<h2><a id="ref-in-async">ref/unsafe をイテレーター/非同期メソッド中に書けるように</a></h2>
<p><a href="https://ufcpp.net/study/csharp/sp_ref.html?p=2#ref-returns">ref ローカル変数</a>、
<a href="https://ufcpp.net/study/csharp/resource/refstruct/">ref 構造体</a>の変数、
<a href="https://ufcpp.net/study/csharp/sp_unsafe.html#unsafe">unsafe</a> ブロックを、
<a href="https://ufcpp.net/study/csharp/sp2_iterator.html">イテレーター</a>と<a href="https://ufcpp.net/study/csharp/sp5_async.html">非同期メソッド</a>内で使えるようになりました。</p>
<p>イテレーターと非同期メソッドは内部の仕組み的に非常に似ているにも関わらず、
この2者で微妙に制限のかかり方が違ったんですが、
それも C# 13 でそろいました。</p>
<p>以下のコードで、行末コメントで ⭕ を付けている部分が C# 13 で新たにコンパイルできるようになったコードです。</p>
<pre class="source" title="ref/unsafe をイテレーター/非同期メソッド中に書けるように">
<span class="type">IEnumerable</span>&lt;<span class="reserved">object</span><span class="operator">?</span>&gt; <span class="method">Enumerate</span>()
{
    <span class="reserved">unsafe</span> { } <span class="comment">// ⭕</span>

    <span class="control">yield</span> <span class="control">return</span> <span class="reserved">null</span>;

    <span class="type struct">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">data</span> <span class="operator">=</span> [];

    <span class="control">yield</span> <span class="control">return</span> <span class="reserved">null</span>;

    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>;
    <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x</span>; <span class="comment">// ⭕</span>
}

<span class="reserved">async</span> <span class="type">Task</span> <span class="method">GetAsync</span>()
{
    <span class="reserved">unsafe</span> { }

    <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="static"><span class="method">Yield</span></span>();

    <span class="type struct">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">data</span> <span class="operator">=</span> []; <span class="comment">// ⭕</span>

    <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>();

    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>;
    <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x</span>; <span class="comment">// ⭕</span>
}

<span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">object</span><span class="operator">?</span>&gt; <span class="method">EnumerateAsync</span>()
{
    <span class="reserved">unsafe</span> { } <span class="comment">// ⭕</span>

    <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>(); <span class="control">yield</span> <span class="control">return</span> <span class="reserved">null</span>;

    <span class="type struct">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">data</span> <span class="operator">=</span> []; <span class="comment">// ⭕</span>

    <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="method"><span class="static">Yield</span></span>(); <span class="control">yield</span> <span class="control">return</span> <span class="reserved">null</span>;

    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>;
    <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x</span>; <span class="comment">// ⭕</span>
}
</pre>
<p>元々、原理的にはこう書いても問題ないことはわかっていたんですが、
正しく判定するのにコストがかかる割に、需要は低いだろうということでエラーにしていました。
C# 13 で書けるようになったのは、前述の<a href="#lock-class"><code>Lock</code> クラスに対する <code>lock</code></a> のついでだそうです。
(<code>Lock</code> クラスの <code>EnterScope</code> が ref 構造体を使っています。)</p>
<p>ただし、これは <code>yield</code> や <code>await</code> をまたがない場合に限って許されます。
例えば以下のコードは C# 13 でもコンパイル エラーを起こします。</p>
<pre class="source" title="C# 13 でもエラーになる書き方の例">
<span class="type">IEnumerable</span>&lt;<span class="reserved">object</span><span class="operator">?</span>&gt; <span class="method">Enumerate</span>()
{
    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>;
    <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x</span>;
    <span class="control">yield</span> <span class="control">return</span> <span class="reserved">null</span>;
    <span class="error" title="CS9217"><span class="variable">r</span></span> <span class="operator">=</span> <span class="number">456</span>;
}

<span class="reserved">async</span> <span class="type">Task</span> <span class="method">GetAsync</span>()
{
    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>;
    <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x</span>;
    <span class="reserved">await</span> <span class="type">Task</span><span class="operator">.</span><span class="static"><span class="method">Yield</span></span>();
    <span class="error" title="CS9217"><span class="variable">r</span></span> <span class="operator">=</span> <span class="number">456</span>;
}
</pre>
<h2><a id="escape-escape">\e (エスケープ文字のエスケープ シーケンス)</a></h2>
<p>文字・文字列リテラル中の<a href="https://ufcpp.net/study/csharp/st_embeddedtype.html#escape-sequence">エスケープ シーケンス</a>に <code>\e</code> (U+001B、エスケープ文字)が追加されました。</p>
<p>例えば、コンソール アプリで以下のように書くことで、文字列の色を変えたり装飾したりできます。</p>
<pre class="source" title="\e の利用例">
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="string">&quot;\e[31mred text&quot;</span>);
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;\e[4munderlined text&quot;</span>);
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;\e[0mreset style&quot;</span>);
</pre>
<p><img src="/media/1217/escapeescape.png" alt="\e エスケープ シーケンス" /></p>
<p>機能追加の背景などについてはブログ記事「<a href="https://ufcpp.net/blog/2023/12/escape-escape/">\e (エスケープ文字のエスケープ シーケンス)</a>」で説明しています。</p>
<h2><a id="interceptor">インターセプター</a></h2>
<p>(書きかけ。予定地。)</p>
<p>トラッキングissue: <a href="https://github.com/ufcpp/UfcppSample/issues/456">#456</a></p>
<h2><a id="other">その他</a></h2>
<p>その他、ほぼバグ修正レベルの機能がいくつかあります。</p>
<h3><a id="index-in-object-initializer">オブジェクト初期化子中の ^ 演算子</a></h3>
<p>以下のように、オブジェクト初期化子中の <code>[]</code> の中で<a href="https://ufcpp.net/study/csharp/data/dataranges/">インデックスの <code>^</code> 演算子</a>を使えるようになりました。</p>
<pre class="source" title="">
<span class="comment">// これが C# 12 以前はコンパイル エラーを起こしてた。</span>
<span class="reserved">var</span> <span class="variable">c</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">C</span> { [<span class="operator">^</span><span class="number">1</span>] <span class="operator">=</span> <span class="number">1</span> };

<span class="comment">// これなら昔からコンパイルできる。</span>
<span class="comment">// (オブジェクト初期化子はこれと同じコードに展開されるはずなのに。)</span>
<span class="variable">c</span>[<span class="operator">^</span><span class="number">1</span>] <span class="operator">=</span> <span class="number">1</span>;

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// インデクサーと Length さえ持っていれば c[^i] と書けるようになる。</span>
    <span class="comment">// c[c.Length - i] 扱い。</span>
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">Length</span> <span class="operator">=&gt;</span> <span class="number">1</span>;
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="reserved">this</span>[<span class="reserved">int</span> <span class="variable local">i</span>] { <span class="reserved">get</span> <span class="operator">=&gt;</span> <span class="variable local">i</span>; <span class="reserved">set</span> { } }
}
</pre>
<h3><a id="method-group-natrural-type">デリゲートの自然な型の改善</a></h3>
<p><a href="https://ufcpp.net/study/csharp/sp_delegate.html#natural-type">デリゲートの自然な型</a>の決定の際、
メソッド グループに対する型決定がちょっと賢くなったそうです。
同名のインスタンス メソッドと拡張メソッドがあるとき、インスタンス メソッドを優先的に見るようになりました。</p>
<p>例えば以下のようなクラスがあったとします。</p>
<pre class="source" title="同名のインスタンス メソッドと拡張メソッド">
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>() { } <span class="comment">// インスタンス メソッド M と、</span>
}

<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">E</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">this</span> <span class="type">C</span> <span class="variable local">c</span>, <span class="reserved">object</span> <span class="variable local">o</span>) { } <span class="comment">// 同名の拡張メソッド。</span>
}
</pre>
<p>この <code>C</code> 型のインスタンス <code>x</code> に対して <code>x.M</code> と書いたとき、
C# 12 までは自然な型を決定できなかったのに対して、
C# 13 ではインスタンスメソッドを優先的に見ます。</p>
<pre class="source" title="C# 13 の新ルール">
<span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">C</span>();

<span class="comment">// オーバーロード解決ではインスタンスメソッド優先。</span>
<span class="variable">x</span><span class="operator">.</span><span class="method">M</span>();      <span class="comment">// C.M()</span>
<span class="variable">x</span><span class="operator">.</span><span class="method">M</span>(<span class="string">&quot;&quot;</span>); <span class="comment">// E.M(C, object)</span>

<span class="comment">// 型の明示があると昔から大丈夫だった。</span>
<span class="type">Action</span> <span class="variable">a</span> <span class="operator">=</span> <span class="variable">x</span><span class="operator">.</span><span class="method">M</span>;         <span class="comment">// C.M()</span>
<span class="type">Action</span>&lt;<span class="reserved">object</span>&gt; <span class="variable">b</span> <span class="operator">=</span> <span class="variable">x</span><span class="operator">.</span><span class="method">M</span>; <span class="comment">// E.M(C, object)</span>

<span class="comment">// var を使う。</span>
<span class="comment">// これが C# 13 から行けるように。</span>
<span class="comment">// インスタンス メソッド優先で、Action 型になる。</span>
<span class="reserved">var</span> <span class="variable">z</span> <span class="operator">=</span> <span class="variable">x</span><span class="operator">.</span><span class="method">M</span>;
</pre>
<h3><a id="collection-expression13">コレクション式の改善</a></h3>
<p><a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver12/#collection-expression">コレクション式</a>にも微妙な修正が2つ入っています。</p>
<p>1つは、<code>Add</code> メソッドが拡張メソッドでも大丈夫になりました。
(こちらは最新のコンパイラーにすると <code>LangVersion</code> 12 にしても元の挙動(= コンパイル エラー)にはなりません。)</p>
<pre class="source" title="コレクション式も拡張メソッドの Add を見てくれるように">
<span class="reserved">using</span> System<span class="operator">.</span>Collections;

<span class="type">C</span> <span class="variable">c</span> <span class="operator">=</span> [<span class="string">'a'</span>];

<span class="reserved">class</span> <span class="type">C</span> : <span class="type">IEnumerable</span>
{
    <span class="reserved">public</span> <span class="type">IEnumerator</span> <span class="method">GetEnumerator</span>() <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">NotImplementedException</span>();
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">Extensions</span></span>
{
    <span class="comment">// C# 12 の頃はこの拡張メソッドを見てくれずエラーになっていた。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Add</span></span>(<span class="reserved">this</span> <span class="type">C</span> <span class="variable local">a</span>, <span class="reserved">char</span> <span class="variable local">_</span>) { }
}
</pre>
<p>もう1つは、<a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver13/#params-collections">params コレクション</a>との兼ね合いで、オーバーロード解決ルールが変わっています。
以下のように、要素の型違いのオーバーロードがあるとき、要素の<a href="https://ufcpp.net/blog/2022/12/stackalloc-natural-type/">自然な型</a>を見るようになりました。
(この変更は言語バージョンを見て分岐しているようで、
最新のコンパイラーでも <a href="https://ufcpp.net/study/csharp/cheatsheet/langversionoption/#langversion"><code>LangVersion</code></a> を12以前に戻すと古い挙動になります。)</p>
<pre class="source" title="要素の自然な型優先">
<span class="comment">// C# 12 では以下の2つとも解決不能(コンパイル エラー)になってた。</span>

<span class="comment">// C# 13 では int の方になる。</span>
<span class="type">C</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([<span class="number">1</span>]);

<span class="comment">// C# 13 では string の方になる。</span>
<span class="type">C</span><span class="operator">.</span><span class="static"><span class="method">M</span></span>([<span class="string">$&quot;</span><span class="string">&quot;</span>]);

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">List</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable local">_</span>) { }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">List</span>&lt;<span class="reserved">string</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">List</span>&lt;<span class="type">IFormattable</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<p>ただ、この結果、ちょっとした破壊的変更も起きています。
C# 12 から C# 13 にアップデートすると、以下のような場合にオーバーロード解決先が変わります。</p>
<pre class="source" title="コレクション式のオーバーロード解決の破壊的変更">
<span class="type">C</span><span class="operator">.</span><span class="static"><span class="method">M</span></span>([<span class="number">1</span>, <span class="number">2</span>]);

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="comment">// C# 12 だとこっちが呼ばれる。</span>
    <span class="comment">// (ReadOnlySpan 優先。)</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable local">data</span>) <span class="operator">=&gt;</span> <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;ReadOnlySpan&lt;byte&gt;&quot;</span>);

    <span class="comment">// C# 13 だとこっちが呼ばれる。</span>
    <span class="comment">// (中身の自然な型(整数リテラルは int になる)優先。)</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">data</span>) <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;Span&lt;int&gt;&quot;</span>);
}
</pre> ]]></description>
				<pubDate>Sat, 13 Jul 2024 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>ref構造体</title>
				<link>http://www.ufcpp.net/study/csharp/resource/refstruct/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p><a href="/study/csharp/resource/span/">前項</a>では、C# 7.2 の新機能と深くかかわる <code>Span&lt;T&gt;</code> 構造体という型を紹介しました。
この型は、論理的には <code>(ref T Reference, int Length)</code> というような、「参照フィールド」と長さのペアを持つ構造体です。
「参照」を持っているので、参照戻り値や参照ローカル変数と同種の「出所の保証」が必要です。
また<code>Span&lt;T&gt;</code> には「<a href="/study/csharp/misc_heap.html">スタック</a>上に置かれている必要がある」(ヒープに置けない)という制限が必要です。</p>
<p>さらに、<code>Span&lt;T&gt;</code> に制限が掛かっている以上、「<code>Span&lt;T&gt;</code>を持つ型」にも再帰的に制限が掛かります。
「<code>Span&lt;T&gt;</code> を持つか持たないか」だけで挙動が変わるのでは影響範囲が大きすぎるため、
「<code>Span&lt;T&gt;</code> を持ちたければ <code>ref</code> という修飾が必要」という制約もあります。</p>
<p>ここでは、これらの <code>Span&lt;T&gt;</code> の「スタック上に置かれている必要がある」という制約や、「<code>ref</code> 構造体」について説明していきます。
(<code>ref</code>構造体という機能ではありますが、主用途が<code>Span&lt;T&gt;</code>に関するものなので、span safety ruleと呼ばれたりもします。)</p>
<h2><a id="ref-struct">ref 構造体</h2>
<p><code>Span&lt;T&gt;</code> には制限が必要といっても、C# コンパイラーとしては <code>Span&lt;T&gt;</code> だけを特別扱いしたくはありません。
そこで、<strong id="key-refstruct" class="keyword"><code>ref</code>構造体</strong> (<code>ref struct</code>)というものを導入しました。</p>
<p><code>ref</code>構造体は、名前通り、<code>ref</code> 修飾子が付いた構造体です。
<code>Span&lt;T&gt;</code> 構造体自身にも <code>ref</code> 修飾子がついています。
そして、<code>ref</code>構造体をフィールドとして持てるのは<code>ref</code>構造体だけです。</p>
<pre class="source" title="ref構造体を持てるのはref構造体だけ">
<code><span class="comment">// Span&lt;T&gt; は ref 構造体になっている</span>
<span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">Span</span>&lt;<span class="type">T</span>&gt; { ... }

<span class="comment">// ref 構造体を持てるのは ref 構造体だけ</span>
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">RefStruct</span>
{
    <span class="reserved">private</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; _span; <span class="comment">//OK</span>
}
</code></pre>
<p>逆に言うと、<code>ref</code> 修飾子がついていない構造体や、クラスは<code>ref</code>構造体をフィールドとして持てません。</p>
<pre class="source" title="">
<code><span class="comment">// NG。構造体以外を「ref 型」にはできない</span>
<span class="reserved">ref</span> <span class="reserved"><span class="error">class</span></span> <span class="type">InvalidClass</span> { }

<span class="comment">// ref がついていない普通の構造体は ref 構造体を持てない</span>
<span class="reserved">struct</span> <span class="type">NonRefStruct</span>
{
    <span class="reserved">private</span> <span class="error"><span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;</span> _span; <span class="comment">//NG</span>
}
</code></pre>
<p>そして、以下で説明する制約は、<code>Span&lt;T&gt;</code> 構造体だけでなく、すべての <code>ref</code> 構造体に対して掛かります。</p>
<h2><a id="flow-analysis">戻り値で返せるもの</h2>
<p><code>ref</code> 構造体を戻り値として使いたい場合、
<a href="/study/csharp/sp_ref.html?p=2#ref-returns"><code>ref</code> 戻り値・<code>ref</code> ローカル変数</a>と同様に、大元をたどって調べて(フロー解析して)、返していいものかどうかを判定します。
以下のようなルールがあります(<a href="/study/csharp/sp_ref.html?p=2#flow-analysis"><code>ref</code>戻り値と同じルール</a>です)。</p>
<ul>
<li>引数で受け取ったものは戻り値に返せます</li>
<li>ローカルで確保したものは返せません</li>
<li>引数などを介して多段に参照している場合、コードをたどって大元が安全かまで調べます</li>
</ul>
<pre class="source" title="戻り値に返せるかどうか">
<code><span class="comment">// 引数で受け取ったものは戻り値で返せる</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; Success(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x) =&gt; x;

<span class="comment">// ローカルで確保したもの変数はダメ</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; Error()
{
    <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[1];
    <span class="reserved">return</span> <span class="error">x</span>;
}

<span class="comment">// 多段の場合も元をたどって出所を調べてくれる</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; Success(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x, <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; y)
{
    <span class="reserved">var</span> r1 = x;
    <span class="reserved">var</span> r2 = y;
    <span class="reserved">var</span> r3 = r1.Length &gt;= r2.Length ? r1 : r2;

    <span class="comment">// r3 は出所をたどると引数の x か y</span>
    <span class="comment">// x も y も引数なので大丈夫</span>
    <span class="reserved">return</span> r3;
}

<span class="reserved">private</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; Error(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x, <span class="reserved">int</span> n)
{
    <span class="reserved">var</span> r1 = x;
    <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; r2 = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[n];
    <span class="reserved">var</span> r3 = r1.Length &gt;= r2.Length ? r1 : r2;

    <span class="comment">// r2 がローカルなのでダメ</span>
    <span class="reserved">return</span> <span class="error">r3</span>;
}
</code></pre>
<p>ちなみに、上記の<code>Error</code>と似たようなコードでも、以下のコードはコンパイルできます。
ちゃんと「メモリ確保があったかどうか」を見ていて、「<code>default</code>であれば何も確保していない」という判定もしています。</p>
<pre class="source" title="default は何も確保しない">
<code><span class="comment">// ちゃんと「メモリ確保」があったかどうかを見てる</span>
<span class="comment">// 同じようなコードでもこれは OK (default だと何も確保しない)</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; Success1()
{
    <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x = <span class="reserved">default</span>;
    <span class="reserved">return</span> x;
}
</code></pre>
<p>このルールは、<code>ref</code>構造体と、<code>ref</code>引数・<code>ref</code>戻り値の間でも働きます。
例えば、引数由来の <code>Span&lt;T&gt;</code>から得た<code>ref T</code>な参照は戻り値にできますが、ローカル由来のものはできません。</p>
<pre class="source" title="Span&gt;T&lt;とref T">
<code><span class="comment">// 引数で受け取った Span 由来の ref 戻り値は返せる</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">ref</span> <span class="reserved">int</span> Success(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x) =&gt; <span class="reserved">ref</span> x[0];

<span class="comment">// ローカルで確保した Span 由来の ref 戻り値はダメ</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">ref</span> <span class="reserved">int</span> Error()
{
    <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[1];
    <span class="reserved">return</span> <span class="reserved">ref</span> <span class="error">x</span>[0];
}
</code></pre>
<h3><a id="readonly-ref">readonly ref</h3>
<p>C# 7.2 で追加された構造体がらみの修飾子には<a href="/study/csharp/resource/readonlyness/#readonly-struct"><code>readonly</code></a>というものもあります。
<code>readonly</code>修飾は、一見、参照がらみの機能とは無関係に見えますが、実はこれも「参照として返せるかどうか」の判定に関係しています。</p>
<p>例えば以下のコードを見てください。</p>
<pre class="source" title="readonly修飾とref構造体">
<code><span class="reserved">using</span> System;

<span class="comment">// ref だけ</span>
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">RefToSpan</span>
{
    <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; _span;
    <span class="reserved">public</span> RefToSpan(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; span) =&gt; _span = span;

    <span class="comment">// 例え _span に readonly が付いていても、this 書き換えが可能</span>
    <span class="reserved">public</span> <span class="reserved">void</span> Method(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; span) { <span class="reserved">this</span> = <span class="reserved">new</span> RefToSpan(span); }
}

<span class="comment">// readonly ref</span>
<span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">RORefToSpan</span>
{
    <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; _span;
    <span class="reserved">public</span> <span class="reserved">void</span> Method(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; span) { }
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> LocalToRef(<span class="type">RefToSpan</span> r)
    {
        <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; local = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[1];
        <span class="error">r.Method(local)</span>; <span class="comment">// ここでエラーになる。r の中身が書き換えられることで、local が外に漏れる可能性を危惧</span>

        <span class="comment">// 注: この例の場合は実際には漏れはしないものの、RefToSpan の作り次第なので保証はできない</span>
    }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> LocalToRORef(<span class="type">RORefToSpan</span> r)
    {
        <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; local = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[1];
        r.Method(local); <span class="comment">// readonly ref に対してなら OK</span>
    }
}
</code></pre>
<p>ローカルで定義した<code>Span&lt;T&gt;</code>を、引数で渡ってきた<code>ref</code>構造体のメソッドに対して渡しています。
この場合、<code>readonly</code>がついている場合にだけコンパイルできます。
<code>readonly</code>がついていない方では、メソッドの中で<code>r</code>が書き換わる可能性があります。
その結果「ローカルの<code>Span&lt;T&gt;</code>が外に漏れる可能性がある」という判定を受けるため、コンパイル エラーになります。
<code>readonly</code>がついている方では「書き換えがあり得ない」ということで、「外にも漏れない」という判定になります。</p>
<h3><a id="unsafe">余談: さすがに unsafe までは追えない</h3>
<p>参照がらみのフロー解析は、あくまで<code>ref</code>ローカル変数や、<code>ref</code>構造体に対してだけ働きます。
<code>unsafe</code>を使って、ポインターなどを介するとさすがに追跡できません。</p>
<p>例えば、以下のコードは不正で、実行時エラーであったり、予期しない動作を招く可能性があります。
しかし、コンパイラーが不正を判定できず、コンパイル時にエラーにすることができません。</p>
<pre class="source" title="unsafe な手段までは追えない">
<code><span class="reserved">unsafe</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; X()
{
    <span class="comment">// ローカル</span>
    <span class="reserved">int</span> x = 10;

    <span class="comment">// unsafe な手段でローカルなものの参照を作って返す</span>
    <span class="comment">// これをやってしまうとまずいものの、コンパイル時にはエラーにできない</span>
    <span class="reserved">return</span> <span class="reserved">new</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;(&amp;x, 1);
}
</code></pre>
<h2><a id="stack-only">「スタックのみ」制約</h2>
<p><code>ref</code>構造体はスタック上に置かれている必要があります。
この性質から、<code>ref</code>構造体は「stack-only 型」と呼ばれることもあります。
この制限が必要になるのは以下の2つの理由からです。</p>
<ul>
<li>そもそも参照自体がスタック上でしか働かない</li>
<li>マルチスレッド動作時に安全性を保証できない</li>
</ul>
<p>まず、<code>ref</code> 構造体以前に、参照自体がスタック上でしか使えません。
参照は、常にその参照の出所をトラッキングする必要があります。
例えば、出所がクラス(.NET の<a href="http://ufcpp.net/study/csharp/rm_gc.html#garbage-collection">ガベージ コレクション</a>の管理下)の場合、
それを参照する方もガベージ コレクションのトラッキングの対象になります。
このトラッキング処理を低コストで行うためには、参照がスタック上になければなりません。</p>
<p>次に、マルチスレッド動作に関してですが、
<code>Span&lt;T&gt;</code> の中身が論理的には <code>(ref T Reference, int Length)</code> という2要素からなることによります。
安全に使うには、この2つが<a href="/study/csharp/sp_thread.html#lock">アトミック</a>に読み書きされなければなりません。
もし、<code>Reference</code> だけが書き換わり、<code>Length</code> がまだ書き換わっていないタイミングで参照先を読み書きされてしまうと、
範囲チェックが正しく働かず、不正な領域を読み書きしてしまう危険性が出てきます。</p>
<p>ということで、「スタック上に置かれている必要がある」という制約が掛かります。
具体的には、以下のような制限があります。</p>
<ul>
<li>クラスのフィールドとして持てない(クラスに <code>ref</code> 修飾子を付けれない理由はこれ)</li>
<li>
<a href="/study/csharp/sp2_anonymousmethod.html">クラスのフィールドに昇格</a>する可能性があることができない
<ul>
<li><a href="/study/csharp/functional/fun_localfunctions/#key-local">ローカル関数</a>や<a href="/study/csharp/functional/fun_localfunctions/#key-anonymous">ラムダ式</a>で<a href="/study/csharp/functional/fun_localfunctions/#capture-local">キャプチャ</a>できない</li>
<li><a href="/study/csharp/sp2_iterator.html">イテレーター</a>の引数には使えない</li>
<li>イテレーター内では、<code>yield return</code> をまたいで使えない</li>
<li>
<a href="/study/csharp/sp5_async.html">非同期メソッド</a>に対しては引数にもローカル変数にも使えない
<ul>
<li>(<a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver13/#ref-in-async">C# 13 で緩和</a>。C# 13 からは、<code>await</code> をまたがない限り、ローカル変数に使えます)</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="/study/csharp/RmBoxing.html">ボックス化</a>できない
<ul>
<li><code>object</code>や<code>dynamic</code>、インターフェイス型の変数に代入できない</li>
<li><code>ToString</code> など、<code>object</code> 型のメソッドを呼べない</li>
</ul>
</li>
<li>ジェネリック型引数として使えない</li>
</ul>
<pre class="source" title="ref構造体は stack-only">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Threading.Tasks;

<span class="comment">//❌ そもそもクラスに ref を付けれないのも stack-only を保証するため</span>
<span class="reserved">ref</span> <span class="reserved"><span class="error">class</span></span> <span class="type">Class</span> { }

<span class="comment">//❌ インターフェイス実装</span>
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">RefStruct</span> : <span class="type"><span class="error">IDisposable</span></span> { <span class="reserved">public</span> <span class="reserved">void</span> Dispose() { } }

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">//❌ 非同期メソッドの引数</span>
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> Async(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="error">x</span>)
    {
        <span class="comment">//❌ 非同期メソッドのローカル変数</span>
        <span class="error"><span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;</span> local = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[10];
    }

    <span class="comment">//❌ イテレーターの引数</span>
    <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; Iterator(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x)
    {
        <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; local = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[10];
        local[0] = 1; <span class="comment">//⭕ yield return をまたがないならOK</span>
        <span class="reserved">yield</span> <span class="reserved">return</span> local[0];
        <span class="comment">//❌ yield をまたいだ読み書き</span>
        <span class="error">local</span>[0] = 2; <span class="comment">// ダメ</span>
    }

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; local = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[1];

        <span class="comment">//❌ box 化</span>
        <span class="reserved">object</span> obj = <span class="error">local</span>;

        <span class="comment">//❌ object のメソッド呼び出し</span>
        <span class="reserved">var</span> str = <span class="error">local</span>.ToString();

        <span class="comment">//❌ クロージャ</span>
        <span class="type">Func</span>&lt;<span class="reserved">int</span>&gt; a1 = () =&gt; <span class="error">local</span>[0];
        <span class="reserved">int</span> F() =&gt; <span class="error">local</span>[0];

        <span class="comment">//❌ 型引数にも渡せない</span>
        <span class="type">List</span>&lt;<span class="error"><span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;</span>&gt; list;
    }
}
</code></pre>
<h3><a id="TypedReference">余談: TypedReference</h3>
<p>「<a href="/study/csharp/sp_makeref.html">型付き参照</a>」で説明している<code>TypedReference</code>型も、内部的に参照を持っている型の1つです。
<code>TypedReference</code> は ref 構造体の仕様よりも古くからあって、昔はこの型だけに対して特殊対応をしていました。</p>
<p>その昔からある <code>TypedReference</code> に対する特殊対応は、本項で説明している C# 7.2 から入った ref 構造体に対する制約よりもだいぶ緩くて、実は「スタック上に置かれている必要がある」制約から割かし簡単に外れることができました。</p>
<p>ちなみに、C# 7.2 で ref 構造体を導入後、
.NET Core 2.1 からは <code>TypedReference</code> に対する特殊対応は止めて、単に <code>TypedReference</code> を ref 構造体に変更したようです。
結果的に元よりも制約が厳しくなっていて、昔は(バグっている可能性が非常に高いものの)一応コンパイルできていたコードがコンパイル エラーになる可能性があります。
(ただ、<code>TypedReference</code> 自体利用頻度が非常に低いので問題にはなっていません。)</p>
<h2><a id="ref-field">ref フィールド</a></h2>
<h5 class="version version11">Ver. 11</h5>
<p>C# 11 で、<a href="https://ufcpp.net/study/csharp/resource/refstruct/#key-refstruct">ref 構造体</a>のフィールドを <a href="https://ufcpp.net/study/csharp/sp_ref.html#byref"><code>ref</code> (参照渡し)</a>で持てるようになりました。
これを <strong id="key-ref-field" class="keyword">ref フィールド</strong>(ref field)と言います。</p>
<p>ref フィールドの書き方は参照引数や参照戻り値と同じく、型の前に <code>ref</code> 修飾を付けます。</p>
<pre class="source" title="ref フィールド">
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">ByReference</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="type param">T</span> <span class="field">Value</span>;
}
</pre>
<p>C# 7.2 に頃に <a href="https://ufcpp.net/study/csharp/resource/span/#fast-span"><code>Span&lt;T&gt;</code> 構造体の内部的な話</a>で、「<code>Span&lt;T&gt;</code> はランタイム側で特殊処理を入れている」というような話を書いていましたが、
ref フィールドが入ったことで、通常の C# コードで同様のことができるようになりました。
実際、.NET 7 からはそういう実装に置き換わっていて、<code>Span&lt;T&gt;</code> の内部は晴れて以下のようなコードに変更されています。</p>
<pre class="source" title=".NET 7 での Span の中身">
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Span</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">internal</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="type param">T</span> <span class="field">_reference</span>;
    <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="field">_length</span>;
}
</pre>
<p>ちなみに、ref フィールドを持てるのは ref 構造体だけです。
以下のコードはコンパイル エラーになります。</p>
<pre class="source" title="">
<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">ref</span> <span class="reserved">int</span> <span class="field"><span class="error" title="CS9059">_x</span></span>; <span class="comment">// class 中はダメ。</span>
}

<span class="reserved">struct</span> <span class="type struct">B</span>
{
    <span class="reserved">ref</span> <span class="reserved">int</span> <span class="field"><span class="error" title="CS9059">_x</span></span>; <span class="comment">// struct も ref がついてないものの中はダメ。</span>
}
</pre>
<h3><a id="readonly-ref">readonly ref</a></h3>
<p>C# 7.2 の頃に <a href="https://ufcpp.net/study/csharp/sp_ref.html?p=2#ref-readonly"><code>ref readonly</code></a> というものがありました。
これは、「参照先の値の変更不可」というものです。
一方で、ref フィールドになると、<code>ref readonly</code> と <code>readonly ref</code> の2種類の readonly ができます(あるいは両方付けて <code>readonly ref readonly</code> もできます)。</p>
<p>比較のためにまず、どちらの readonly もついていない状態ですが、
当然、「どこを参照するか変更」と「参照先の値の変更」のどちらもできます。</p>
<pre class="source" title="✔「どこを参照するか変更」と✔「参照先の値の変更」">
<span class="reserved">scoped</span> <span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">A</span>();

<span class="reserved">int</span> <span class="variable">x1</span> <span class="operator">=</span> <span class="number">0</span>;
<span class="variable">a</span><span class="operator">.</span><span class="field">X</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x1</span>; <span class="comment">// どこを参照するかを変更。</span>

<span class="variable">a</span><span class="operator">.</span><span class="field">X</span> <span class="operator">=</span> <span class="number">2</span>; <span class="comment">// 参照先の値を変更</span>

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="reserved">public</span> <em><span class="reserved">ref</span></em> <span class="reserved">int</span> <span class="field">X</span>;
}
</pre>
<p>で、<code>ref readonly</code> の方は C# 7.2 の頃からある意味と同じで、「参照先の値の変更不可」です。</p>
<pre class="source" title="✔「どこを参照するか変更」と✖「参照先の値の変更」">
<span class="reserved">scoped</span> <span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">A</span>();

<span class="reserved">int</span> <span class="variable">x1</span> <span class="operator">=</span> <span class="number">0</span>;
<span class="variable">a</span><span class="operator">.</span><span class="field">X</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x1</span>; <span class="comment">// どこを参照するかを変更。</span>

<span class="variable"><span class="error" title="CS8331">a</span><span class="operator">.</span><span class="field">X</span></span> <span class="operator">=</span> <span class="number">2</span>; <span class="comment">// エラー: 参照先の値を変更不可。</span>

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="reserved">public</span> <em><span class="reserved">ref</span> <span class="reserved">readonly</span></em> <span class="reserved">int</span> <span class="field">X</span>;
}
</pre>
<p>一方、C# 11 から書ける <code>readonly ref</code> は、要は、ref フィールド <code>ref T X</code> を readonly にするという意味なので、「どこを参照するか変更」の方ができなくなります。</p>
<pre class="source" title="✖「どこを参照するか変更」と✔「参照先の値の変更」">
<span class="reserved">int</span> <span class="variable">x0</span> <span class="operator">=</span> <span class="number">0</span>;

<span class="comment">// readonly フィールドはコンストラクターでしか初期化できないので引数で渡す。</span>
<span class="reserved">scoped</span> <span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">A</span>(<span class="reserved">ref</span> <span class="variable">x0</span>);

<span class="reserved">int</span> <span class="variable">x1</span> <span class="operator">=</span> <span class="number">1</span>;
<span class="variable"><span class="error" title="CS0191">a</span><span class="operator">.</span><span class="field">X</span></span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x1</span>; <span class="comment">// エラー: どこを参照するかを変更不可。</span>

<span class="variable">a</span><span class="operator">.</span><span class="field">X</span> <span class="operator">=</span> <span class="number">2</span>; <span class="comment">// 参照先の値を変更はできる。</span>

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="reserved">public</span> <em><span class="reserved">readonly</span> <span class="reserved">ref</span></em> <span class="reserved">int</span> <span class="field">X</span>;
    <span class="reserved">public</span> <span class="type struct">A</span>(<span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="field">X</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span>;
}
</pre>
<p>当然、両方の <code>readonly</code> を付けると両方不可です。</p>
<pre class="source" title="✖「どこを参照するか変更」と✖「参照先の値の変更」">
<span class="reserved">int</span> <span class="variable">x0</span> <span class="operator">=</span> <span class="number">0</span>;

<span class="comment">// readonly フィールドはコンストラクターでしか初期化できないので引数で渡す。</span>
<span class="reserved">scoped</span> <span class="type struct">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">A</span>(<span class="reserved">ref</span> <span class="variable">x0</span>);

<span class="reserved">int</span> <span class="variable">x1</span> <span class="operator">=</span> <span class="number">1</span>;
<span class="variable"><span class="error" title="CS0191">a</span><span class="operator">.</span><span class="field">X</span></span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x1</span>; <span class="comment">// エラー: どこを参照するかを変更不可。</span>

<span class="variable"><span class="error" title="CS8331">a</span><span class="operator">.</span><span class="field">X</span></span> <span class="operator">=</span> <span class="number">2</span>; <span class="comment">// エラー: 参照先の値を変更不可。</span>

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="field">X</span>;
    <span class="reserved">public</span> <span class="type struct">A</span>(<span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="field">X</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span>;
}
</pre>
<h2><a id="escape-analysis">エスケープ解析</a></h2>
<p>参照を使う上では、「漏らしてはいけないものを漏らさない」ということが必要になります。
簡単に言うと、メソッド内のローカル変数はメソッドを抜けると消えるので、
その参照は外に漏らしてはいけません。</p>
<pre class="source" title="ローカル変数への参照は外に漏らせない">
<span class="reserved">static</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method"><span class="static">M</span></span>()
{
    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>; <span class="comment">// メソッド内の変数はメソッド抜けると消える。</span>
    <span class="control">return</span> <span class="reserved">ref</span> <span class="variable"><span class="error" title="CS8168">x</span></span>; <span class="comment">// エラー: 消えるものと外には漏らせない。</span>
}
</pre>
<p>こういう「漏れている」状態を「エスケープ(escape: 脱走)している」と言います。</p>
<p>上記の例の場合は単純ですが、
参照変数などがあるため、間接的に何段も追いかける必要があります。</p>
<pre class="source" title="エスケープ阻止のため、多段に追う必要あり">
<span class="reserved">static</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="static"><span class="method">M</span></span>()
{
    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>; <span class="comment">// メソッド内の変数はメソッド抜けると消える。</span>
    <span class="reserved">ref</span> <span class="reserved">var</span> <span class="variable">y</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">x</span>;
    <span class="reserved">ref</span> <span class="reserved">var</span> <span class="variable">z</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable">y</span>;
    <span class="control">return</span> <span class="reserved">ref</span> <span class="variable"><span class="error" title="CS8157">z</span></span>; <span class="comment">// エラー: 間に2段挟まっているものの、元は x なので外に漏らせない。</span>
}
</pre>
<p>このように、間に何段か挟まっていようと、大本をたどってエスケープを避ける処理を「<strong id="key-escape-analysis" class="keyword">エスケープ解析</strong>」(escape analysis)と呼びます。</p>
<p>C# 7.2 で ref 構造体が、
C# 11 で ref フィールドが入ったわけですが、
エスケープ解析はこれらも考慮する必要があります。</p>
<p>例えばわざとちょっと複雑なことをすると、以下のように、いろいろなところに参照が伝搬するコードが書けます。</p>
<pre class="source" title="参照がいろんなところに伝搬する例">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">out</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">result</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>;
    <span class="reserved">var</span> <span class="variable">span</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;(<span class="reserved">ref</span> <span class="variable">x</span>); <span class="comment">// x が span から参照される状態。</span>
    <span class="reserved">scoped</span> <span class="reserved">var</span> <span class="variable">r</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">R</span>();

    <span class="reserved">var</span> <span class="variable">ret</span> <span class="operator">=</span> <span class="variable">r</span><span class="operator">.</span><span class="method">M</span>(<span class="variable">span</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">y</span>); <span class="comment">// x がいろんなところに伝搬。</span>

    <span class="variable local">result</span> <span class="operator">=</span> <span class="error" title="CS8352"><span class="variable">r</span><span class="operator">.</span><span class="field">Span</span></span>; <span class="comment">// エラー: x が r.Span に伝搬してるかもしれないのでダメ。</span>
    <span class="variable local">result</span> <span class="operator">=</span> <span class="variable"><span class="error" title="CS8352">y</span></span>;      <span class="comment">// エラー: x が y に伝搬してるかもしれないのでダメ。</span>
    <span class="variable local">result</span> <span class="operator">=</span> <span class="error" title="CS8352"><span class="variable">ret</span></span>;    <span class="comment">// エラー: x が ret に伝搬してるかもしれないのでダメ。</span>
}

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">R</span>
{
    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="field">Span</span>;

    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="method">M</span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">x</span>, <span class="reserved">out</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>)
    {
        <span class="field">Span</span> <span class="operator">=</span> <span class="variable local">x</span>; <span class="comment">// フィールドにも、</span>
        <span class="variable local">y</span> <span class="operator">=</span> <span class="variable local">x</span>;    <span class="comment">// out 引数にも、</span>
        <span class="control">return</span> <span class="variable local">x</span>; <span class="comment">// 戻り値にも x (が持ってる参照)が伝搬。</span>
    }
}
</pre>
<p>コスト度外視でよければ、
「どの引数・フィールドが、他のどの引数・フィールド・戻り値に伝搬するか」を事細かに指定することで厳密なエスケープ解析ができます。
(C# では採用しなかったため)仮定的なコードにはなりますが、
先ほどのコードを以下のように書けるようにするという案はなくはないです。</p>
<pre class="source" title="(仮定的なコードで) 参照の伝搬をすべて明示">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">out</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">result</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>;
    <span class="reserved">var</span> <span class="variable">span1</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;(<span class="reserved">ref</span> <span class="variable">x</span>); <span class="comment">// x が span から参照される状態。</span>
    <span class="reserved">var</span> <span class="variable">span2</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="reserved">int</span>[<span class="number">1</span>];           <span class="comment">// こちらは配列を参照しているので外に漏らしても大丈夫。</span>

    <span class="reserved">var</span> <span class="variable">r</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">R</span> { <span class="field">Span</span> <span class="operator">=</span> <span class="variable">span1</span> };

    <span class="reserved">var</span> <span class="variable">ret</span> <span class="operator">=</span> <span class="variable">r</span><span class="operator">.</span><span class="method">M</span>(<span class="variable">span2</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">y</span>); <span class="comment">// span2 → y, span1 → r.Span → ret と伝搬。</span>

    <span class="variable local">result</span> <span class="operator">=</span> <span class="variable">y</span>;      <span class="comment">// 出どころが y → span2 → 配列 なので外に漏らして大丈夫。</span>
    <span class="variable local">result</span> <span class="operator">=</span> <span class="error"><span class="variable">ret</span></span>;    <span class="comment">// 出どころが ret → r.Span → span1 → x なのでダメ。</span>
}

<span class="comment">// 仮定的な文法: ` で、参照の伝搬先を表現。</span>
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">R</span>
{
    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;</span><em>`A</em> <span class="field">Span</span>;

    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;</span><em>`A</em> <span class="method">M</span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;</span><em>`B</em> <span class="variable local">x</span>, <span class="reserved">out</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;<em>`B</em> <span class="variable local">y</span>)
    {
        <span class="comment">// 伝搬先の指定が違うので、以下のコードはダメ。</span>
        <span class="comment">// Span = x;</span>
        <span class="comment">// return x;</span>
        <span class="variable local">y</span> <span class="operator">=</span> <span class="variable local">x</span>;       <span class="comment">// `B 間の伝搬は OK。</span>
        <span class="control">return</span> <span class="field">Span</span>; <span class="comment">// `A 間の伝搬は OK。</span>
    }
}
</pre>
<h3><a id="scoped-modifier">scoped 修飾子</a></h3>
<p>ただ、ここまで細かい指定に需要があるかというと微妙です。
そこで C# 11 では、以下の2種類だけに絞ることにしました。</p>
<ul>
<li>scoped: どこにも漏らさない。メソッドの中でだけ使う。</li>
<li>unscoped: どこかに漏らす。</li>
</ul>
<p>ref 構造体(<code>Span&lt;T&gt;</code> など)に関しては実際にこの2択で、
何もつかなかった場合は unscoped 扱いで、<code>scoped</code> という新しい修飾子を付けると scoped 扱いになります。</p>
<p>一方で、<code>ref T</code> (<code>ref</code> 引数・<code>ref</code> 変数)に関しては、
既存コードを壊さないように、何もつけないと「引数から戻り値への伝搬だけ認める」(通称 return-only)というわかりにくいルールになっています。
そして、<code>UnscopedRef</code> 属性(<code>System.Diagnostics.CodeAnalysis</code> 名前空間)を付けると unscoped 扱い、
<code>scoped</code> 修飾子を付けると scoped 扱いになります。
(またちょっとややこしいことに、コンストラクターの引数の場合だけ、<code>ref T</code> でも unscoped 扱いみたいです。)</p>
<p>実際のコードを見てみましょう。
まず、何もつけない場合(<code>ref T</code> は return-only、ref 構造体は unscoped):</p>
<pre class="source" title="何もつけない: ref T は return-only、ref 構造体は unscoped">
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Default</span>
{
    <span class="reserved">private</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="field">_x</span>;
    <span class="reserved">private</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="field">_y</span>;

    <span class="comment">// OK なやつ。</span>
    <span class="reserved">public</span> <span class="type struct">Default</span>(<span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="field">_x</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span>;
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method">ReturnRef</span>(<span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="variable local">x</span>;
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method">GetRef</span>() <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="field">_x</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">UseRef</span>(<span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) { }

    <span class="reserved">public</span> <span class="type struct">Default</span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="field">_y</span> <span class="operator">=</span> <span class="variable local">y</span>;
    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="method">ReturnSpan</span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="variable local">y</span>;
    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="method">GetSpan</span>() <span class="operator">=&gt;</span> <span class="field">_y</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetSpan</span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="field">_y</span> <span class="operator">=</span> <span class="variable local">y</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">UseSpan</span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) { }

    <span class="comment">// エラーになるやつ。</span>
    <span class="comment">// 引数 → フィールドへの伝搬だけ、ref T と Span&lt;T&gt; の挙動が違う。</span>
    <span class="comment">// ref T は「引数 → 戻り値 だけは OK」(return-only)。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetRef</span>(<span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="error" title="CS9079"><span class="field">_x</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span></span>;
}
</pre>
<p>続いて、<code>scoped</code> 修飾子を付けた場合(いずれも scoped 扱い)、たいていのものがダメになります:</p>
<pre class="source" title="scoped 修飾子を付けた場合">
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Scoped</span>
{
    <span class="reserved">private</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="field">_x</span>;
    <span class="reserved">private</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="field">_y</span>;

    <span class="comment">// OK なやつ。</span>
    <span class="comment">// フィールドにも戻りにも伝搬しない場合だけ OK。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">UseRef</span>(<span class="reserved">scoped</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">UseSpan</span>(<span class="reserved">scoped</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) { }

    <span class="comment">// エラーになるやつ。</span>
    <span class="comment">// たいていダメ。</span>
    <span class="reserved">public</span> <span class="type struct">Scoped</span>(<span class="reserved">scoped</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="error" title="CS8374"><span class="field">_x</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span></span>;
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method">ReturnRef</span>(<span class="reserved">scoped</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="variable local"><span class="error" title="CS9075">x</span></span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetRef</span>(<span class="reserved">scoped</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="error" title="CS8374"><span class="field">_x</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span></span>;

    <span class="reserved">public</span> <span class="type struct">Scoped</span>(<span class="reserved">scoped</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="field">_y</span> <span class="operator">=</span> <span class="variable local"><span class="error" title="CS8352">y</span></span>;
    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="method">ReturnSpan</span>(<span class="reserved">scoped</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="error" title="CS8352"><span class="variable local">y</span></span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetSpan</span>(<span class="reserved">scoped</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="field">_y</span> <span class="operator">=</span> <span class="variable local"><span class="error" title="CS8352">y</span></span>;
}
</pre>
<p>最後に、<code>UnscopedRef</code> 属性を付けた場合、たいていのものが OK になります
(ただし、ref 構造体は何も付けなくても unscoped 扱いなので、追加で属性を付けようとするとエラーになります):</p>
<pre class="source" title="">
<span class="reserved">using</span> System<span class="operator">.</span>Diagnostics<span class="operator">.</span>CodeAnalysis;

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Unscoped</span>
{
    <span class="reserved">private</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="field">_x</span>;
    <span class="reserved">private</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="field">_y</span>;

    <span class="comment">// OK なやつ。</span>
    <span class="comment">// UnscopedRef 属性を付けるとなんでも OK に。</span>
    <span class="comment">// (といっても差が出るのは SetRef だけ。)</span>
    <span class="reserved">public</span> <span class="type struct">Unscoped</span>([<span class="type">UnscopedRef</span>] <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="field">_x</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span>;
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method">ReturnRef</span>([<span class="type">UnscopedRef</span>] <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="variable local">x</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetRef</span>([<span class="type">UnscopedRef</span>] <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="field">_x</span> <span class="operator">=</span> <span class="reserved">ref</span> <span class="variable local">x</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">UseRef</span>([<span class="type">UnscopedRef</span>] <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">x</span>) { }

    <span class="comment">// Span の方は「デフォルトで UnscopedRef だから属性付けるな」とエラーになる。</span>
    <span class="reserved">public</span> <span class="type struct">Unscoped</span>([<span class="type"><span class="error" title="CS9063">UnscopedRef</span></span>] <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="field">_y</span> <span class="operator">=</span> <span class="variable local">y</span>;
    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="method">ReturnSpan</span>([<span class="type"><span class="error" title="CS9063">UnscopedRef</span></span>] <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="variable local">y</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetSpan</span>([<span class="error" title="CS9063"><span class="type">UnscopedRef</span></span>] <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="field">_y</span> <span class="operator">=</span> <span class="variable local">y</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">UseSpan</span>([<span class="type"><span class="error" title="CS9063">UnscopedRef</span></span>] <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">y</span>) { }
}
</pre>
<h3><a id="caller">呼び出し元の挙動</a></h3>
<p>この手の機能は、
「メソッド内でできることを制限する代わりに、呼び出し元でできることを増やす」というものです。</p>
<p>例えば、unscoped (何も修飾子を付けていない ref 構造体)の場合、以下のように、
<code>Builder.Replace</code> の中で制限がない代わり、それを呼んでいる場所でのエラーが増えます。</p>
<pre class="source" title="unscoped な挙動">
<span class="reserved">var</span> <span class="variable">builder</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">Builder</span>();

<span class="static"><span class="method">Replace</span></span>(<span class="reserved">ref</span> <span class="variable">builder</span>);

<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">Replace</span></span>(<span class="reserved">ref</span> <span class="type struct">Builder</span> <span class="variable local">builder</span>)
{
    <span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable">newBuffer</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="reserved">char</span>[<span class="number">3</span>];
    <span class="error" title="CS8350"><span class="variable local">builder</span><span class="operator">.</span><span class="method">Replace</span>(<span class="error" title="CS8352"><span class="variable">newBuffer</span></span>)</span>; <span class="comment">// ダメ。stackalloc したものが builder 越しに外に漏れる。</span>
}

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Builder</span>(<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">initialBuffer</span>)
{
    <span class="reserved">private</span> <span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="field">_buffer</span> <span class="operator">=</span> <span class="variable local">initialBuffer</span>;

    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Replace</span>(<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">value</span>)
    {
        <span class="comment">// 参照先自体を書き換え。</span>
        <span class="comment">// 引数からフィールドに参照が伝搬。</span>
        <span class="field">_buffer</span> <span class="operator">=</span> <span class="variable local">value</span>;
    }
}
</pre>
<p>一方、scoped (<code>scoped</code> 修飾子を付けている)の場合、以下のように、
<code>Builder.Replace</code> の中で制限が掛かる代わり、それを呼んでいる場所でのエラーがなくなります。</p>
<pre class="source" title="">
<span class="reserved">var</span> <span class="variable">builder</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">Builder</span>();

<span class="static"><span class="method">Append</span></span>(<span class="reserved">ref</span> <span class="variable">builder</span>);

<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">Append</span></span>(<span class="reserved">ref</span> <span class="type struct">Builder</span> <span class="variable local">builder</span>)
{
    <span class="type struct">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">buffer</span> <span class="operator">=</span> [<span class="number">0x61</span>, <span class="number">0x62</span>, <span class="number">0x63</span>];
    <span class="variable local">builder</span><span class="operator">.</span><span class="method">Append</span>(<span class="variable">buffer</span>); <span class="comment">// 同じようなことをしていてもこれは OK。</span>
}


<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Builder</span>(<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">initialBuffer</span>)
{
    <span class="reserved">private</span> <span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="field">_buffer</span> <span class="operator">=</span> <span class="variable local">initialBuffer</span>;

    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Append</span>(<span class="reserved">scoped</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable local">utf8</span>)
    {
        <span class="comment">// 中身を書き換え。参照先自体は元のまま。</span>
        <span class="comment">// 引数の参照はどこにも漏らさない。</span>
        System<span class="operator">.</span>Text<span class="operator">.</span><span class="type">Encoding</span><span class="operator">.</span><span class="static"><span class="property">UTF8</span></span><span class="operator">.</span><span class="method">GetChars</span>(<span class="variable local">utf8</span>, <span class="field">_buffer</span>);
    }
}
</pre>
<p>ちなみに、内部的には <code>scoped</code> 修飾子の方も属性で表現されています。
<code>scoped</code> 修飾子を付けた引数には <code>ScopedRef</code> 属性が付きます。
(ユーザーが自分の手でこの属性を付けることは認められていません。)</p>
<h3><a id="ref-this">構造体の this</a></h3>
<p>構造体の <code>this</code> は参照になっています。
この参照はデフォルトで scoped 扱いになっていて、外に漏らすことができません。</p>
<pre class="source" title="this は scoped 扱い">
<span class="reserved">using</span> System<span class="operator">.</span>Diagnostics<span class="operator">.</span>CodeAnalysis;

<span class="reserved">struct</span> <span class="type struct">S</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_x</span>;

    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="type struct">S</span> <span class="method">RefThis</span>() <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="reserved"><span class="error" title="CS8170">this</span></span>;

    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method">RefX</span>() <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="field"><span class="error" title="CS8170">_x</span></span>;
}
</pre>
<p>この挙動を変えるのにも <code>UnscopedRef</code> 属性が使えます。
メソッド自身に <code>UnscopedRef</code> 属性を付けることで、<code>this</code> が unscoped 扱いになります。</p>
<pre class="source" title="this を unscoped 扱いに変更">
<span class="reserved">using</span> System<span class="operator">.</span>Diagnostics<span class="operator">.</span>CodeAnalysis;

<span class="reserved">struct</span> <span class="type struct">S</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_x</span>;

    [<span class="type">UnscopedRef</span>]
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="type struct">S</span> <span class="method">RefThis</span>() <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="reserved">this</span>;

    [<span class="type">UnscopedRef</span>]
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="method">RefX</span>() <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="field">_x</span>;
}
</pre>
<h2><a id="ref-struct-interface">ref 構造体のインターフェイス実装</a></h2>
<h5 class="version version13">Ver. 13</h5>
<p>C# 13 で、ref 構造体にインターフェイスを実装できるようになりました。
例えば以下のようなコードを書いてもエラーを起こしません。</p>
<pre class="source" title="ref 構造体にインターフェイスを実装する例">
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">S</span> : <span class="type">IFormattable</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="method">ToString</span>(<span class="reserved">string</span><span class="operator">?</span> <span class="variable local">format</span>, <span class="type">IFormatProvider</span><span class="operator">?</span> <span class="variable local">formatProvider</span>) <span class="operator">=&gt;</span> <span class="string">&quot;&quot;</span>;
}
</pre>
<p>ただ、前述の<a href="https://ufcpp.net/study/csharp/resource/refstruct/#stack-only">「スタックのみ」制約</a>のせいで直接インターフェイス型の変数に代入することは C# 13 でもできません。
以下のコードは引き続きエラーになります。</p>
<pre class="source" title="インターフェイスを実装できるようになったのに、インターフェイスに代入できない">
<span class="type">IFormattable</span> <span class="variable">f</span> <span class="operator">=</span> <span class="error" title="CS0029"><span class="reserved">new</span> <span class="type struct">S</span>()</span>;

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">S</span> : <span class="type">IFormattable</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="method">ToString</span>(<span class="reserved">string</span><span class="operator">?</span> <span class="variable local">format</span>, <span class="type">IFormatProvider</span><span class="operator">?</span> <span class="variable local">formatProvider</span>) <span class="operator">=&gt;</span> <span class="string">&quot;&quot;</span>;
}
</pre>
<p><a href="https://ufcpp.net/study/csharp/RmBoxing.html#boxing">ボックス化</a>を起こさないようにインターフェイス活用しようと思うと<a href="https://ufcpp.net/study/csharp/sp2_generics.html">ジェネリクス</a>が必要になります。</p>
<pre class="source" title="ジェネリクスでボックス化回避">
<span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">123</span>; <span class="comment">// int は IFormattable を実装してる。</span>

<span class="comment">// これはボックス化を起こす。</span>
<span class="type">IFormattable</span> <span class="variable">f</span> <span class="operator">=</span> <span class="variable">x</span>;
<span class="variable">f</span><span class="operator">.</span><span class="method">ToString</span>(<span class="string">&quot;X&quot;</span>, <span class="reserved">null</span>);

<span class="comment">// ジェネリックメソッドを介して、</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span> <span class="variable local">f</span>) <span class="reserved">where</span> <span class="type param">T</span> : <span class="type">IFormattable</span>
    <span class="operator">=&gt;</span> <span class="variable local">f</span><span class="operator">.</span><span class="method">ToString</span>(<span class="string">&quot;X&quot;</span>, <span class="reserved">null</span>);

<span class="comment">// こうやって IFormattable.ToString を呼べばボックス化を回避できる。</span>
<span class="static"><span class="method">M</span></span>(<span class="variable">x</span>);
</pre>
<p>したがって、この機能の肝は「ref 構造体をジェネリクスで使えるようにする」ということになります。</p>
<h3><a id="allows-ref-struct">allows ref struct</a></h3>
<p>ref 構造体に課せられている「ボックス化できない」などの制限は、C# のジェネリクスにとっては後付けなので、
そのままでは「ref 構造体の制限を満たしている」ということを保証できません。
例えば以下のコードは C# 2 以来ずっと合法なわけですが、
ボックス化を起こすコードなので ref 構造体に適しません。</p>
<pre class="source" title="">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span> <span class="variable local">f</span>) <span class="reserved">where</span> <span class="type param">T</span> : <span class="type">IFormattable</span>
{
    <span class="comment">// object に代入するとボックス化。</span>
    <span class="reserved">object</span> <span class="variable">o</span> <span class="operator">=</span> <span class="variable local">f</span>;

    <span class="comment">// WriteLine(object) なので、これも「object への変換」でボックス化。</span>
    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable local">f</span>);

    <span class="comment">// 何ならインターフェイスへの代入でもボックス化。</span>
    <span class="type">IFormattable</span> <span class="variable">f1</span> <span class="operator">=</span> <span class="variable local">f</span>;
}

<span class="static"><span class="method">M</span></span>(<span class="number">123</span>);
</pre>
<p>そこで C# 13 で、<code>allows ref struct</code> というものが追加されました。
型制約の <code>where</code> 句にこの条件を書くと、型引数に ref 構造体を渡せるようになります。</p>
<pre class="source" title="">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">T</span>&gt;() <span class="reserved">where</span> <span class="type param">T</span> : <em><span class="reserved">allows</span> <span class="reserved">ref</span> <span class="reserved">struct</span></em>
{
}

<span class="comment">// これまで使えていた型は引き続き使える。</span>
<span class="static"><span class="method">M</span></span>&lt;<span class="reserved">string</span>&gt;();
<span class="static"><span class="method">M</span></span>&lt;<span class="reserved">int</span>&gt;();

<span class="comment">// これまで使えなかった ref 構造体にも使えるようになる。</span>
<span class="static"><span class="method">M</span></span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;&gt;();
<span class="static"><span class="method">M</span></span>&lt;<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">char</span>&gt;&gt;();
</pre>
<p>その代わり、<code>allows ref struct</code> を付けると、メソッド内でボックス化を起こすようなコードを書けなくなります。</p>
<pre class="source" title="allows ref struct な型の変数はボックス化できない">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">T</span>&gt;() <span class="reserved">where</span> <span class="type param">T</span> : <span class="reserved">allows</span> <span class="reserved">ref</span> <span class="reserved">struct</span>
{
    <span class="comment">// 先ほどのボックス化を起こすコードはすべてエラーに。</span>
    <span class="reserved">object</span> <span class="variable">o</span> <span class="operator">=</span> <span class="error" title="CS0103">f</span>;
    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="error" title="CS0103">f</span>);
    <span class="type">IFormattable</span> <span class="variable">f1</span> <span class="operator">=</span> <span class="error" title="CS0103">f</span>;
}
</pre>
<p>ちなみに、通常の制約が「メソッド内でできることが増える代わりに、渡せる型が減る」というものなのに対して、
<code>allows ref struct</code> は「メソッド内でできることを減らす代わりに、渡せるが型が増える」ものになっていて、
これを「<a href="https://ufcpp.net/study/csharp/sp2_generics.html#anti-constraint">アンチ制約</a>」と呼びます。</p>
<p>これで、ボックス化を起こさないようにインターフェイスのメンバーを呼べるようになったので、
ref 構造体のインターフェイス実装を活用できるようになります。</p>
<pre class="source" title="allows ref struct なジェネリック メソッドを介して、ref 構造体のインターフェイス実装を呼ぶ">
<span class="type struct">S</span> <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">new</span>(); <span class="comment">// S は IFormattable を実装してる。</span>

<span class="comment">// これはボックス化を起こすから C# 13 でもエラーになる。</span>
<span class="type">IFormattable</span> <span class="variable">f</span> <span class="operator">=</span> <span class="variable"><span class="error" title="CS0029">x</span></span>;
<span class="variable">f</span><span class="operator">.</span><span class="method">ToString</span>(<span class="string">&quot;X&quot;</span>, <span class="reserved">null</span>);

<span class="comment">// allows ref struct なジェネリックメソッドを介して、</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span> <span class="variable local">f</span>) <span class="reserved">where</span> <span class="type param">T</span> : <span class="type">IFormattable</span>, <span class="reserved">allows</span> <span class="reserved">ref</span> <span class="reserved">struct</span>
    <span class="operator">=&gt;</span> <span class="variable local">f</span><span class="operator">.</span><span class="method">ToString</span>(<span class="string">&quot;X&quot;</span>, <span class="reserved">null</span>);

<span class="comment">// こうやって IFormattable.ToString を呼べば大丈夫になった。</span>
<span class="method"><span class="static">M</span></span>(<span class="variable">x</span>);

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">S</span> : <span class="type">IFormattable</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="method">ToString</span>(<span class="reserved">string</span><span class="operator">?</span> <span class="variable local">format</span>, <span class="type">IFormatProvider</span><span class="operator">?</span> <span class="variable local">formatProvider</span>) <span class="operator">=&gt;</span> <span class="string">&quot;&quot;</span>;
}
</pre>
<h4><a id="bcl-allows-ref-struct">標準ライブラリ中の allows ref struct</a></h4>
<p>C# 13 で <code>allows ref struct</code> が追加されると同時に、
.NET 9 では、標準ライブラリ中のジェネリックなデリゲート型の大部分と、一部のインターフェイスの型引数に <code>allows ref struct</code> が付きました。
以下のようなコードが書けるようになっています。</p>
<pre class="source" title="多くのデリゲート、一部のインターフェイスに allows ref struct">
<span class="reserved">using</span> System<span class="operator">.</span>Diagnostics<span class="operator">.</span>CodeAnalysis;

<span class="comment">// 多くのデリゲートの型引数に allows ref struct が付いた。</span>
<span class="type">Action</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt;&gt; <span class="variable">a</span> <span class="operator">=</span> <span class="variable local">x</span> <span class="operator">=&gt;</span> <span class="string">&quot;123&quot;</span><span class="operator">.</span><span class="method">TryCopyTo</span>(<span class="variable local">x</span>);
<span class="type">Func</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt;, <span class="reserved">int</span>&gt; <span class="variable">b</span> <span class="operator">=</span> <span class="variable local">x</span> <span class="operator">=&gt;</span> <span class="variable local">x</span><span class="operator">.</span><span class="method">IndexOf</span>(<span class="string">'1'</span>);
<span class="type">Predicate</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt;&gt; <span class="variable">c</span> <span class="operator">=</span> <span class="variable local">x</span> <span class="operator">=&gt;</span> <span class="variable local">x</span><span class="operator">.</span><span class="method">Contains</span>(<span class="string">'1'</span>);
<span class="type">Comparison</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt;&gt; <span class="variable">d</span> <span class="operator">=</span> (<span class="variable local">x</span>, <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span><span class="operator">.</span><span class="method">SequenceCompareTo</span>(<span class="variable local">y</span>);
<span class="type">Converter</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt;, <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">char</span>&gt;&gt; <span class="variable">e</span> <span class="operator">=</span> <span class="variable local">x</span> <span class="operator">=&gt;</span> <span class="variable local">x</span>;

<span class="comment">// 比較系のインターフェイスには大体 allows ref struct が付いた。</span>
<span class="reserved">class</span> <span class="type">C</span> : <span class="type">IComparer</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt;&gt;, <span class="type">IEqualityComparer</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt;&gt;
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="method">Compare</span>(<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">x</span>, <span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;
    <span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">Equals</span>(<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">x</span>, <span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">true</span>;
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="method">GetHashCode</span>([<span class="type">DisallowNull</span>] <span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">obj</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;
}

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">S</span> : <span class="type">IEquatable</span>&lt;<span class="type struct">S</span>&gt;, <span class="type">IComparable</span>&lt;<span class="type struct">S</span>&gt;
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="method">CompareTo</span>(<span class="type struct">S</span> <span class="variable local">other</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;
    <span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">Equals</span>(<span class="type struct">S</span> <span class="variable local">other</span>) <span class="operator">=&gt;</span> <span class="reserved">true</span>;
}
</pre>
<h5><a id="ref-struct-delegate">余談: ref 構造体引数のデリゲートの自然な型</a></h5>
<p>C# 10 の頃にデリゲートに<a href="https://ufcpp.net/study/csharp/sp_delegate.html#natural-type">自然な型</a>が入りましたが、
「可能であれば <code>Action</code>、<code>Action&lt;T&gt;</code>、<code>Func&lt;T&gt;</code> を使う」という仕様になっています。
これに対して、.NET 9 でこれらのデリゲートに <code>allows ref strcut</code> が付いたことで、「可能であれば」の範囲が広がっています。
これまでだと匿名のデリゲート型になっていたものが、<code>Action</code> や <code>Func</code> に変わることがあります。</p>
<pre class="source" title=".NET 8 から 9 で型が変わる例">
<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> (<span class="type struct">Span</span>&lt;<span class="reserved">char</span>&gt; <span class="variable local">s</span>) <span class="operator">=&gt;</span> { };

<span class="comment">// .NET 8 以前だと: &lt;&gt;f__AnonymousDelegate0</span>
<span class="comment">// .NET 9 以降だと: Action`1</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">a</span><span class="operator">.</span><span class="method">GetType</span>()<span class="operator">.</span><span class="property">Name</span>);
</pre>
<h4><a id="ienumerable-not-allow">余談: IEnumerable 問題</a></h4>
<p>ref 構造体がらみで非常に多い要望の1つに、<code>Span&lt;T&gt;</code>、<code>ReadOnlySpan&lt;T&gt;</code> に対して LINQ を使いたいというものがあります。
しかし、ref 構造体にインターフェイスを実装できるようになっても、<code>Span&lt;T&gt;</code> に <code>IEnumerable&lt;T&gt;</code> は実装できなくて、この要望はかないません。
問題は、以下のように、<code>IEnumerator&lt;T&gt;</code> インターフェイスを戻り値に返す部分が ref 構造体と合いません。</p>
<pre class="source" title="ref 構造体は IEnumerable と相性がよくない">
<span class="reserved">using</span> System<span class="operator">.</span>Collections;

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Span</span>&lt;<span class="type param">T</span>&gt; : <span class="type">IEnumerable</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="comment">// res 構造体に IEnumerator を実装するのは可能。</span>
    <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Enumerator</span>(<span class="type struct">Span</span>&lt;<span class="type param">T</span>&gt; <span class="variable local">span</span>) : <span class="type">IEnumerator</span>&lt;<span class="type param">T</span>&gt;
    {
        <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="type struct">Span</span>&lt;<span class="type param">T</span>&gt; <span class="field">_span</span> <span class="operator">=</span> <span class="variable local">span</span>;
        <span class="reserved">public</span> <span class="type param">T</span> <span class="property">Current</span> <span class="operator">=&gt;</span> <span class="reserved">default</span><span class="operator">!</span>;
        <span class="reserved">object</span> <span class="type">IEnumerator</span><span class="operator">.</span><span class="property">Current</span> <span class="operator">=&gt;</span> <span class="reserved">null</span><span class="operator">!</span>;
        <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() { }
        <span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">MoveNext</span>() <span class="operator">=&gt;</span> <span class="reserved">false</span>;
        <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Reset</span>() { }
    }

    <span class="comment">// 問題はここ。</span>
    <span class="comment">// (ジェネリックを介さず) 直接 IEnumerator&lt;T&gt; インターフェイスを返す必要があって、ref 構造体に合わない。</span>
    <span class="reserved">public</span> <span class="type">IEnumerator</span>&lt;<span class="type param">T</span>&gt; <span class="method">GetEnumerator</span>() <span class="operator">=&gt;</span> <span class="error" title="CS0029"><span class="reserved">new</span> <span class="type struct">Enumerator</span>(<span class="reserved">this</span>)</span>;
    <span class="type">IEnumerator</span> <span class="type">IEnumerable</span><span class="operator">.</span><span class="method">GetEnumerator</span>() <span class="operator">=&gt;</span> <span class="method">GetEnumerator</span>();
}
</pre>
<p><code>IEnumerator&lt;T&gt;</code> の方であれば問題なく実装できるので、<code>IEnumerator&lt;T&gt;</code> 版の LINQ を用意した方がいいのかという話題も出ていたりします。</p>
 ]]></description>
				<pubDate>Sat, 22 Jun 2024 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>コレクション式</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/collection-expression/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<h5 class="version version12">Ver. 12</h5>
<p>C# 12 で、<code>[]</code> 記号を使って配列などの初期化ができるようになりました。
配列だけではなく、コレクション(<code>List&lt;T&gt;</code> 型など)、<code>Span&lt;T&gt;</code> なども全く同じ書き方で初期化できます。
これをコレクション式(collection expression)と言います。</p>
<pre class="source" title="コレクション式">
<span class="reserved">using</span> System<span class="operator">.</span>Collections<span class="operator">.</span>Immutable;

<span class="reserved">int</span>[] <span class="variable">array</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">list</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">ros</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type struct">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
</pre>
<p>また、コレクション式中では、<code>..</code> を使うことで「別のコレクションの中身の展開」ができます。
これを スプレッド (spread)演算子と言います。</p>
<pre class="source" title="">
<span class="reserved">int</span>[] <span class="variable">array1</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="reserved">int</span>[] <span class="variable">array2</span> <span class="operator">=</span> [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];

<span class="comment">// 0, 1, 2, 3, 4, 5, 6, 7</span>
<span class="reserved">int</span>[] <span class="variable">combined</span> <span class="operator">=</span> [<span class="number">0</span>, <em>..</em><span class="variable">array1</span>, <em>..</em><span class="variable">array2</span>, <span class="number">7</span>];
</pre>
<h2><a id="background">背景: これまでのコレクションの初期化</a></h2>
<p>これまでだと、以下のように型に応じて書き方を変える必要がありました。</p>
<pre class="source" title="これまでの書き方いろいろ">
<span class="reserved">using</span> System<span class="operator">.</span>Collections<span class="operator">.</span>Immutable;

<span class="reserved">int</span>[] <span class="variable">array1</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
<span class="reserved">int</span>[] <span class="variable">array2</span> <span class="operator">=</span> { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">list</span> <span class="operator">=</span> <span class="reserved">new</span>() { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <span class="reserved">stackalloc</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">ros</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
<span class="type struct">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> <span class="type"><span class="static">ImmutableArray</span></span><span class="operator">.</span><span class="method"><span class="static">Create</span></span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);
</pre>
<p>1つずつ、もう少し補足を加えます。</p>
<h4>配列(1)</h4>
<p><code>new[] { }</code> という書き方で配列を作れます。</p>
<pre class="source" title="配列の new">
<span class="reserved">int</span>[] <span class="variable">array1</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
</pre>
<p>正確にはこれは省略形で、本来の書き方では、<code>new T[length]</code> という書き方で配列を作ります。
ただし、<code>{}</code> (配列初期化子といいます)がついている場合、中身の数から長さが確定するので <code>new T[] { ... }</code> というように長さを省略できます。
また、<code>{}</code> の中身から型を推論できる場合には <code>T</code> の部分を省略できて、<code>new[] { ... }</code> と書けます。</p>
<p><code>new[] { ... }</code>の型推論は「要素の中身から型決定」なので、例えば以下のようなコードはエラーになります。</p>
<pre class="source" title="要素の型からの型推論">
<span class="reserved">byte</span>[] <span class="variable">array</span> <span class="comment">// byte[] 型</span>
    <span class="operator">=</span> <span class="error" title="CS0029"><span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> }</span>; <span class="comment">// 数値リテラルはデフォルトでは int 型。int からの型推論で int[] 型に。</span>
</pre>
<p>また、「要素の中身から型決定」だと、ブログ「<a href="https://ufcpp.net/blog/2022/11/covariantarrayincident/">共変配列事故</a>」で書いたような問題を踏むことがあります。</p>
<h4>配列(2)</h4>
<p>配列の変数宣言時に限り、以下のように <code>{}</code> だけで初期化できます。</p>
<pre class="source" title="配列初期化子">
<span class="reserved">int</span>[] <span class="variable">array2</span> <span class="operator">=</span> { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
</pre>
<p>宣言と初期化を別の行に分けてしまうと <code>{}</code> を使えなくなります。(<code>new[] { }</code> なら使えます)。</p>
<pre class="source" title="">
<span class="reserved">int</span>[] <span class="variable">array</span>; <span class="comment">// 宣言</span>

<span class="variable">array</span> <span class="operator">=</span> <span class="error" title="CS1525"><span class="error" title="CS1002">{</span></span> <span class="number">1</span><span class="error" title="CS1513"><span class="error" title="CS1002">,</span></span> <span class="number">2</span><span class="error" title="CS1513"><span class="error" title="CS1002">,</span></span> <span class="number">3</span> <span class="error" title="CS1002">}</span>; <span class="comment">// 宣言と別の行ではこの書き方はできない</span>
</pre>
<h4>コレクション初期化子</h4>
<p>所定の条件を満たす型に対して、<code>new T() { }</code> という書き方で初期化ができます。
これを<a href="https://ufcpp.net/study/csharp/sp3_lambda.html?key=collectioninit#collectioninit">コレクション初期化子</a>と言います。</p>
<p>これと、<a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver9/#target-typed-new">ターゲットからの型推論</a>を組み合わせると、以下のように <code>new() { }</code> という書き方で初期化できます。</p>
<pre class="source" title="">
<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">list</span> <span class="operator">=</span> <span class="reserved">new</span>() { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
</pre>
<p>配列の場合は <code>new[] { }</code> なのに対して、その他のコレクションは <code>new() { }</code> になります。
このせいで、「配列とその他のコレクションを切り替えて使う」みたいなことがちょっと面倒になっています。</p>
<pre class="source" title="配列とコレクションの切り替えが難しい">
<span class="preprocess">#</span><span class="preprocess">if</span> WPF
<span class="excluded">using System.Collections.ObjectModel;

// WPF の時だけ ObservableCollection を使う。
ObservableCollection&lt;int&gt;
</span><span class="preprocess">#</span><span class="preprocess">else</span>
<span class="comment">// 他はただの配列。</span>
<span class="reserved">int</span>[]
<span class="preprocess">#</span><span class="preprocess">endif</span>
    <span class="variable">list</span> <span class="operator">=</span> <span class="error" title="CS8752"><span class="reserved">new</span>() { <span class="number"><span class="error" title="CS1061">1</span></span>, <span class="number"><span class="error" title="CS1061">2</span></span>, <span class="number"><span class="error" title="CS1061">3</span></span> }</span>; <span class="comment">// () と [] が違うのでコード共通化が難しい。</span>
</pre>
<h4>stackalloc</h4>
<p>パフォーマンス的に配列を使いたくない場面があり、
そういう場合 <a href="https://ufcpp.net/study/csharp/sp_unsafe.html#safe-stackalloc">stackalloc</a>というものが使えることがあります。</p>
<p>元々は unsafe な機能でめったに使うものではなかったんですが、
C# 7.2 で、<a href="https://ufcpp.net/study/csharp/resource/span/"><code>Span&lt;T&gt;</code> 構造体</a>の導入とともに safe な構文になりました。</p>
<pre class="source" title="stackalloc">
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <span class="reserved">stackalloc</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
</pre>
<p>これも本来の書き方は <code>stackalloc T[length]</code> で、長さ・型の推論が働くことで <code>stackalloc[] { }</code>という書き方ができています。</p>
<p>ちなみに、<code>stackalloc</code> は参照型を含められないという問題があって、
例えば以下のようなコードはコンパイル エラーになります。</p>
<pre class="source" title="参照型に対する stackalloc はエラーに">
<span class="type struct">Span</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <span class="error" title="CS0208"><span class="reserved">stackalloc</span>[] { <span class="string">&quot;abc&quot;</span> }</span>;
</pre>
<h4><a id="static-data">静的データ最適化</a></h4>
<p><code>ReadOnlySpan&lt;T&gt;</code> 型に対して配列を渡すと、
最適化で配列が消えてくれて、stackalloc を使うよりもパフォーマンスがよくなることがあります。</p>
<pre class="source" title="静的データ最適化">
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">ros</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
</pre>
<p>詳しくはブログ「<a href="https://ufcpp.net/blog/2018/12/staticdatareadonlyspan/">静的なデータの ReadOnlySpan 最適化</a>」に書いたことがあるのでそちらを参照してください。
(C# 12 からは <code>byte</code>, <code>sbyte</code> 以外の型に対してもこの最適化がかかります。)</p>
<p>この最適化は、「条件がそろえば配列が消える」というのが上級者にしかわからないという問題があります。
ぱっと見はパフォーマンスが悪そうに見えますし、
古い C# コンパイラーで同様のコードをコンパイルすると実際パフォーマンスが悪いので、
結構な混乱を招いています。</p>
<h4>ImmutableArray</h4>
<p><a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.immutable.immutablearray-1"><code>ImmutableArray&lt;T&gt;</code></a> という型に対しては初期化子の類が使えません。
以下のように地道に <code>Create</code> メソッドを呼ぶ必要があります。</p>
<pre class="source" title="ImmutableArray.Create">
<span class="type struct">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> <span class="type"><span class="static">ImmutableArray</span></span><span class="operator">.</span><span class="method"><span class="static">Create</span></span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);
</pre>
<p>ところが質が悪いことに、<code>ImmutableArray&lt;T&gt;</code> 型はコレクション初期化子を使える要件を満たしてしまっています。
以下のようなコードは「コンパイルはできてしまうけど、実行すると必ず例外が起こる」という、かなりつらい状態になります。</p>
<pre class="source" title="ImmutableArray に対してコレクション初期化子">
<span class="reserved">using</span> System<span class="operator">.</span>Collections<span class="operator">.</span>Immutable;

<span class="comment">// コンパイルはできてしまう。</span>
<span class="comment">// ところが実行すると必ず例外。</span>
<span class="type struct">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> <span class="reserved">new</span>() { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };
</pre>
<h2><a id="collection-expr">コレクション式</a></h2>
<p>前節で説明したような「型によって初期化の方法が違う」という問題と、補足で書いた諸問題に対処するため、
C# 12 で<strong id="key-collection-expr" class="keyword">コレクション式</strong>(collection expression)というものを導入することになりました。</p>
<p>概要でも書いたように、<code>[]</code> 記号を使って配列などを初期化します。</p>
<pre class="source" title="コレクション式">
<span class="reserved">using</span> System<span class="operator">.</span>Collections<span class="operator">.</span>Immutable;

<span class="reserved">int</span>[] <span class="variable">array</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">list</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">span</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">ros</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="type struct">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
</pre>
<p>コレクション式は以下のような型に対して使えます。</p>
<ul>
<li>配列</li>
<li><code>Span&lt;T&gt;</code>, <code>ReadOnlySpan&lt;T&gt;</code></li>
<li>配列が実装している <code>IEnumerable&lt;T&gt;</code>, <code>IReadOnlyList&lt;T&gt;</code>, <code>IList&lt;T&gt;</code> などのインターフェイス</li>
<li><a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.runtime.compilerservices.collectionbuilderattribute"><code>CollectionBuilder</code> 属性</a>が付いている型</li>
<li><a href="https://ufcpp.net/study/csharp/sp3_lambda.html?key=collectioninit#collectioninit">コレクション初期化子</a>の条件を満たす型</li>
</ul>
<p>配列初期化子と違って、<code>[]</code> はどこにでも書けます。</p>
<pre class="source" title="宣言以外でも書ける">
<span class="reserved">int</span>[] <span class="variable">array</span>;

<span class="comment">// OK</span>
<span class="variable">array</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
</pre>
<p>stackalloc と違って、参照型の <code>Span&lt;T&gt;</code> に対しても使えます。
ちゃんと、(配列を作るよりも)パフォーマンスのいいコードになります。
(内部的には<a href="https://ufcpp.net/study/csharp/datatype/inline-array/">InlineArray</a>を使っています。)</p>
<pre class="source" title="参照型の Span">
<span class="comment">// OK</span>
<span class="type struct">Span</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">span</span> <span class="operator">=</span> [<span class="string">&quot;abc&quot;</span>];
</pre>
<p><code>ReadOnlySpan&lt;T&gt;</code> に対しては前述の<a href="#static-data">静的データ最適化</a>がかかるわけですが、
「配列を new してそうに見えるコード」がないだけ混乱が少ないです。</p>
<pre class="source" title="ReadOnlySpan の静的データ最適化">
<span class="comment">// 以下のコードはちゃんと静的データ最適化がかかる。</span>
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">span</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
</pre>
<p>コレクション初期化子の条件よりも、<code>CollectionBuilder</code> 属性の方が優先されます。
<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.immutable.immutablearray-1"><code>ImmutableArray&lt;T&gt;</code></a> には <code>CollectionBuilder</code> 属性が付いていることによってコレクション式を使えます。</p>
<pre class="source" title="ImmutableArray に対するコレクション式">
<span class="reserved">using</span> System<span class="operator">.</span>Collections<span class="operator">.</span>Immutable;

<span class="type struct">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="comment">// CollectionBuilder 属性の情報をもとに、C# コンパイラーが以下のようなコードに展開する。</span>
<span class="comment">//</span>
<span class="comment">//ReadOnlySpan&lt;int&gt; temp = [1, 2, 3];</span>
<span class="comment">//ImmutableArray&lt;int&gt; immutable = ImmutableArray.Create(temp);</span>
</pre>
<p>ちなみに、<code>CollectionBuilder</code> 属性はインターフェイスにも付けることができます。
<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.immutable.iimmutablelist-1"><code>IImmutableList&lt;T&gt;</code></a>が一例で、以下のようなコードを書けます。</p>
<pre class="source" title="CollectionBuilder 属性はインターフェイス可">
<span class="reserved">using</span> System<span class="operator">.</span>Collections<span class="operator">.</span>Immutable;

<span class="type">IImmutableList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="comment">// IImmutableList インターフェイスについている CollectionBuidler 属性では、</span>
<span class="comment">// ImmutableList.Create メソッドを使うよう指定されているので、</span>
<span class="comment">// おおむね以下のようなコードと同じ意味。</span>
<span class="comment">//</span>
<span class="comment">//ReadOnlySpan&lt;int&gt; span = [1, 2, 3];</span>
<span class="comment">//IImmutableList&lt;int&gt; immutable = ImmutableList.Create(span);</span>
</pre>
<p><code>List&lt;T&gt;</code> は「コレクション初期化子の条件」に該当していて、コレクション初期化子の時と同じコードに展開されます。</p>
<pre class="source" title="">
<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">list</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="comment">// コレクション初期化子 new() { 1, 2, 3 } と同じ結果。</span>
<span class="comment">//</span>
<span class="comment">//List&lt;int&gt; list = new();</span>
<span class="comment">//list.Add(1);</span>
<span class="comment">//list.Add(2);</span>
<span class="comment">//list.Add(3);</span>
</pre>
<p><code>IEnumerable&lt;T&gt;</code> などのインターフェイスに対しては、
将来の最適化の余地を残すため、実際に何の型が使われるかは仕様化されていません。
参考までに、「C# 12 リリース時点」では以下のような実装になっています。</p>
<pre class="source" title="">
<span class="comment">//※ C# 12 時点の実装。将来、最適化で変更する余地あり。</span>

<span class="comment">// 長さが既知で読み取り専用 → ReadOnlyArray みたいな型をコンパイラーが生成して使う。</span>
<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">x1</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="type">IReadOnlyList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">x2</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="type">IReadOnlyCollection</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">x3</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="comment">// 書き換え・追加・削除可能なもの → new List&lt;T&gt; を使用。</span>
<span class="type">ICollection</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">x4</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">x5</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="method"><span class="static">Twice</span></span>(<span class="variable">x1</span>);

<span class="comment">// 長さが未知の場合も new List&lt;T&gt; を使用。</span>
<span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="method"><span class="static">Twice</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">e</span>) <span class="operator">=&gt;</span> [.. <span class="variable local">e</span>, .. <span class="variable local">e</span>];

<span class="comment">// 空っぽの時は Array.Empty&lt;T&gt;() を使用。</span>
<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">empty</span> <span class="operator">=</span> [];
</pre>
<p>いずれにせよ、ターゲットとする型から最適なものを選んで展開されると思ってください。
コレクション式は「書きやすい」だけではなく、「<em>一番パフォーマンスがいい</em>」を目標としています。</p>
<p>(おおむね目標は達成しているので、以前の書き方を積極的に選ぶ理由はありません。
配列やコレクションの初期化は、C# 12 以降を使えるのであればすべて <code>[]</code> を使っていいと思います。)</p>
<h3><a id="square-bracket">余談: [] 括弧</a></h3>
<p>C# ではこれまで、
配列の <code>new[] { }</code> にしろ、コレクション初期化子の <code>new() { }</code> にしろ、
コレクション系の構文には <code>{}</code> を使うものが多かったわけですが、
C# 12 のコレクション式は <code>[]</code> になりました。</p>
<p>その理由として、<code>{}</code> は用途が多すぎてこれ以上新しい構文を兼ねることが難しかったというのがあります。</p>
<pre class="source" title="">
<span class="comment">// 普通に単独で書ける。</span>
<span class="comment">// これは「空のブロック」。</span>
<span class="comment">// 要は、if とかの後ろにある { } と同じものを単独で書いてる。</span>
{ }

<span class="comment">// ラムダ式の後ろとか、</span>
<span class="reserved">var</span> <span class="variable">action</span> <span class="operator">=</span> () <span class="operator">=&gt;</span> { };

<span class="comment">// メソッドの後ろとかにも普通にブロックを書く。</span>
<span class="reserved">void</span> <span class="method">localFunc</span>() { }

<span class="comment">// 初期化子に限っても、</span>
<span class="comment">// コレクション初期化子(Add メソッド呼び出しになる)と、</span>
<span class="reserved">var</span> <span class="variable">list</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">List</span>&lt;<span class="reserved">int</span>&gt; { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };

<span class="comment">// オブジェクト初期化子(プロパティの初期化になる)があるし、</span>
<span class="reserved">var</span> <span class="variable">obj</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">EnumerationOptions</span> { <span class="property">BufferSize</span> <span class="operator">=</span> <span class="number">1024</span> };

<span class="comment">// 匿名クラスとかにも使う。</span>
<span class="reserved">var</span> <span class="variable">anonymous</span> <span class="operator">=</span> <span class="reserved">new</span> { <span class="property">X</span> <span class="operator">=</span> <span class="number">1</span>, <span class="property">Y</span> <span class="operator">=</span> <span class="number">2</span> };

<span class="comment">// 将来候補として、「ブロック式」を導入したいという話もある。</span>
<span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> { <span class="reserved">var</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">123</span>; <span class="variable">i</span> <span class="operator">*</span> <span class="variable">i</span> };
</pre>
<p>特に、オブジェクト初期化子とコレクション初期化子が同じ記号を使っていて、混在不可なので以下のようなことが起こります。</p>
<pre class="source" title="2つの {} 初期化子">
<span class="comment">// オブジェクト初期化子(プロパティの値指定)とコレクション初期化子(Add)の混在不可。</span>
<span class="reserved">var</span> <span class="variable">list1</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">List</span>&lt;<span class="reserved">int</span>&gt; { <span class="property">Capacity</span> <span class="operator">=</span> <span class="number">1014</span>, <span class="error" title="CS0747"><span class="number">1</span></span>, <span class="number"><span class="error" title="CS0747">2</span></span>, <span class="number"><span class="error" title="CS0747">3</span></span> };

<span class="comment">// ちなみに、[0] = 1 みたいな書き方はオブジェクト初期化子の範疇。</span>
<span class="reserved">var</span> <span class="variable">list2</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">List</span>&lt;<span class="reserved">int</span>&gt;
{
    <span class="property">Capacity</span> <span class="operator">=</span> <span class="number">1014</span>,
    [<span class="number">0</span>] <span class="operator">=</span> <span class="number">1</span>, <span class="comment">// 実行時例外にはなるけど、コンパイルは通っちゃう。</span>
};

<span class="comment">// なので「混在不可」のせいで以下のコードもエラー。</span>
<span class="reserved">var</span> <span class="variable">dictionary</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">Dictionary</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;
{
    <span class="error" title="CS0747">{ <span class="number">1</span>, <span class="number">2</span> }</span>,
    [<span class="number">0</span>] <span class="operator">=</span> <span class="number">1</span>,
};
</pre>
<p>この問題は C# 11 で<a href="https://ufcpp.net/study/csharp/datatype/patterns/?p=2#list">リスト パターン</a>を導入する際にも問題になりました。
C# 8 の頃からある<a href="https://ufcpp.net/study/csharp/datatype/patterns/?p=2#property">プロパティ パターン</a>との区別のためには <code>{}</code> を使えませんでした。
例えば以下のようなコードで、「空っぽのリスト」の意味で <code>list is {}</code> とは書けないという問題があったりします。</p>
<pre class="source" title="{} の「兼用」は難しい">
<span class="reserved">var</span> <span class="variable">obj</span> <span class="operator">=</span> <span class="reserved">new</span> { <span class="property">X</span> <span class="operator">=</span> <span class="number">1</span>, <span class="property">Y</span> <span class="operator">=</span> <span class="number">2</span> };
<span class="reserved">var</span> <span class="variable">list</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> };

<span class="comment">// プロパティ パターン。</span>
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">obj</span> <span class="reserved">is</span> { <span class="property">X</span>: <span class="number">1</span> };

<span class="comment">// (当初検討にあった)リスト パターンの候補としての {}。</span>
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">list</span> <span class="reserved">is</span> { <span class="number">1</span>, .. } ;

<span class="comment">// プロパティ パターンで {} は「単に null チェック」になる。</span>
<span class="reserved">var</span> <span class="variable">isNotNull</span> <span class="operator">=</span> <span class="variable">obj</span> <span class="reserved">is</span> { };

<span class="comment">// これは C# 11 以前から有効な文法(「null じゃない」の意味)なので、</span>
<span class="comment">// リスト パターンとして {} を使おうとすると「空リストとマッチ」にはできなくなる。</span>
<span class="reserved">var</span> <span class="variable">isEmpty</span> <span class="operator">=</span> <span class="variable">list</span> <span class="reserved">is</span> { };
</pre>
<p>そこで C# 11 では最終的にリスト パターンに <code>[]</code> を採用したわけですが、
だったら「リスト構築の方でも <code>[]</code> を使った方がきれい」という話になりました。</p>
<pre class="source" title="コレクション式とリスト パターンが対">
<span class="comment">// () コンストラクター/タプル構築と位置パターンが対。</span>
<span class="reserved">var</span> <span class="variable">obj</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">DateOnly</span>(<span class="number">2021</span>, <span class="number">1</span>, <span class="number">1</span>);
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">obj</span> <span class="reserved">is</span> (<span class="number">2021</span>, <span class="reserved">_</span>, <span class="reserved">_</span>);

<span class="reserved">var</span> <span class="variable">tuple</span> <span class="operator">=</span> (<span class="number">1</span>, <span class="number">2</span>);
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">tuple</span> <span class="reserved">is</span> (<span class="number">1</span>, <span class="reserved">_</span>);

<span class="comment">// {} オブジェクト初期化子/匿名クラスとプロパティ パターンが対。</span>
<span class="reserved">var</span> <span class="variable">prop</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">EnumerationOptions</span> { <span class="property">BufferSize</span> <span class="operator">=</span> <span class="number">1024</span> };
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">prop</span> <span class="reserved">is</span> { <span class="property">BufferSize</span>: <span class="number">1024</span> };

<span class="reserved">var</span> <span class="variable">anon</span> <span class="operator">=</span> <span class="reserved">new</span> { <span class="property">X</span> <span class="operator">=</span> <span class="number">1</span>, <span class="property">Y</span> <span class="operator">=</span> <span class="number">2</span> };
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">anon</span> <span class="reserved">is</span> { <span class="property">X</span>: <span class="number">1</span> };

<span class="comment">// [] コレクション式とリスト パターンが対。</span>
<span class="reserved">int</span>[] <span class="variable">list</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">list</span> <span class="reserved">is</span> [<span class="number">1</span>, ..];
</pre>
<h3><a id="null-conditional-foreach">余談: null 条件 foreach</a></h3>
<p>「C# に追加して欲しい機能」としてそこそこ高頻度で挙がるものの1つに、
「null 条件 foreach」があったりします。
これは要するに、以下のようなコードを、</p>
<pre class="source" title="null があり得る foreach">
<span class="method"><span class="static">Print</span></span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]);
<span class="method"><span class="static">Print</span></span>(<span class="reserved">null</span>);

<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Print</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">list</span>)
{
    <span class="comment">// null が来た時に普通にぬるぽ。</span>
    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable local"><span class="warning" title="CS8602">list</span></span>)
        <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">Write</span></span>(<span class="string">$&quot;</span>{<span class="variable">item</span>}<span class="string"> </span><span class="string">&quot;</span>);
}
</pre>
<p>以下のように直すのが嫌で、</p>
<pre class="source" title="null チェックで1段インデントが下がる">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Print</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">list</span>)
{
    <span class="comment">// null チェックを1行足せばいいだけの話なものの、1段インデントが下がるのが嫌。</span>
    <span class="control">if</span> (<span class="variable local">list</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span>)
        <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable local">list</span>)
            <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">Write</span></span>(<span class="string">$&quot;</span>{<span class="variable">item</span>}<span class="string"> </span><span class="string">&quot;</span>);
}
</pre>
<p>以下のように <code>foreach?</code> という構文を追加してもらえないかという提案です。</p>
<pre class="source" title="foreach?">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Print</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">list</span>)
{
    <span class="comment">// foreach? 構文を足すのはどうだろう？</span>
    <span class="control">foreach</span>? (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable local">list</span>)
        <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">Write</span></span>(<span class="string">$&quot;</span>{<span class="variable">item</span>}<span class="string"> </span><span class="string">&quot;</span>);
}
</pre>
<p>確かに時々そういう機能が欲しくなるものの、
新文法を導入するほどのものかと言われると悩ましく、
長らく塩漬けになっている提案です。</p>
<p>そしてこの度コレクション式が入ったことで、
これと同等のことが以下のコードで実現できるようになりました。</p>
<pre class="source" title="??[]">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">Print</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">list</span>)
{
    <span class="comment">// ?? [] の4文字を追加すれば null チェック代わりになる。</span>
    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable local">list</span> <span class="operator">??</span> [])
        <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">Write</span></span>(<span class="string">$&quot;</span>{<span class="variable">item</span>}<span class="string"> </span><span class="string">&quot;</span>);
}
</pre>
<p>これはまあ、以下のようなコードとほぼ同等です。</p>
<pre class="source" title="??[] と同等のコード">
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Print</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">list</span>)
{
    <span class="control">if</span> (<span class="variable local">list</span> <span class="reserved">is</span> <span class="reserved">null</span>) <span class="variable local">list</span> <span class="operator">=</span> <span class="type">Array</span><span class="operator">.</span><span class="static"><span class="method">Empty</span></span>&lt;<span class="reserved">int</span>&gt;();

    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable local">list</span>)
        <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">Write</span></span>(<span class="string">$&quot;</span>{<span class="variable">item</span>}<span class="string"> </span><span class="string">&quot;</span>);
}
</pre>
<p><code>Array.Empty&lt;int&gt;()</code> を挟んでいるので無駄そうに見えるわけですが、
.NET 8 では<a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#collections">かなり強力な最適化がかかるようになっていて</a>、
<code>Array.Empty&lt;int&gt;()</code> に対する foreach のコストはかなり低く抑えられます。</p>
<p>(これが十分に便利なので、<code>foreach?</code> 提案が通る可能性はかなり低くなりました。)</p>
<h2><a id="spread">スプレッド</a></h2>
<p>コレクション式の中では、<code>..</code> を使って「他のコレクションの中身を展開」みたいなことができます。
これを<strong id="key-spread" class="keyword">スプレッド</strong>(spread: 広げる、伸ばす、まき散らす)演算子と言います。</p>
<pre class="source" title="..">
<span class="reserved">int</span>[] <span class="variable">a</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>];
<span class="reserved">int</span>[] <span class="variable">b</span> <span class="operator">=</span> [<span class="number">3</span>, <span class="number">4</span>];

<span class="comment">// これで 0, 1, 2, 3, 4, 5 になる。</span>
<span class="reserved">int</span>[] <span class="variable">c</span> <span class="operator">=</span> [<span class="number">0</span>, ..<span class="variable">a</span>, ..<span class="variable">b</span>, <span class="number">5</span>];
</pre>
<p>これは、<code>List&lt;T&gt;</code> でいう <a href="https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.addrange"><code>AddRange</code> メソッド</a>であったり、
<a href="https://ufcpp.net/study/csharp/sp3_stdqueryo.html#concat">LINQ でいう <code>Concat</code> メソッド</a>みたいな物です。</p>
<pre class="source" title="AddRange と Concat">
<span class="reserved">int</span>[] <span class="variable">a</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>];
<span class="reserved">int</span>[] <span class="variable">b</span> <span class="operator">=</span> [<span class="number">3</span>, <span class="number">4</span>];

<span class="comment">// コレクション式では ..</span>
<span class="reserved">int</span>[] <span class="variable">expression</span> <span class="operator">=</span> [<span class="number">0</span>, ..<span class="variable">a</span>, ..<span class="variable">b</span>, <span class="number">5</span>];

<span class="comment">// List&lt;T&gt; でいう AddRange</span>
<span class="reserved">var</span> <span class="variable">list</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">List</span>&lt;<span class="reserved">int</span>&gt;();
<span class="variable">list</span><span class="operator">.</span><span class="method">Add</span>(<span class="number">0</span>);
<span class="variable">list</span><span class="operator">.</span><span class="method">AddRange</span>(<span class="variable">a</span>);
<span class="variable">list</span><span class="operator">.</span><span class="method">AddRange</span>(<span class="variable">b</span>);
<span class="variable">list</span><span class="operator">.</span><span class="method">Add</span>(<span class="number">5</span>);

<span class="comment">// LINQ でいう Concat</span>
<span class="reserved">var</span> <span class="variable">linq</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">0</span> }
    <span class="operator">.</span><span class="method">Concat</span>(<span class="variable">a</span>)
    <span class="operator">.</span><span class="method">Concat</span>(<span class="variable">b</span>)
    <span class="operator">.</span><span class="method">Append</span>(<span class="number">5</span>);
</pre>
<p>ちなみに<a href="#square-bracket">先ほど</a>、コレクション式とリスト パターンが対という話をしましたが、</p>
<pre class="source" title="コレクション式とリスト パターンが対">
<span class="comment">// [] コレクション式とリスト パターンが対。</span>
<span class="reserved">int</span>[] <span class="variable">list</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="reserved">_</span> <span class="operator">=</span> <span class="variable">list</span> <span class="reserved">is</span> [<span class="number">1</span>, ..];
</pre>
<p>スプレッドも<a href="https://ufcpp.net/study/csharp/datatype/patterns/?p=2#slice-pattern">スライス パターン</a>と対になっています。</p>
<pre class="source" title="スプレッドとスライス パターンが対">
<span class="reserved">int</span>[] <span class="variable">list</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];

<span class="comment">// スライス: コレクションの一部分を切り出して新しい変数に代入。</span>
<span class="control">if</span> (<span class="variable">list</span> <span class="reserved">is</span> [<span class="reserved">var</span> <span class="variable">first</span>, ..<span class="reserved">var</span> <span class="variable">middle</span>, <span class="reserved">var</span> <span class="variable">last</span>])
{
    <span class="comment">// スプレッド: コレクションの中身を展開して、1つのコレクションに結合。</span>
    <span class="reserved">int</span>[] <span class="variable">list2</span> <span class="operator">=</span> [<span class="variable">first</span>, ..<span class="variable">middle</span>, <span class="variable">last</span>];
}
</pre>
<h2><a id="type-inference">型推論・オーバーロード解決</a></h2>
<p>元々あった配列やコレクション初期化子の構文では、<code>new T[]</code> や <code>new List&lt;T&gt;()</code> などというように、型名を明示できます。
それに対して、コレクション式は <code>[]</code> しか書かないので何の型になるかは完全に推論だよりになります。</p>
<p>ちなみに、<a href="#after12">後述</a>しますが、C# 12 時点では以下のような「<code>var</code> との組み合わせ」はできません。
C# 13 以降で検討中です。</p>
<pre class="source" title="C# 12 時点では型決定できない var">
<span class="reserved">var</span> <span class="variable">list</span> <span class="operator">=</span> <span class="error" title="CS9176">[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span>;</pre>
<h3><a id="target-typed">ターゲットの型から</a></h3>
<p>基本的にコレクション式の型はターゲット(代入先の変数・引数の型)から決定します。</p>
<p>この点は <code>new[] {}</code> の場合と異なります。
<code>new[] {}</code> は「中身の型からの推論優先」で、コレクション式 <code>[]</code> は「ターゲットからの推論優先」です。
例えば、以下のようなコードでは、<code>x</code> と <code>y</code> に代入されるインスタンスの型が異なります。</p>
<pre class="source" title="new[]{} は要素からの推論なので時々困る">
<span class="comment">// new[]{} は要素からの型推論。</span>
<span class="comment">// x には string[] が入る。</span>
<span class="reserved">object</span>[] <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="string">&quot;a&quot;</span> };

<span class="comment">// [] はターゲットからの型推論。</span>
<span class="comment">// y には object[] が入る。</span>
<span class="reserved">object</span>[] <span class="variable">y</span> <span class="operator">=</span> [<span class="string">&quot;a&quot;</span>];

<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">x</span><span class="operator">.</span><span class="method">GetType</span>()<span class="operator">.</span><span class="property">Name</span>); <span class="comment">// String[]</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">y</span><span class="operator">.</span><span class="method">GetType</span>()<span class="operator">.</span><span class="property">Name</span>); <span class="comment">// Object[]</span>

<span class="variable">y</span>[<span class="number">0</span>] <span class="operator">=</span> <span class="number">1</span>; <span class="comment">// OK。</span>
<span class="variable">x</span>[<span class="number">0</span>] <span class="operator">=</span> <span class="number">1</span>; <span class="comment">// 例外が出る(C# 1.0 からある嫌な仕様)。</span>
</pre>
<p>(この例の最後の行はかなり<a href="https://ufcpp.net/blog/2022/11/covariantarrayincident/">奇妙で安全性に欠ける仕様ですが、大昔の名残りで今更変更できない</a>そうです。)</p>
<p>コレクション式の「ターゲットからの型推論」は、型や式が入れ子になっていてもちゃんと働きます。
以下のように、<a href="https://ufcpp.net/study/csharp/datatype/tuples/">タプル</a>中にコレクションがあって、条件演算子や <a href="https://ufcpp.net/study/csharp/datatype/typeswitch/?p=5#switch-expression">switch 式</a>を経由していても正しく型推論されます。</p>
<pre class="source" title="入れ子でもちゃんと型推論される例">
<span class="reserved">bool</span> <span class="variable">b</span> <span class="operator">=</span> <span class="reserved">true</span>;
<span class="reserved">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>;

<span class="comment">// 条件演算子 x ? y : z とか、</span>
<span class="comment">// switch 式 x switch { ... } とか、</span>
<span class="comment">// タプルを使った入れ子とかあっても、ちゃんと型推論される。</span>
(<span class="reserved">byte</span>, (<span class="reserved">byte</span>, <span class="reserved">byte</span>[] z)[])[] <span class="variable">x</span> <span class="operator">=</span> <span class="variable">b</span> <span class="operator">?</span> [] <span class="operator">:</span> <span class="variable">i</span> <span class="control">switch</span>
{
    <span class="reserved">_</span> <span class="operator">=&gt;</span> [
        (<span class="number">1</span>, [(<span class="number">2</span>, [<span class="number">3</span>, <span class="number">4</span>])]) <span class="comment">// [3, 4] の部分、ちゃんと byte[] になる。</span>
    ]
};
</pre>
<h3><a id="from-element">要素の型から</a></h3>
<p>一方で、メソッドのオーバーロード解決などが絡む場合、
コレクション式の中身からの型解決も働きます。</p>
<pre class="source" title="要素の型からオーバーロード解決">
<span class="static"><span class="method">Print</span></span>([<span class="number">1</span>, <span class="number">2</span>]);     <span class="comment">// Print&lt;int&gt;</span>
<span class="method"><span class="static">Print</span></span>([<span class="number">1.1</span>, <span class="number">2.2</span>]); <span class="comment">// Print&lt;double&gt;</span>
<span class="method"><span class="static">Print</span></span>([<span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>]); <span class="comment">// Print&lt;string&gt;</span>

<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Print</span></span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span>[] <span class="variable local">args</span>) { <span class="comment">/* 省略 */</span> }
</pre>
<p>ただ、スプレッドが絡むとき、スプレッドの中身の優先度は低いそうです。
(実装が大変なわりに需要が少ないという判断。)</p>
<pre class="source" title="スプレッドが絡むとき">
<span class="reserved">byte</span>[] <span class="variable">x</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>];

<span class="comment">// ..x しかない場合には x の型から byte[] に決定。</span>
<span class="method"><span class="static">Print</span></span>([.. <span class="variable">x</span>]);     <span class="comment">// Print&lt;byte&gt;</span>

<span class="comment">// ただ、その横に整数リテラルが1個でも並ぶと…</span>
<span class="comment">// 3 (int) につられて int[] に決定。</span>
<span class="static"><span class="method">Print</span></span>([.. <span class="variable">x</span>, <span class="number">3</span>]);  <span class="comment">// Print&lt;int&gt;</span>

<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Print</span></span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span>[] <span class="variable local">args</span>) { }
</pre>
<h3><a id="priority">オーバーロード解決の優先度</a></h3>
<p><code>[]</code> は配列や <code>List&lt;T&gt;</code>, <code>Span&lt;T&gt;</code> など、いろいろな型になるわけですが、
では、そのいずれも候補になるオーバーロードの場合はどれが優先されるでしょうか。</p>
<p>これまでの C# では、「元の型に近いほど優先度が高い」というのがオーバーロード解決の基本ルールで、
具体的には以下のような順(上ほど優先)になっています。</p>
<ol>
<li>ぴったり一致する型</li>
<li>基底クラス(階層が近いほど優先)</li>
<li>実装しているインターフェイス(階層が近いほど優先)</li>
<li>暗黙の型変換できる型</li>
</ol>
<p>このルールに沿うなら、配列(<code>[]</code> で作るのではなく <code>new T[]</code> で作る)の場合、
一例をあげると以下のような優先度になります。</p>
<ol>
<li><code>T[]</code></li>
<li><code>IList&lt;T&gt;</code></li>
<li><code>IEnumerable&lt;T&gt;</code></li>
<li><code>Span&lt;T&gt;</code> もしくは <code>ReadOnlySpan&lt;T&gt;</code> (両方あるとエラー)</li>
</ol>
<p>一方で、コレクション式 <code>[]</code> の場合、「パフォーマンスがいいものを優先する」という目標のため、
<code>Span&lt;T&gt;</code> と <code>ReadOnlySpan&lt;T&gt;</code> を特別扱いして優先度を上げています(ぴったり一致する型よりも優先度が上)。
そのため、以下のような優先度になっています。</p>
<p>(※ .NET 8 RC 2 時点では <code>ReadOnlySpan&lt;T&gt;</code> の優先度がちょっと低いですが、正式リリースまでに変更される予定です。)</p>
<ol>
<li><code>ReadOnlySpan&lt;T&gt;</code></li>
<li><code>Span&lt;T&gt;</code></li>
<li><code>T[]</code></li>
<li><code>IList&lt;T&gt;</code></li>
<li><code>IEnumerable&lt;T&gt;</code></li>
</ol>
<p>以下に例を挙げます。</p>
<pre class="source" title="具象型優先">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([]); <span class="comment">// int[]</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 具象型優先。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">int</span>[] <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<pre class="source" title="具象型優先">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([]); <span class="comment">// List&lt;int&gt;</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 具象型優先。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<pre class="source" title="具象型に近い方優先 (派生側優先)">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([]); <span class="comment">// IList&lt;int&gt;</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 具象型に近い方優先 (派生側優先)。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">IList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<pre class="source" title="Span 優先">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([]); <span class="comment">// Span&lt;int&gt;</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// Span 優先(コレクション式のみの特殊動作)。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">int</span>[] <span class="variable local">_</span>) { } <span class="comment">// 普通は具象型優先。</span>
}
</pre>
<pre class="source" title="Span 優先">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([]); <span class="comment">// Span&lt;int&gt;</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// Span 優先(コレクション式のみの特殊動作)。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { } <span class="comment">// 普通は 派生 &gt; 型変換</span>
}
</pre>
<pre class="source" title="ReadOnlySpan 優先">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([]); <span class="comment">// ReadOnlySpan&lt;int&gt;</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// ReadOnlySpan 優先(コレクション式のみの特殊動作)。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IReadOnlyList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { } <span class="comment">// 普通は 派生 &gt; 型変換</span>
}
</pre>
<pre class="source" title="ReadOnlySpan 優先">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([]); <span class="comment">// ReadOnlySpan&lt;int&gt;</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// ReadOnlySpan 優先(コレクション式のみの特殊動作)。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { } <span class="comment">// (.NET 8 RC 2 時点ではまだこっちが優先されてる。変更予定)</span>
}
</pre>
<p>ちなみに、以下のような場合には(普通のオーバーロード解決でも、コレクション式でも)不明瞭(オーバーロード解決不能)でコンパイル エラーになります。</p>
<pre class="source" title="具象型同士は同列">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="error" title="CS0121"><span class="static">M</span></span></span>([]); <span class="comment">// コンパイル エラー</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 具象型同士は同列。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">int</span>[] <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<pre class="source" title="派生関係のないインターフェイスは同列">
<span class="type">A</span><span class="operator">.</span><span class="method"><span class="error" title="CS0121"><span class="static">M</span></span></span>([]); <span class="comment">// コンパイル エラー</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 派生関係のないインターフェイスは同列。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IReadOnlyList</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">_</span>) { }
}
</pre>
<h2><a id="after12">将来計画(C# 13 以降)</a></h2>
<p>スケジュールの関係で C# 12 からは外れて、
C# 13 以降で実装される予定になっている機能がいくつかあります。
詳細は実装されてから追記しますが、
簡単に紹介だけしておきます。</p>
<h4>自然な型</h4>
<p><code>var x = [1, 2];</code> みたいに、<code>var</code> と組み合わせでは「ターゲットからの型推論」ができないわけですが、
この時にデフォルトで何の型になるかは C# 12 時点では決めかねました。</p>
<p>使い勝手を考えると(機能が多い) <code>List&lt;T&gt;</code> がいいですし、
一方で、パフォーマンスを考えると <code>Span&lt;T&gt;</code> がいいです(検討中)。</p>
<h4>拡張メソッドからの型推論</h4>
<p>単純に <code>var x = [1, 2];</code> とは書けない一方で、
C# 12 時点でも、<code>var x = (int[])[1, 2];</code> みたいにキャストを挟めば型を決定できます。</p>
<p>ただ、キャストは「なんか書きにくい」
(キャストは型推論が効かないとか、<code>()</code> がタイピングしにくいとか、コード補完の都合で後置きの方が書き心地がいいとか)
という問題があって、
以下のように、拡張メソッドからの型推論が効くようにしてほしいという話があります。</p>
<pre class="source" title="拡張メソッドからの型推論">
<span class="comment">// (List&lt;int&gt;)[1, 2] よりも、拡張メソッド形式の方が書き心地がいい。</span>
<span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="error" title="CS9176">[<span class="number">1</span>, <span class="number">2</span>]</span><span class="operator">.</span>AsList();

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">Extensions</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">List</span>&lt;<span class="type param">T</span>&gt; <span class="method"><span class="static">AsList</span></span>&lt;<span class="type param">T</span>&gt;(<span class="reserved">this</span> <span class="type">List</span>&lt;<span class="type param">T</span>&gt; <span class="variable local">list</span>) <span class="operator">=&gt;</span> <span class="variable local">list</span>;
}
</pre>
<p>この話はコレクション式に限らず、
<a href="https://ufcpp.net/study/csharp/sp_delegate.html#natural-type">デリゲート</a>や<a href="https://ufcpp.net/study/csharp/start/improvedinterpolatedstring/">文字列補間</a>でもそうなんですが、
C# 13 以降で取り組むそうです。</p>
<h4>Dictionary 式</h4>
<p><code>Dictionary&lt;TKey, TValue&gt;</code> などのキーを持つタイプのコレクションに対して、
以下のような構文で初期化できるようにしたいという案があって、これも C# 13 で検討中です。</p>
<pre class="source" title="">
<span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="reserved">int</span>&gt; <span class="variable">map</span> <span class="operator">=</span>
[
    <span class="string">&quot;one&quot;</span>:</span> <span class="number">1</span>,</span>
    <span class="string">&quot;two&quot;</span>: <span class="number">2</span>,
];
</pre>
<h4>非ジェネリック コレクション</h4>
<p>C# 12 では以下のようなコードに対応しなかったんですが、これも C# 13 で検討中です。</p>
<pre class="source" title="非ジェネリック コレクション">
<span class="reserved">using</span> System<span class="operator">.</span>Collections;

<span class="type">ICollection</span> <span class="variable">c</span> <span class="operator">=</span> <span class="error" title="CS9174">[<span class="string">&quot;a&quot;</span>, <span class="number">2</span>, <span class="reserved">null</span>]</span>;
</pre> ]]></description>
				<pubDate>Tue, 24 Oct 2023 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] InlineArray</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/inline-array/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<h5 class="version version12">Ver. 12</h5>
<p>.NET 8 で、
<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.runtime.compilerservices.inlinearrayattribute"><code>InlineArray</code> 属性</a> (<code>System.Runtime.CompilerServices</code> 名前空間) というものが入りました。</p>
<p>基本的には .NET ランタイム側の機能ですが、
いくつか、C# 側にもこの <code>InlineArray</code> 向けの特殊対応が入っています。</p>
<p>ちなみに、この機能は現状、
<a href="https://github.com/ufcpp/UfcppSample/issues/447">コレクション式</a>の内部実装にこそ使っていますが、
本稿で書いているようなコードを直接書く必要はほぼありません。
(実質、本稿はコレクション式の内部実装(の一部)の説明みたいなものです。)</p>
<h2><a id="inline-array-attribute">InlineArray 属性</a></h2>
<p>.NET 8 から、
以下のように、構造体に属性を付けると構造体のサイズが変わります。</p>
<pre class="source" title="InlineArray 属性">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// この属性を付けると、 .NET ランタイムが特別扱いして、構造体のサイズを拡大する。</span>
<span class="comment">// (コンストラクター引数で Length 指定。)</span>
[<span class="type">InlineArray</span>(<span class="number">3</span>)]
<span class="reserved">struct</span> <span class="type struct">FixedBuffer</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="comment">// フィールドを1個だけ書く。</span>
    <span class="comment">// (2個以上書くとコンパイル エラーになる。)</span>
    <span class="comment">// 構造体のサイズが sizeof(T) × Length になる。</span>
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field">_value</span>;
}
</pre>
<p>inline array という名前通り、「埋め込み配列」として使います。
(長さ N の配列代わりに、長さ N 個分のサイズを持った構造体を作ります。
C# の配列はヒープに割り当てられるのに対して、この inline array であればスタック上に値を持てます。)</p>
<p>要は、以下のような「N 個のフィールドを並べる」みたいな構造体を、ランタイム側で自動的に作ってくれる機能です。</p>
<pre class="source" title="N 個のフィールドを手書きで並べた例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="reserved">struct</span> <span class="type struct">FixedBuffer3</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="comment">// 所望の個数フィールドを書く。</span>
    <span class="comment">// (3要素くらいならいいけども、数十とか数百になるときつい。)</span>
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field">_value0</span>;
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field"><span class="warning" title="CS0169">_value1</span></span>;
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field"><span class="warning" title="CS0169">_value2</span></span>;

    <span class="comment">// 変換とかも自前で書く。</span>
    <span class="reserved">public</span> <span class="type struct">Span</span>&lt;<span class="type param">T</span>&gt; <span class="method">AsSpan</span>() <span class="operator">=&gt;</span> <span class="type"><span class="static">MemoryMarshal</span></span><span class="operator">.</span><span class="static"><span class="method">CreateSpan</span></span>(<span class="reserved">ref</span> <span class="field">_value0</span>, <span class="number">3</span>);

    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="type param">T</span> <span class="reserved">this</span>[<span class="reserved">int</span> <span class="variable local">index</span>] <span class="operator">=&gt;</span> <span class="reserved">ref</span> <span class="method">AsSpan</span>()[<span class="variable local">index</span>];
}
</pre>
<h2><a id="vs-stackalloc">stackalloc との違い</a></h2>
<p>これまでも <a href="https://ufcpp.net/study/csharp/sp_unsafe.html#safe-stackalloc"><code>stackalloc</code></a> という機能を使えば、
一応、スタック上に配列上のデータを置くことはできました。
ただ、<code>stackalloc</code> には結構強い制限があって使いづらいです。</p>
<p>一番きつい制限は、参照型、もしくは、参照を含む型に対して使えないことです
(これを認めようとすると<a href="https://ufcpp.net/study/computer/MemoryManagement.html#garbage-collection">ガベコレ</a>の負担が上がって、パフォーマンス的にかえって不利になるそうです)。
例えば以下のコードでは、<code>string</code> 以下の型に対してコンパイル エラーになります。</p>
<pre class="source" title="参照を含むときには stackalloc は使えない">
<span class="comment">// 構造体に対しては使える。</span>
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">i</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="reserved">int</span>[<span class="number">100</span>];
<span class="type struct">Span</span>&lt;<span class="type struct">DateTimeOffset</span>&gt; <span class="variable">d</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="type struct">DateTimeOffset</span>[<span class="number">100</span>];

<span class="comment">// クラスに対しては使えない。</span>
<span class="comment">// (コンパイル エラーになる。)</span>
<span class="type struct">Span</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">s</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="reserved"><span class="error" title="CS0208">string</span></span>[<span class="number">100</span>];

<span class="comment">// クラスや参照を含む構造体に対しても使えない。</span>
<span class="comment">// (コンパイル エラーになる。)</span>
<span class="type struct">Span</span>&lt;<span class="type struct">ContainsRefType</span>&gt; <span class="variable">r1</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="type struct"><span class="error" title="CS0208">ContainsRefType</span></span>[<span class="number">100</span>];
<span class="type struct">Span</span>&lt;<span class="type struct"><span class="error" title="CS0306">ContainsRefField</span></span>&gt; <span class="variable">r2</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="error" title="CS0208"><span class="type struct">ContainsRefField</span></span>[<span class="number">100</span>];

<span class="reserved">struct</span> <span class="type struct">ContainsRefType</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="warning" title="CS0649"><span class="field">String</span></span>;
}

<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">ContainsRefField</span>
{
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">int</span> <span class="warning" title="CS0649"><span class="field">Ref</span></span>;
}
</pre>
<p>また、<code>stackalloc</code> で確保したスタック領域は、メソッドを抜けるまで解放されません。
このせいで、ループの内側で間違って <code>stackalloc</code> を使ってしまうと簡単にスタック オーバーフロー(要はメモリ不足)を引き起こします
(一般に、スタックはヒープよりもだいぶサイズが小さいです。Windows の場合は 1MB 程度)。
例えば以下のコードを Windows で実行するとスタック オーバーフローします
(1000 とか 200 とか、そこまで大きくない数字ですら簡単にスタック オーバーフローになります)。</p>
<pre class="source" title="">
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; <span class="variable">i</span> <span class="operator">&lt;</span> <span class="number">1000</span>; <span class="variable">i</span><span class="operator">++</span>)
{
    <span class="reserved">_</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="reserved">long</span>[<span class="number">200</span>];
}
</pre>
<h2><a id="special-syntax">C# 側特殊対応</a></h2>
<p>一応、C# 側にもこの InlineArray に対する特殊対応が入っています。
(一応、C# 12 の新機能。)</p>
<p>まず、属性を付けた型に対するチェックが働いています。
すでに前述の例でも書いていますが、
<code>InlineArray</code> 属性を付けた型にフィールドが2つ以上あるとコンパイル エラーになります。</p>
<pre class="source" title="InlineArray 属性を付けた型に対するチェック">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

[<span class="type">InlineArray</span>(<span class="number">3</span>)]
<span class="reserved">struct</span> <span class="type struct">FixedBuffer</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="comment">// フィールドを2個以上書くとコンパイル エラーになるのは一応「C# の新機能」。</span>
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field">_value</span>;
}
</pre>
<p>また、この型を使う側に、以下のような特殊対応が入っています。</p>
<ul>
<li>インデクサーを直接書ける</li>
<li><code>Span&lt;T&gt;</code>/<code>ReadOnlySpan&lt;T&gt;</code> に暗黙的に変換できる</li>
<li><code>foreach</code> で列挙できる</li>
</ul>
<pre class="source" title="InlineArray 型利用側の特殊対応">
<span class="type struct">FixedBuffer</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">buffer</span> <span class="operator">=</span> <span class="reserved">new</span>();

<span class="comment">// InlineArray に対して直接インデクサーを書ける。</span>
<span class="variable">buffer</span>[<span class="number">0</span>] <span class="operator">=</span> <span class="string">&quot;zero&quot;</span>;
<span class="variable">buffer</span>[<span class="number">1</span>] <span class="operator">=</span> <span class="string">&quot;one&quot;</span>;

<span class="comment">// Span/ReadOnlySpan に暗黙的に変換できる。</span>
<span class="type struct">Span</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <span class="variable">buffer</span>;
<span class="variable">span</span>[<span class="number">2</span>] <span class="operator">=</span> <span class="string">&quot;two&quot;</span>;

<span class="comment">// foreach で列挙できる。</span>
<span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">buffer</span>)
{
    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);
}
</pre>
<h2><a id="collection-expressions">コレクション式と InlineArray</a></h2>
<p>前述の通り、
<code>InlineArray</code> 属性には <code>[EditorBrowsable(Never)]</code> が付いていて、
開発者が直接使う想定はあまりありません。</p>
<p>ただ、この機能は C# 12 時点で、コレクション式の最適化のために使われています。
<code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> 型に対してコレクション式を使うと、
<code>InlineArray</code> に展開されます。
例えば以下のようなコードの場合、</p>
<pre class="source" title="Span/ReadOnlySpan に対するコレクション式の例">
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">i</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];

<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">s</span> <span class="operator">=</span> [<span class="string">&quot;a&quot;</span>, <span class="string">&quot;abc&quot;</span>, <span class="string">&quot;&quot;</span>];
</pre>
<p>以下のようなコードとほぼ同じ挙動になります。</p>
<pre class="source" title="上記のコレクション式は InlineArray に展開される">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="reserved">var</span> <span class="variable">i0</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">FixedArray5</span>&lt;<span class="reserved">int</span>&gt;();
<span class="variable">i0</span>[<span class="number">0</span>] <span class="operator">=</span> <span class="number">1</span>;
<span class="variable">i0</span>[<span class="number">1</span>] <span class="operator">=</span> <span class="number">2</span>;
<span class="variable">i0</span>[<span class="number">2</span>] <span class="operator">=</span> <span class="number">3</span>;
<span class="variable">i0</span>[<span class="number">3</span>] <span class="operator">=</span> <span class="number">4</span>;
<span class="variable">i0</span>[<span class="number">4</span>] <span class="operator">=</span> <span class="number">5</span>;
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">i</span> <span class="operator">=</span> <span class="variable">i0</span>;

<span class="reserved">var</span> <span class="variable">s0</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type struct">FixedArray3</span>&lt;<span class="reserved">string</span>&gt;();
<span class="variable">s0</span>[<span class="number">0</span>] <span class="operator">=</span> <span class="string">&quot;a&quot;</span>;
<span class="variable">s0</span>[<span class="number">1</span>] <span class="operator">=</span> <span class="string">&quot;abc&quot;</span>;
<span class="variable">s0</span>[<span class="number">2</span>] <span class="operator">=</span> <span class="string">&quot;&quot;</span>;
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">s</span> <span class="operator">=</span> <span class="variable">s0</span>;

[<span class="type">InlineArray</span>(<span class="number">3</span>)]
<span class="reserved">struct</span> <span class="type struct">FixedArray3</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field">_value</span>;
}

[<span class="type">InlineArray</span>(<span class="number">5</span>)]
<span class="reserved">struct</span> <span class="type struct">FixedArray5</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field">_value</span>;
}
</pre>
<h2><a id="future">将来展望</a></h2>
<p>現状では、先ほどの例でいうと <code>FixedArray3&lt;T&gt;</code> と <code>FixedArray5&lt;T&gt;</code> があるように、
長さごとに別の型を用意せざるを得ない状態です。
「N 個のフィールドを並べる」コードを手書きするよりはマシですが、
まだ一時しのぎ的な実装になっていることは否めません。</p>
<p>根本的に大工事して型システムを改善するなら、
例えば、以下のように「整数型引数」を導入して、これを使って <code>InlineArray</code> を作りたいという話もなくはないです。</p>
<pre class="source" title="「整数型引数」で InlineArray">
<span class="comment">// ※仮定の文法</span>
<span class="reserved">namespace</span> System;

<span class="reserved">public</span> <span class="reserved">struct</span> <span class="type struct">InlineArray</span>&lt;<span class="type param">T</span>, <span class="reserved">int</span> <span class="variable">N</span>&gt;;
</pre>
<p>こういう「public にできる(一時しのぎではないちゃんとした) <code>InlineArray</code> 型」があるのなら、
C# 側でももう少し踏み込んだ文法を導入したかったみたいです。
候補として挙がっていたのは、<code>int[N]</code> という書き方で「長さ N の <code>InlineArray</code>」を書けるようにするというものです。</p>
<pre class="source" title="T[N]">
<span class="comment">// ※仮定の文法</span>
<span class="reserved">var</span> <span class="variable">c</span> = <span class="reserved">new</span> <span class="type">C</span>();

<span class="reserved">int</span>[3] <span class="reserved">values</span> = <span class="variable">c</span>.Values;

<span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span>[3] _values;
    <span class="reserved">public</span> <span class="reserved">int</span>[3] Values =&gt; _values;
}
</pre>
<p>前述の <code>InlineArray&lt;T, int N&gt;</code> みたいな書き方をできるようにするのは結構大変で、
短期的には実現しそうになく、
それに依存しそうな <code>int[N]</code> という書き方も残念ながらしばらく実現の見込みはありません。</p>
 ]]></description>
				<pubDate>Wed, 20 Sep 2023 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>ローカル関数と匿名関数</title>
				<link>http://www.ufcpp.net/study/csharp/functional/fun_localfunctions/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>C# には、関数内に関数を書く方法として、ローカル関数と匿名関数という2つの機能があります。</p>
<p>いずれも共通して、以下のような性質があります。</p>
<ul>
<li>定義している関数の中でしか使えない</li>
<li>周りの(定義している関数側にある)ローカル変数を取り込める</li>
</ul>
<p>ローカル関数の方ができることは多いですが、書ける場所は少なくなります。
匿名関数はその逆で、できることに少し制限がある代わりに、どこにでも書けます。</p>
<p>サンプル コード: <a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Functional/LocalFunctions">https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Functional/LocalFunctions</a></p>
<h2><a id="local-function">ローカル関数</h2>
<h5 class="version version7">Ver. 7</h5>
<p>C# 7では、関数の中で別の関数を定義して使うことができます。
関数の中でしか使えないため、<strong id="key-local">ローカル関数</strong>(local function: その場所でしか使えない関数)と呼びます。</p>
<p>例えば以下のように書けます。</p>
<pre class="source" title="ローカル関数の例">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// Main 関数の中で、ローカル関数 f を定義</span>
        <em><span class="reserved">int</span> f(<span class="reserved">int</span> n) =&gt; n &gt;= 1 ? n * f(n - 1) : 1;</em>

        <span class="type">Console</span>.WriteLine(f(10));
    }
}
</code></pre>
<p>ローカル関数(この例でいう <code>f</code>)は、定義した関数(この例でいう <code>Main</code>メソッド)の中でしか使えません。</p>
<p>ローカル関数は、通常のメソッドでできることであれば概ね何でもできます。例えば、以下のようなこともできます。</p>
<ul>
<li>再帰呼び出し</li>
<li>イテレーター</li>
<li>非同期メソッド</li>
</ul>
<p>また、メソッド内に限らず、<a href="http://ufcpp.net/study/csharp/st_function.html#sec-function-member">関数メンバー</a>ならどれの中でも定義できます。</p>
<pre class="source" title="メソッドに限らず、プロパティやコンストラクター、演算子等の中でローカル関数を定義する例">
<code><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> Sample()
    {
        <span class="reserved">int</span> f(<span class="reserved">int</span> n) =&gt; n * n;
    }

    <span class="reserved">public</span> <span class="reserved">int</span> Property
    {
        <span class="reserved">get</span>
        {
            <span class="reserved">int</span> f(<span class="reserved">int</span> n) =&gt; n * n;
            <span class="reserved">return</span> f(10);
        }
    }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Sample</span> <span class="reserved">operator</span>+(<span class="type">Sample</span> x)
    {
        <span class="reserved">int</span> f(<span class="reserved">int</span> n) =&gt; n * n;
        <span class="reserved">return</span> <span class="reserved">null</span>;
    }
}
</code></pre>
<h3><a id="local-function-attribute">ローカル関数への属性適用</h3>
<h5 class="version version9">Ver. 9.0</h5>
<p>ローカル関数の追加当初、ローカル関数には属性を付けれなかったんですが、C# 9.0 でできるようになりました。</p>
<pre class="source" title="ローカル関数に属性を付ける">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Diagnostics.CodeAnalysis;
 
<span class="method">m</span>(<span class="string">&quot;&quot;</span>, <span class="string">&quot;&quot;</span>);
 
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">string</span>? <span class="variable">a</span>, <span class="reserved">string</span>? <span class="variable">b</span>)
{
    <span class="comment">// C# 9.0 からローカル関数に属性を付けれる。</span>
    <span class="comment">// C# 8.0 の null 許容参照型がらみで特に有用。</span>
    [<span class="reserved">return</span>: <span class="type">NotNullIfNotNull</span>(<span class="string">&quot;s&quot;</span>)]
    <span class="reserved">string</span>? <span class="method">toLower</span>(<span class="reserved">string</span>? <span class="variable">s</span>) =&gt; <span class="variable">s</span>?.<span class="method">ToLower</span>();
 
    <span class="control">if</span> (<span class="variable">a</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span> &amp;&amp; <span class="variable">b</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span>)
    {
        <span class="comment">// a, b の null 許容性が、NotNullIfNotNull 属性のおかげで al, bl に伝搬。</span>
        <span class="reserved">string</span> <span class="variable">al</span> = <span class="method">toLower</span>(<span class="variable">a</span>);
        <span class="reserved">string</span> <span class="variable">bl</span> = <span class="method">toLower</span>(<span class="variable">a</span>);
 
        <span class="comment">// a, b が非 null なので、al, bl は非 null で確定済み。改めてのチェック不要。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">al</span>.<span class="method">GetHashCode</span>());
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">bl</span>.<span class="method">GetHashCode</span>());
    }
}
</code></pre>
<p>ローカル関数が追加された C# 7.0 時点で特に属性を付けれない積極的な理由はなく、
9.0 で入ったのは単に実装都合です。
(メソッド本体(<code>{}</code> の中身)内で属性を使えるような文法がこれまで全くなくて、
新たに書かないといけないコードが案外多く、
単純な割には実装コストが高くて後回しになっていただけ。
C# 8.0 の <a href="/study/csharp/resource/nullablereferencetype/">null 許容参照型</a>がらみでローカル関数にも属性を付けたい需要が急激に増えたので実装優先度が上がったみたいです。)</p>
<h3><a id="local-function-usage">ローカル関数の使い道</h3>
<p>ローカル関数を使いたくなる一番の動機は、定義した関数内からだけ使えるというになるでしょう。</p>
<p>あるメソッド<code>M</code>の中から、その<code>M</code>でしか使わないメソッドを呼び出したい場面が時々あります。
このとき、ローカル関数を使わないと、<code>M</code>でしか使わないメソッドに<code>MInternal</code>など、あまり意味のない名前を付ける羽目になり、不格好です。</p>
<pre class="source" title="不格好な Internal メソッド">
<code><reserved></span><span class="reserved">static</span> <span class="reserved">void</span> M()
{
    <span class="comment">// 何らかの前準備とか</span>
    MInternal();
}

<span class="reserved">static</span> <span class="reserved">void</span> MInternal()
{
    <span class="comment">// 実際の処理はこちらで</span>
}
</code></pre>
<p>名前が不格好な程度ならそれほど大きな問題ではないんですが、
この<code>MInternal</code>は、<code>M</code>以外のメソッドからも呼べてしまうという問題が発生します。
こういう場合に、ローカル関数を使えば、以下のように書くことができ、呼びたい場所からだけ呼べるようになります。</p>
<pre class="source" title="ローカル関数を使って呼べる場所をメソッド内に限定">
<code><span class="reserved">static</span> <span class="reserved">void</span> M()
{
    <span class="comment">// 何らかの前準備とか</span>

    <span class="reserved">void</span> m()
    {
        <span class="comment">// 実際の処理はこちらで</span>
    }

    m();
}
</code></pre>
<h4><a id="iterator">例1: イテレーターの引数チェック</h4>
<p>例えば、<a href="http://ufcpp.net/study/csharp/sp2_iterator.html#iterator">イテレーター</a>の引数チェックではこういうコードが必要になりがちです。</p>
<p>例として、標準ライブラリ中の処理を1つ自作してみましょう。<code>Enumerable</code>クラス(<code>System.Linq</code>名前空間)の<code>Where</code>メソッドをまねてみます。
まず、単純な書き方をしてみましょう。この書き方には、コメントに書いてあるように、少し欠陥があります。</p>
<pre class="source" title="Whereをまねたもの(欠陥あり)">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">MyEnumerable</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; Where&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source, <span class="type">Func</span>&lt;<span class="type">T</span>, <span class="reserved">bool</span>&gt; predicate)
    {
        <span class="comment">// イテレーター中のコードは、最初に列挙した(foreach などに渡す)時に初めて実行される</span>
        <span class="comment">// このメソッドを呼んだ時点では、↓この引数チェックが働かない</span>
        <span class="reserved">if</span> (source == <span class="reserved">null</span>) <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentNullException</span>(<span class="reserved">nameof</span>(source));
        <span class="reserved">if</span> (predicate == <span class="reserved">null</span>) <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentNullException</span>(<span class="reserved">nameof</span>(predicate));

        <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> source)
            <span class="reserved">if</span> (predicate(x))
                <span class="reserved">yield</span> <span class="reserved">return</span> x;
    }
}
</code></pre>
<p>コメント中に「メソッドを呼んだ時点では引数チェックが働かない」とありますが、使う側のコードも書いてみると問題がよりはっきりするでしょう。
以下のように、期待されるのと異なるタイミングで例外が起きます。</p>
<pre class="source" title="欠陥版の問題点の例">
<code><reserved></span><span class="reserved">using</span> Iterator1;
<span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="type">IEnumerable</span>&lt;<span class="reserved">string</span>&gt; input = <span class="reserved">null</span>;

        <span class="comment">// input が null なので例外を投げてほしい</span>
        <span class="comment">// 多くの人がそれを期待する</span>
        <span class="reserved">var</span> output = input.Where(x =&gt; x.Length &lt; 10);

        <span class="type">Console</span>.WriteLine(<span class="string">"ここが表示されるとおかしい"</span>); <span class="comment">// でも表示される</span>

        <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> output) <span class="comment">// 実際に例外が出るのはこの行</span>
        {
            <span class="type">Console</span>.WriteLine(x);
        }
    }
}
</code></pre>
<p>そこで、よく以下のような書き方をします。</p>
<pre class="source" title="Whereをまねたもの(実物に近い書き方)">
<code><reserved></span><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">MyEnumerable</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; Where&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source, <span class="type">Func</span>&lt;<span class="type">T</span>, <span class="reserved">bool</span>&gt; predicate)
    {
        <span class="comment">// イテレーターではなくなった(イテレーターなのは WhereInternal の方)ので、ちゃんと呼ばれた時点でチェックが走る</span>
        <span class="reserved">if</span> (source == <span class="reserved">null</span>) <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentNullException</span>(<span class="reserved">nameof</span>(source));
        <span class="reserved">if</span> (predicate == <span class="reserved">null</span>) <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentNullException</span>(<span class="reserved">nameof</span>(predicate));

        <span class="reserved">return</span> WhereInternal(source, predicate);
    }

    <span class="reserved">private</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; WhereInternal&lt;<span class="type">T</span>&gt;(<span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source, <span class="type">Func</span>&lt;<span class="type">T</span>, <span class="reserved">bool</span>&gt; predicate)
    {
        <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> source)
            <span class="reserved">if</span> (predicate(x))
                <span class="reserved">yield</span> <span class="reserved">return</span> x;
    }
}
</code></pre>
<p>こういう場面こそ、ローカル関数の出番です。
以下のように書き直すことができます。</p>
<pre class="source" title="Whereをまねたもの(ローカル関数を使った実装)">
<code><reserved></span><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">MyEnumerable</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; Where&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source, <span class="type">Func</span>&lt;<span class="type">T</span>, <span class="reserved">bool</span>&gt; predicate)
    {
        <span class="comment">// イテレーターではなくなった(イテレーターなのは WhereInternal の方)ので、ちゃんと呼ばれた時点でチェックが走る</span>
        <span class="reserved">if</span> (source == <span class="reserved">null</span>) <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentNullException</span>(<span class="reserved">nameof</span>(source));
        <span class="reserved">if</span> (predicate == <span class="reserved">null</span>) <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentNullException</span>(<span class="reserved">nameof</span>(predicate));

        <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; f()
        {
            <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> source)
                <span class="reserved">if</span> (predicate(x))
                    <span class="reserved">yield</span> <span class="reserved">return</span> x;
        }

        <span class="reserved">return</span> f();
    }
}
</code></pre>
<h4><a id="ToArray">例2: イテレーターをToArrayしてから返す</h4>
<p><a href="http://ufcpp.net/study/csharp/sp2_iterator.html#iterator">イテレーター</a>を使って書きたいものの、
遅延実行(foreachで列挙されて初めて実行される)ではなく即座に実行するために、<code>ToArray</code>メソッド(<code>System.Enumerable</code>クラスの拡張メソッド)を掛けてから返したい場合があります。</p>
<p>この場合も、1つのメソッドからしか呼ばれないメソッドが作られがちです。
例えば以下のようなコードになります。</p>
<pre class="source" title="ToArrayするためだけに作られるメソッド">
<code><span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Linq;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">MyEnumerable</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">U</span>[] SelectToArray&lt;<span class="type">T</span>, <span class="type">U</span>&gt;(<span class="reserved">this</span> <span class="type">T</span>[] array, <span class="type">Func</span>&lt;<span class="type">T</span>, <span class="type">U</span>&gt; selector)
    {
        <span class="reserved">return</span> Select(array, selector).ToArray();
    }

    <span class="comment">// SelectToArray からしか呼ばれない</span>
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type">U</span>&gt; Select&lt;<span class="type">T</span>, <span class="type">U</span>&gt;(<span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source, <span class="type">Func</span>&lt;<span class="type">T</span>, <span class="type">U</span>&gt; selector)
    {
        <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> source)
            <span class="reserved">yield</span> <span class="reserved">return</span> selector(x);
    }
}
</code></pre>
<p>これも、以下のように書き直せます。</p>
<pre class="source" title="ローカル関数を使って書き直し">
<code><span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Linq;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">MyEnumerable</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">U</span>[] SelectToArray&lt;<span class="type">T</span>, <span class="type">U</span>&gt;(<span class="reserved">this</span> <span class="type">T</span>[] array, <span class="type">Func</span>&lt;<span class="type">T</span>, <span class="type">U</span>&gt; selector)
    {
        <span class="type">IEnumerable</span>&lt;<span class="type">U</span>&gt; inner()
        {
            <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> array)
                <span class="reserved">yield</span> <span class="reserved">return</span> selector(x);
        }

        <span class="reserved">return</span> inner().ToArray();
    }
}
</code></pre>
<h4><a id="async-task">例3: 非同期メソッドのキャッシュ</h4>
<p>最後の例は、非同期メソッドで作った<code>Task</code>のキャッシュです。</p>
<p>非同期メソッドを呼び出すと、呼び出すたびに<code>Task</code>クラス(<code>System.Threading.Tasks</code>名前空間)のインスタンスが作られます。
しかし、これを、1度だけ呼んで、2度目以降はキャッシュして持っている<code>Task</code>を返したいことがあります。</p>
<pre class="source" title="Taskをキャッシュする例">
<code><reserved></span><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> MainAsync()
{
    <span class="comment">// 何度か呼ぶけども、キャッシュされているので通信は1回きり</span>
    <span class="type">Console</span>.WriteLine(<span class="reserved">await</span> LoadAsync());
    <span class="type">Console</span>.WriteLine(<span class="reserved">await</span> LoadAsync());
    <span class="type">Console</span>.WriteLine(<span class="reserved">await</span> LoadAsync());
}

<span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">string</span>&gt; LoadAsync()
{
    _loadCache = _loadCache ?? LoadAsyncInternal();
    <span class="reserved">return</span> _loadCache;
}
<span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">string</span>&gt; _loadCache;

<span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span>&lt;<span class="reserved">string</span>&gt; LoadAsyncInternal()
{
    <span class="reserved">var</span> c = <span class="reserved">new</span> <span class="type">HttpClient</span>();
    <span class="reserved">var</span> res = <span class="reserved">await</span> c.GetAsync(<span class="string">"http://ufcpp.net"</span>);
    <span class="reserved">var</span> content = <span class="reserved">await</span> res.Content.ReadAsStringAsync();

    <span class="reserved">return</span> <span class="type">Regex</span>.Match(content, @"\&lt;title\&gt;(.*?)\&lt;").Groups[1].Value;
}
</code></pre>
<p>これも、以下のように書き直せます。</p>
<pre class="source" title="ローカル関数を使って書き直し">
<code><span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">string</span>&gt; LoadAsync()
{
    <span class="reserved">async</span> <span class="type">Task</span>&lt;<span class="reserved">string</span>&gt; inner()
    {
        <span class="reserved">var</span> c = <span class="reserved">new</span> <span class="type">HttpClient</span>();
        <span class="reserved">var</span> res = <span class="reserved">await</span> c.GetAsync(<span class="string">"http://ufcpp.net"</span>);
        <span class="reserved">var</span> content = <span class="reserved">await</span> res.Content.ReadAsStringAsync();

        <span class="reserved">return</span> <span class="type">Regex</span>.Match(content, @"\&lt;title\&gt;(.*?)\&lt;").Groups[1].Value;
    }

    _loadCache = _loadCache ?? inner();
    <span class="reserved">return</span> _loadCache;
}
<span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">string</span>&gt; _loadCache;
</code></pre>
<h2><a id="anonymous-function">匿名関数 (ラムダ式)</h2>
<h5 class="version version2">Ver. 2.0</h5>
<h5 class="version version3">Ver. 3.0</h5>
<p>C# 2.0では<a href="http://ufcpp.net/study/csharp/sp_delegate.html#anonymous-method">匿名メソッド式</a>、C# 3.0では<a href="http://ufcpp.net/study/csharp/sp_delegate.html#lambda">ラムダ式</a>という構文が入り、これらを合わせて<strong id="key-anonymous" class="keyword">匿名関数</strong>と呼びます。</p>
<p>(ラムダ式は匿名メソッド式のほぼ上位互換です。
C#開発者も、「ラムダ式が最初からあれば、匿名メソッド式の構文はC#には不要だった」と言っています。
そのため、匿名メソッド式はC# 2.0時代の互換性を保つためだけの機能だと考えて差し支えないです。
こういう背景から、匿名関数という名前が使われることはあまりなく、
<strong id="key-lambda" class="keyword">ラムダ式</strong>(lambda expression)という言葉の方がよく目にすることになると思います。
本節でも、以下の説明はラムダ式でのみ行います。)</p>
<p>ラムダ式は、以下の例のように、引数リストと関数本体を <code>=&gt;</code>でつないで書きます。</p>
<pre class="source" title="ラムダ式の例1">
<code>(<span class="reserved">int</span> x) =&gt;
{
    <span class="reserved">var</span> sum = 0;
    <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; x; i++)
        sum += i;
    <span class="reserved">return</span> sum;
}
</code></pre>
<p>この例を見ての通り、関数名がありません。これが「匿名」と呼ばれる理由です。</p>
<p><code>=&gt;</code> は、矢印のように見えることからアロー演算子(arrow operator)と呼ばれたり、
その矢印を「行先」に見立ててgoes to演算子と呼ばれたりします。
(実際、<code>x =&gt; 2 * x</code>を x goes to 2x (xが2xに行く)と読むと、英語的に案外しっくり来るそうです。)</p>
<p><code>=&gt;</code> の後ろの関数本体の部分は、式が1つだけの場合、<code>{}</code>と<code>return</code>を省略して、以下のように書くことができます。</p>
<pre class="source" title="ラムダ式の例2 (本体が式1つだけの場合)">
<code>(<span class="reserved">int</span> x) =&gt; x * x
</code></pre>
<p>また、<code>=&gt;</code>の前の引数リストでは、引数の型を推論できる場合には型を省略できます。
このとき、引数が1つだけであれば、<code>()</code>も省略できます。</p>
<pre class="source" title="ラムダ式の例3 (引数の型の省略)">
<code>(x, y) =&gt; x * y
</code></pre>
<pre class="source" title="ラムダ式の例3 (引数の型の省略)">
<code>x =&gt; x * x
</code></pre>
<p>例えば、以下のような使い方ができます。</p>
<pre class="source" title="匿名関数の例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Linq;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> input = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 };
        <span class="reserved">var</span> output = input
            .Where(<em>n =&gt; n &gt; 3</em>)
            .Select(<em>n =&gt; n * n</em>);

        <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> output)
        {
            <span class="type">Console</span>.WriteLine(x);
        }
    }
}
</code></pre>
<p>強調表示している部分が匿名関数です。
匿名関数の引数(<code>n</code>)の型は、渡す先（<code>Where</code>や<code>Select</code>)から推論されます。</p>
<h2><a id="pros-cons">ローカル関数と匿名関数のそれぞれの利点</h2>
<p>前節の例のように、匿名関数は式(この例では<code>Where</code>メソッドや<code>Select</code>メソッドの引数)の中に書くことができます。
ここがローカル関数との最大の違いになります。
ローカル関数の場合は、関数(この場合<code>Main</code>メソッド)直下にしか書けません。</p>
<p>匿名関数はどこにでも書けるという利点がある一方で、以下のような制限があります。</p>
<ul>
<li>再帰呼び出しが素直にはできない</li>
<li>イテレーターにできない</li>
<li>ジェネリックにできない</li>
<li>引数の既定値を持てない</li>
</ul>
<pre class="source" title="匿名関数の再帰呼び出しは面倒">
<code><span class="comment">// ローカル関数は素直に再帰を書ける</span>
<span class="reserved">int</span> f1(<span class="reserved">int</span> n) =&gt; n &gt;= 1 ? n * f1(n - 1) : 1;

<span class="comment">// 匿名関数はひと手間必要</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; f2 = <span class="reserved">null</span>;
f2 = n =&gt; n &gt;= 1 ? n * f2(n - 1) : 1;
</code></pre>
<pre class="source" title="匿名関数はイテレーターにできない">
<code><span class="comment">// ローカル関数ならイテレーターにできる</span>
<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; g1(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; items)
{
    <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> items)
        <span class="reserved">yield</span> <span class="reserved">return</span> 2 * x;
}

<span class="comment">// 匿名関数ではコンパイル エラー</span>
<span class="type">Func</span>&lt;<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt;, <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt;&gt; g2 = items =&gt;
{
    <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> items)
        <span class="reserved">yield</span> <span class="reserved">return</span> 2 * x;
}
</code></pre>
<pre class="source" title="匿名関数はジェネリックにできない">
<code><span class="comment">// ローカル関数ならジェネリックに使える</span>
<span class="reserved">bool</span> eq1&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="type">T</span> y) <span class="reserved">where</span> <span class="type">T</span> : <span class="type">IComparable</span>&lt;<span class="type">T</span>&gt; =&gt; x.CompareTo(y) == 0;
<span class="type">Console</span>.WriteLine(eq1(1, 2));
<span class="type">Console</span>.WriteLine(eq1(<span class="string">"aaa"</span>, <span class="string">"aaa"</span>));

<span class="comment">// 匿名関数はジェネリックにならない</span>
<span class="comment">// Func&lt;T, T, bool&gt; の時点でコンパイル エラー</span>
<span class="comment">// where 制約を付ける構文もない</span>
<span class="type">Func</span>&lt;T, T, <span class="reserved">bool</span>&gt; eq2 = (x, y) =&gt; x.CompareTo(y) == 0;
<span class="comment">// 当然、呼べない</span>
<span class="type">Console</span>.WriteLine(eq2(1, 2));
<span class="type">Console</span>.WriteLine(eq2(<span class="string">"aaa"</span>, <span class="string">"aaa"</span>));
</code></pre>
<pre class="source" title="匿名関数の引数には既定値を与えられない">
<code><comment></span><span class="comment">// ローカル関数の引数には既定値を与えられる</span>
<span class="reserved">int</span> f1(<span class="reserved">int</span> n = 0) =&gt; 2 * n;
<span class="type">Console</span>.WriteLine(f1());
<span class="type">Console</span>.WriteLine(f1(5));

<span class="comment">// 匿名関数は無理</span>
<span class="comment">// この時点でコンパイル エラー</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; f2 = (<span class="reserved">int</span> n = 0) =&gt; 2 * n;
<span class="comment">// 当然、呼べない</span>
<span class="type">Console</span>.WriteLine(f2());
<span class="type">Console</span>.WriteLine(f2(5));
</code></pre>
<p>すなわち、以下のことが言えます。</p>
<ul>
<li>ローカル関数は書ける場所が限られるものの、機能的には通常のメソッドと同程度に何でも書ける</li>
<li>逆に、匿名関数はどこにでも書ける代わりに、いくつか機能的に制限がある</li>
</ul>
<p>また、詳しくは「<a href="http://ufcpp.net/study/csharp/sp2_anonymousmethod.html#closure-local-function">[雑記] 匿名関数のコンパイル結果</a>」で説明しますが、
多少、実行性能にも差があります。
呼び出し方次第ではありますが、ローカル関数の方が高速になる場合があります。</p>
<h3><a id="background-local-function">余談: 経緯</h3>
<p>ちなみに、C# 7でローカル関数が導入されるに至った経緯としては、匿名関数の制限を緩和してほしいという要望から始まっています。
すなわち、前述の、「匿名関数はイテレーター化できない、再帰呼び出しが大変」という問題の解決策がローカル関数です。</p>
<p>書ける場所にも違いがあるので、この要望が完全に満たされたわけではありません。
しかし、「イテレーター化」あるいは「再帰呼び出し」をしたい場面を改めて考えてみたところ、
「別に式中に書きたいわけじゃない」、「ローカル関数で十分」、「ローカル関数の方が実行性能的にお得になる場面もある」となったみたいです。</p>
<h2><a id="capture-local">ローカル変数の捕獲</h2>
<p>ローカル関数でも匿名関数でも、周りの(定義している関数内の)ローカル変数や引数を取り込んで使うことができます。
例えば以下のようなコードが書けます。</p>
<pre class="source" title="ローカル変数の取り込みの例">
<code><reserved></span><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Linq;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// ユーザーからの入力をローカル変数に記録</span>
        <span class="reserved">var</span> m = <span class="reserved">int</span>.Parse(<span class="type">Console</span>.ReadLine());
        <span class="reserved">var</span> n = <span class="reserved">int</span>.Parse(<span class="type">Console</span>.ReadLine());

        <span class="reserved">var</span> input = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        <span class="comment">// ユーザーの入力 m よりも大きいか判定</span>
        <span class="reserved">bool</span> filter(<span class="reserved">int</span> x) =&gt; x &gt; <em>m</em>;

        <span class="reserved">var</span> output = input
            .Where(filter)
            .Select(x =&gt; <em>n</em> * x); <span class="comment">// ユーザーの入力 n を掛ける</span>

        <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> output)
        {
            <span class="type">Console</span>.WriteLine(x);
        }
    }
}
</code></pre>
<p>こういう処理を、ローカル変数の捕獲(capture)と言います(カタカナ言葉で「キャプチャする」ともよく言います)。
また、ローカル変数を捕獲しているローカル関数や匿名関数を<strong id="closure" class="keyword">クロージャ</strong>(closure: 囲い込み)と呼んだりします。</p>
<p>捕獲したローカル変数は書き換えることもできます。</p>
<pre class="source" title="捕獲したローカル変数をクロージャ内で書き換える例">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> x = 1;

        <span class="comment">// ローカル関数内で変数xを書き換え</span>
        <span class="reserved">void</span> f(<span class="reserved">int</span> n) =&gt; x = n;

        <span class="type">Console</span>.WriteLine(x); <span class="comment">// 1</span>

        f(2);
        <span class="type">Console</span>.WriteLine(x); <span class="comment">// 2</span>
    }
}
</code></pre>
<p>注意点として、詳しくは「<a href="http://ufcpp.net/study/csharp/sp2_anonymousmethod.html#closure">[雑記] 匿名関数のコンパイル結果</a>」で説明しますが、
ローカル変数の取り込みには少々ペナルティがかかります。
実行性能への要求が極めて高い場合には、避けれるなら避けるべきです
(ペナルティは小さいので、ボトルネックになっていない場所でまで無理に頑張る必要はありません)。</p>
<h2><a id="avoid-capture">ローカル変数捕獲の禁止</h2>
<p>前節での説明の通り、外部の変数を捕獲してしまうと少々ペナルティが掛かります。
意図してやっているのならいいんですが、無自覚にやってしまうのは避けたいです。</p>
<p>そこで、C# 8.0 では静的ローカル関数、C# 9.0 では静的匿名関数という仕様が入りました。</p>
<h3><a id="static-local-function">静的ローカル関数</h3>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 から、外部の変数を捕獲しないことを明示するため、
ローカル関数に <code>static</code> 修飾を付けれるようになりました。
この機能を<strong id="key-static-local-function" class="keyword">静的ローカル関数</strong>(static local function)と呼びます。</p>
<pre class="source" title="静的ローカル関数の例">
<code><span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">a</span>)
{
    <span class="comment">// 外部の変数(引数)を捕獲(クロージャ化)。</span>
    <span class="reserved">int</span> <span class="method">f</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">a</span> * <span class="variable">x</span>;
 
    <span class="comment">// static を付けて、クロージャ化を禁止。</span>
    <span class="comment">// a を使っているところでコンパイル エラーになる。</span>
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">g</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="error"><span class="variable">a</span></span> * <span class="variable">x</span>;
}
</code></pre>
<p>「<a href="/study/csharp/sp2_anonymousmethod.html#compile_anonymous">匿名関数のコンパイル結果</a>」で説明していますが、
こういう何も捕獲していないローカル関数は、静的メソッドに展開されます。
なので、<code>static</code> 修飾子を使って、静的ローカル関数と呼びます。</p>
<p>ちなみに、「静的」の名前が示す通り、インスタンス メンバーの参照もできません。</p>
<pre class="source" title="静的ローカル関数はインスタンス メンバーに触れない">
<code><span class="reserved">class</span> <span class="type">LocalFunction</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> StaticProperty { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> InstanceProperty { <span class="reserved">get</span>; <span class="reserved">set</span>; }
 
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>()
    {
        <span class="comment">// これは OK。</span>
        <span class="reserved"><em>static</em></span> <span class="reserved">int</span> <span class="method">f1</span>() =&gt; StaticProperty;
 
        <span class="comment">// これはコンパイル エラー。</span>
        <span class="reserved"><em>static</em></span> <span class="reserved">int</span> <span class="method">f2</span>() =&gt; <span class="error">InstanceProperty</span>;
    }
}
</code></pre>
<p>ちなみに、定数や <code>nameof</code> であれば外側のスコープにあるものに触ることができます。
例えば以下のコードはコンパイルできます。</p>
<pre class="source" title="定数なのでセーフ">
<code><span class="reserved">using</span> System;
 
<span class="reserved">const</span> <span class="reserved">string</span> s = <span class="string">&quot;bc&quot;</span>;
<span class="reserved">int</span> <span class="variable">a</span> = 0;
 
<span class="comment">// a を使っているように見えて、nameof(a) は単に &quot;a&quot; に展開されるのでセーフ。</span>
<span class="reserved">static</span> <span class="reserved">string</span> <span class="method">m</span>() =&gt; <span class="reserved">nameof</span>(<span class="variable">a</span>) + s;
 
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">m</span>());
</code></pre>
<h3><a id="static-anonymous-function">静的匿名関数</h3>
<h5 class="version version9">Ver. 9.0</h5>
<p>同様に、C# 9.0 では匿名関数に対しても <code>static</code> 修飾子を付けれるようになりました。
意味的には<a href="#static-local-function">静的ローカル関数</a>と全く同じで、「外部の変数を捕獲しない」という宣言になります。
ラムダ式、匿名メソッド式ともに、式の前に <code>static</code> を付けます。</p>
<pre class="source" title="静的匿名関数">
<code><span class="reserved">using</span> System;
 
<span class="reserved">int</span> <span class="variable">a</span> = 0;
 
<span class="comment">// 以下の2行は自身の引数しか使っていないので static にしても怒られない。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">ok1</span> = <span class="reserved"><em>static</em></span> <span class="variable">x</span> =&gt; <span class="variable">x</span> * <span class="variable">x</span>;
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">ok2</span> = <span class="reserved"><em>static</em></span> <span class="reserved">delegate</span> (<span class="reserved">int</span> <span class="variable">x</span>) { <span class="control">return</span> <span class="variable">x</span> * <span class="variable">x</span>; };
 
<span class="comment">// 以下の2行は外側のローカル変数 a を使ってしまったのでコンパイル エラー。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">ng1</span> = <span class="reserved"><em>static</em></span> <span class="variable">x</span> =&gt; <span class="variable"><span class="error">a</span></span> * <span class="variable">x</span>;
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">ng2</span> = <span class="reserved"><em>static</em></span> <span class="reserved">delegate</span> (<span class="reserved">int</span> <span class="variable">x</span>) { <span class="control">return</span> <span class="variable"><span class="error">a</span></span> * <span class="variable">x</span>; };
</code></pre>
<p>静的ローカル関数がある時点で匿名関数でも同様のことができてしかるべきもので、
ただちょっと構文解析が大変なので後回しになっていたものです。
順当に「1バージョン遅れで実装」となりました。</p>
<h3><a id="not-pure">注意: 純粋関数(副作用なしのメソッド)ではない</h3>
<p>静的ローカル関数にしても静的匿名関数にしても、ローカル変数の捕獲(によるパフォーマンスのペナルティ)は避けることができますが、静的フィールドの読み書きは普通にできます。
例えば以下のコードは有効な C# 8.0 コードになります。</p>
<pre class="source" title="副作用がある静的ローカル関数の例">
<code><span class="reserved">class</span> <span class="type">StaticLocalFunction</span>
{
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">int</span> _count;
 
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>()
    {
        <span class="comment">// ローカル関数内から外の変数を読み書きしてる。</span>
        <span class="comment">// _count が static なのでコンパイル可能。</span>
        <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">local</span>() =&gt; ++_count;
 
        System.<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">local</span>());
    }
}
</code></pre>
<p><code>static</code> を付けてもいわゆる純粋関数(pure function、同じ引数で呼べば必ず同じ戻り値が得られる)にはならないので注意してください。</p>
<h2><a id="shadowing">変数のシャドーイング</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>前節の静的ローカル関数に伴って新たに認められた機能に、変数の<strong id="key-shadowing" class="keyword">シャドーイング</strong>(shadowing)というものがあります。
ローカル関数内で、外側にすでに存在している変数や引数と同じ名前で、
新たに変数・引数を定義できる機能です。
外側のものを「影で覆い隠す」という意味で shadowing と呼びます。</p>
<pre class="source" title="シャドーイングの例">
<code><span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">a</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span>;
 
    <span class="reserved">int</span> <span class="method">f</span>(<span class="reserved">int</span> <span class="variable">a</span>) <span class="comment">// この a は M(int a) の a とは別物</span>
    {
        <span class="reserved">var</span> <span class="variable">x</span> = <span class="variable">a</span>; <span class="comment">// この x も外側の x とは別物</span>
        <span class="control">return</span> <span class="variable">x</span>;
    }
}
</code></pre>
<p>C# 8.0 以降であれば、普通のローカル関数でも使えます。
ただ、外側の変数を捕獲したものなのか、ローカル関数側でシャドーイングしたものなのかの区別がわかりにくくなるという問題があるので、静的ローカル関数と同時(C# 8.0)に認められました。
静的ローカル関数でだけ認めるのも気持ち悪く、普通のローカル関数でも認めるようにしたそうです。</p>
<h2><a id="lambda-csharp10">ラムダ式の戻り値の明示と属性</h2>
<h5 class="version version10">Ver. 10</h5>
<p>C# 10.0 で、ラムダ式の戻り値を明示できるようになりました。
また、属性も付けられるようになりました。
例えば以下のようなコードが書けます。</p>
<pre class="source" title="ラムダ式の戻り値の明示と属性の追加">
<code><span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span> =
    <em>[<span class="type">A</span>]</em>
    <em><span class="reserved">int</span></em> (<span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>)
    =&gt; <span class="variable">x</span> + <span class="variable">y</span>;

<span class="reserved">class</span> <span class="type">AAttribute</span> : <span class="type">Attribute</span> { }
</code></pre>
<p>これだけ見るとあまり使い道がなさそうな機能ですが、
同時に入る<a href="/study/csharp/sp_delegate.html#natural-type">デリゲートの自然な型決定</a>と併せるとそれなりに意味を持ちます。
「<a href="/study/csharp/sp_delegate.html#natural-type">自然な型</a>」の方でも書いていますが、
 .NET 6.0 (C# 10.0 と同世代)の Web アプリ テンプレートで作られるコードは以下のようになっています。</p>
<pre class="source" title="Web アプリの .NET 6 新テンプレート">
<code><span class="reserved">var</span> <span class="variable">builder</span> = <span class="type">WebApplication</span>.<span class="method">CreateBuilder</span>(<span class="variable">args</span>);
<span class="reserved">var</span> <span class="variable">app</span> = <span class="variable">builder</span>.<span class="method">Build</span>();

<span class="variable">app</span>.<span class="method">MapGet</span>(<span class="string">&quot;/&quot;</span>, () =&gt; <span class="string">&quot;Hello World!&quot;</span>);

<span class="variable">app</span>.<span class="method">Run</span>();
</code></pre>
<p><code>MapGet</code> にラムダ式を渡すことで Web API を簡潔に書けるようになりました。
この書き方がそのまま大規模開発に向いているかというと微妙ですが、
少なくとも入門用のコードとしてはこれくらいの簡潔さが求められています。</p>
<p>この例では、HTTP GET で <code>/</code> (Web サイトのルート)にアクセスすると、<code>Hellow World!</code> という文字列を返します。
ここで、<code>/</code> アクセス時に色々と凝ったことをしようと思うと、属性や戻り値の型を指定したくなります。</p>
<h3><a id="lambda-explicit-return">戻り値の型の明示</h3>
<p>ラムダ式に戻り値の型を明示できるようになりました。
戻り値の型は、引数の <code>()</code> の前に書きます。
例えば以下のような書き方ができます。</p>
<pre class="source" title="ラムダ式の戻り値の型を明示する例">
<code><span class="comment">// 新文法。</span>
<span class="comment">// ラムダ式に戻り値の型を明示。</span>
<span class="comment">// (引数も明示。)</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f1</span> = <em><span class="reserved">int</span></em> (<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span>;

<span class="comment">// 元々の文法。</span>
<span class="comment">// 引数の型の方を明示。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f2</span> = (<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span>;

<span class="comment">// 新文法。</span>
<span class="comment">// 戻り値の型だけ明示。 () が必要。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f3</span> = <em><span class="reserved">int</span></em> (<span class="variable">x</span>) =&gt; <span class="variable">x</span>;

<span class="comment">// これはエラーになる。</span>
<span class="comment">// int が引数に掛かっているのか戻り値に掛かっているのか不明瞭。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f4</span> = <span class="error"><span class="reserved">int</span> x</span> =&gt; x;
</code></pre>
<p>たとえ<a href="/study/csharp/sp_delegate.html#natural-type">自然な型決定</a>と組み合わせたとしても、
たいていの場合は引数だけ型を明示すれば戻り値の型は決定できたりするので、
必要になる場面はそう多くないかもしれません。
以下のようなコード(右辺のラムダ式の部分は C# 9.0 でも有効)でも問題なく自然な型決定ができます。</p>
<pre class="source" title="引数の型だけでも自然な型決定がたいてい可能">
<code><span class="comment">// 引数の int から、戻り値の型が int に決定する。</span>
<span class="comment">// その後、ラムダ式の型は Func&lt;int, int&gt; として決定できる。</span>
<span class="reserved">var</span> <span class="variable">f</span> = (<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span>;
</code></pre>
<p>(おそらく、後述する属性のついでで実装された(ついででやれたから手間が掛かっていない)機能だと思われます。)</p>
<p>戻り値の型の明示が有効なのは、
例えば、
ラムダ式の中身自体がターゲット型推論に依存している場合などです。
サンプル コードとして<a href="/study/csharp/cheatsheet/ap_ver9/#target-typed-conditional">条件演算子のターゲット型推論</a>を使いますが、以下のような式は後者のみ有効になります。</p>
<pre class="source" title="ラムダ式の中身にターゲット型推論を含む場合の例">
<code><span class="comment">// 条件演算子だけでは int と null の共通型が決定できなくて、戻り値の型が決まらない。</span>
<span class="comment">// (条件演算子の後方互換性のために掛かってる制限。)</span>
<span class="reserved">var</span> <span class="variable">f1</span> = <span class="error">(<span class="reserved">bool</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>) =&gt; <span class="variable">x</span> ? <span class="variable">y</span> : <span class="reserved">null</span></span>;

<span class="comment">// 一方で、これなら、戻り値の型からのターゲット型推論で条件演算子を書ける。</span>
<span class="comment">// f2 の自然な型決定もできるようになる (Func&lt;bool, int, int?&gt; になる)。</span>
<span class="reserved">var</span> <span class="variable">f2</span> = <span class="reserved">int</span>? (<span class="reserved">bool</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>) =&gt; <span class="variable">x</span> ? <span class="variable">y</span> : <span class="reserved">null</span>;
</code></pre>
<p>ちなみに、<a href="#static-local-function">静的匿名関数</a>の <code>static</code> と併用する場合、戻り値の型を書く場所は <code>static</code> の後ろです。
(通常のメソッドと同じ。)</p>
<pre class="source" title="static の後ろに戻り値の型">
<code><span class="comment">// 戻り値の型を各場所は static の後ろ。</span>
<span class="reserved">var</span> <span class="variable">f</span> = <span class="reserved">static</span> <span class="reserved">int</span> (<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span>;
</code></pre>
<p>また、明示した戻り値の型からラムダ式の引数の型を推論することはできません。</p>
<pre class="source" title="戻り値の型から引数の型の推論はできない">
<code><span class="comment">// 戻り値の型から引数の型の推論はできない。</span>
<span class="comment">// 結果的に、Func&lt;T, int&gt; への代入はできても、自然な型決定(var などへの代入)はできない。</span>
<span class="reserved">var</span> <span class="variable">f6</span> = <span class="error"><span class="reserved">int</span> (<span class="variable">x</span>) =&gt; <span class="variable">x</span></span>;
</code></pre>
<h3><a id="lambda-attribute">属性</h3>
<p>同じくラムダ式に属性を付けれるようになりました。</p>
<pre class="source" title="ラムダ式に対する属性付与">
<code><span class="reserved">var</span> <span class="variable">f</span> =
    <em>[<span class="type">A</span>]</em>
    <em>[<span class="reserved">return</span>: <span class="type">B</span>]</em>
    <span class="reserved">static</span> <span class="reserved">int</span> (<em>[<span class="type">C</span>]</em> <span class="reserved">int</span> <span class="variable">x</span>)
    =&gt; <span class="variable">x</span>;

[<span class="type">AttributeUsage</span>(<span class="type">AttributeTargets</span>.Method)]
<span class="reserved">class</span> <span class="type">AAttribute</span> : <span class="type">Attribute</span> { }

[<span class="type">AttributeUsage</span>(<span class="type">AttributeTargets</span>.ReturnValue)]
<span class="reserved">class</span> <span class="type">BAttribute</span> : <span class="type">Attribute</span> { }

[<span class="type">AttributeUsage</span>(<span class="type">AttributeTargets</span>.Parameter)]
<span class="reserved">class</span> <span class="type">CAttribute</span> : <span class="type">Attribute</span> { }
</code></pre>
<p>属性を書く位置は通常のメソッドと同じです。
ラムダ式(メソッド)自体、引数、戻り値が対象になります。
また、(<a href="#static-local-function">静的匿名関数</a>と併用するなら)ラムダ式全体(メソッド全体)や戻り値に属性を付けたい場合は <code>static</code> よりも前に書きます。</p>
<p>これも、 .NET 6 の新しい Web テンプレートで使います。
<code>MapGet</code> などのメソッドでは、引数などに属性を付けて Web API の挙動をカスタマイズできます。
例えば以下のような書き方ができます。</p>
<pre class="source" title="新 Web テンプレートに対して属性で挙動を制御する例">
<code><span class="reserved">using</span> Microsoft.AspNetCore.Mvc;

<span class="reserved">var</span> <span class="variable">builder</span> = <span class="type">WebApplication</span>.<span class="method">CreateBuilder</span>(<span class="variable">args</span>);

<span class="comment">// テンプレに1行を追加。DI 用。</span>
<span class="variable">builder</span>.Services.<span class="method">AddSingleton</span>&lt;<span class="type">Counter</span>&gt;();

<span class="reserved">var</span> <span class="variable">app</span> = <span class="variable">builder</span>.<span class="method">Build</span>();

<span class="comment">// テンプレを1行書き換え。引数を DI で受け取ったり、クエリ文字列から受け取ったり。</span>
<span class="comment">// counter: ページをリロードするたびに +1。</span>
<span class="comment">// value: クエリ文字列で数値を指定。</span>
<span class="comment">// その2つの値から何らかの計算して返す。</span>
<span class="variable">app</span>.<span class="method">MapGet</span>(<span class="string">&quot;/&quot;</span>, ([<span class="type">FromServices</span>] <span class="type">Counter</span> <span class="variable">counter</span>, [<span class="type">FromQuery</span>] <span class="reserved">int</span>? <span class="variable">value</span>) =&gt; <span class="variable">counter</span>.Count * (<span class="variable">value</span> ?? 1));

<span class="variable">app</span>.<span class="method">Run</span>();

<span class="comment">// テンプレに1クラス追加。上記 DI で渡すデモ用の型。</span>
<span class="reserved">class</span> <span class="type">Counter</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> _count;
    <span class="reserved">public</span> <span class="reserved">int</span> Count { <span class="reserved">get</span> =&gt; _count++; }
}
</code></pre>
<h2><a id="lambda-default">ラムダ式のオプション引数(既定値)と params 引数</a></h2>
<h5 class="version version12">Ver. 12</h5>
<p>C# 12 でラムダ式の引数に<a href="https://ufcpp.net/study/csharp/sp4_optional.html#optional">オプション引数</a>にできる(既定値を与えられる)ようになりました。
また、<a href="https://ufcpp.net/study/csharp/sp_params.html">params 引数</a>も使えるようになりました。</p>
<pre class="source" title="ラムダ式の引数の既定値と params 引数">
<span class="comment">// オプション引数(既定値値指定)。</span>
<span class="reserved">var</span> <span class="variable">f1</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="variable local">x</span> <span class="operator">=</span> <span class="number">1</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;

<span class="comment">// params 引数。</span>
<span class="reserved">var</span> <span class="variable">f2</span> <span class="operator">=</span> (<span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;

<span class="comment">// 混在も OK。</span>
<span class="reserved">var</span> <span class="variable">f3</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="variable local">x</span> <span class="operator">=</span> <span class="number">1</span>, <span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;
</pre>
<p>前節の<a href="https://ufcpp.net/study/csharp/functional/fun_localfunctions/#lambda-csharp10">戻り値の型の指定や属性付与</a>と同様、
<a href="https://ufcpp.net/study/csharp/sp_delegate.html#natural-type">デリゲートの自然な型</a>との併用で使ったり、
リフレクションを使って情報を取得するために使います。</p>
<p>自然な型決定(要するに <code>var</code> への代入)した場合、
匿名デリゲート型が生成されて、既定値や params の情報が残ります。
例えば <code>(int x = 1) =&gt; x</code> であれば <code>delegate int F(int x = 1)</code> 相当の匿名デリゲート型が生成されます。</p>
<pre class="source" title="既定値、params の情報が残る例">
<span class="comment">// 引数にデフォルト値指定。</span>
<span class="comment">// delegate int &lt;anonymous&gt;(int x = 1); みたいな匿名デリゲート型になる。</span>
<span class="reserved">var</span> <span class="variable">f1</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="variable local">x</span> <span class="operator">=</span> <span class="number">1</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;

<span class="variable">f1</span>(); <span class="comment">// f1(1) と同じ。</span>

<span class="comment">// params 引数。</span>
<span class="comment">// delegate int &lt;anonymous&gt;(params int[] x); みたいな匿名デリゲート型になる。</span>
<span class="reserved">var</span> <span class="variable">f2</span> <span class="operator">=</span> (<span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;

<span class="variable">f2</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>); <span class="comment">// f2(new int[] { 1, 2, 3 }) と同じ。</span>
</pre>
<p>一方で、既定値違い、params 違いのデリゲート型への代入もできてしまいます。
この場合、既定値などの情報は消えます。
(ちょっと罠なので、一応、警告はしてくれます。)</p>
<pre class="source" title="既定値違い、params 違いのデリゲート型への代入">
<span class="comment">// 既定値の情報がないデリゲート型に代入。</span>
<span class="type">Action</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">f1</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="warning" title="CS9099"><span class="variable local">x</span></span> <span class="operator">=</span> <span class="number">1</span>) <span class="operator">=&gt;</span> { };

<span class="variable"><span class="error" title="CS7036">f1</span></span>(); <span class="comment">// エラー。 f1(1) と書かないとダメ。</span>

<span class="comment">// params の情報がないデリゲート型に代入。</span>
<span class="type">Action</span>&lt;<span class="reserved">int</span>[]&gt; <span class="variable">f2</span> <span class="operator">=</span> (<span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable local"><span class="warning" title="CS9100">x</span></span>) <span class="operator">=&gt;</span> { };

<span class="variable"><span class="error" title="CS1593">f2</span></span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>); <span class="comment">// エラー。 f2(new int[] { 1, 2, 3 }) と書かないとダメ。</span>
</pre>
<p>この点についてもう少し踏み込んで注意すると、
ラムダ式の側とデリゲート型の側で異なる既定値を与えたとき、
リフレクションで値を取るときに変なことが起きたりもします。
<code>Delegate.Method</code> で取る情報(ラムダ式側)と、<code>Type.GetMethod</code> で取る情報(デリゲート型型)が食い違います。</p>
<pre class="source" title="異なる既定値が取れちゃう例">
<span class="reserved">using</span> System<span class="operator">.</span>Reflection;

<span class="comment">// ラムダ式としては既定値 2。</span>
<span class="comment">// ちゃんと警告にはなるものの、無視してしまうと…</span>
<span class="type">A</span> <span class="variable">a</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="variable local"><span class="warning" title="CS9099">x</span></span> <span class="operator">=</span> <span class="number">2</span>) <span class="operator">=&gt;</span> { };

<span class="type">MethodInfo</span> <span class="variable">m1</span> <span class="operator">=</span> <span class="variable">a</span><span class="operator">.</span><span class="property">Method</span>; <span class="comment">// ラムダ式側の情報が取れる。</span>
<span class="type">MethodInfo</span> <span class="variable">m2</span> <span class="operator">=</span> <span class="variable">a</span><span class="operator">.</span><span class="method">GetType</span>()<span class="operator">.</span><span class="method">GetMethod</span>(<span class="string">&quot;Invoke&quot;</span>)<span class="operator">!</span>; <span class="comment">// デリゲート型側の情報が取れる。</span>

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">m1</span><span class="operator">.</span><span class="method">GetParameters</span>()[<span class="number">0</span>]<span class="operator">.</span><span class="property">DefaultValue</span>); <span class="comment">// 2</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">m2</span><span class="operator">.</span><span class="method">GetParameters</span>()[<span class="number">0</span>]<span class="operator">.</span><span class="property">DefaultValue</span>); <span class="comment">// 1</span>

<span class="comment">// デリゲート型としては既定値 1。</span>
<span class="reserved">delegate</span> <span class="reserved">void</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">x</span> <span class="operator">=</span> <span class="number">1</span>);
</pre>
<h2><a id="simple-param-with-modifier">修飾子付きの引数の型名省略</a></h2>
<h5 class="version version14">Ver. 14.0</h5>
<p>ラムダ式には導入以来ずっと、「型を推論できる限り、引数の型は省略できる」という仕様があります。
ところが、<code>ref</code> や <code>out</code> などの修飾子が必須の引数の場合、C# 13 までは型名省略できませんでした。
これが C# 14 で改善されました。</p>
<p>例えば、<code>int</code> などをはじめ多くの型が以下のような <code>TryParse</code> メソッドを持っています。</p>
<pre class="source" title="int などが持っている TryParse メソッド">
<span class="reserved">using</span> System<span class="operator">.</span>Diagnostics<span class="operator">.</span>CodeAnalysis;

<span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type struct">Int32</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="method"><span class="static">TryParse</span></span>([<span class="type">NotNullWhen</span>(<span class="reserved">true</span>)] <span class="reserved">string</span><span class="operator">?</span> <span class="variable local">s</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable local">result</span>)
    {
        <span class="comment">// ...</span>
    }
}
</pre>
<p>以下のように、この類の処理用のデリゲート型があったとして、</p>
<pre class="source" title="int.TryParse などを受け取るためのデリゲート型">
<span class="reserved">delegate</span> <span class="reserved">bool</span> <span class="type">TryParse</span>&lt;<span class="type param">T</span>&gt;(<span class="reserved">string</span> <span class="variable local">text</span>, <span class="reserved">out</span> <span class="type param">T</span> <span class="variable local">result</span>);
</pre>
<p>C# 13 までは以下のように書くことができませんでした。</p>
<pre class="source" title="C# 13 までは (out x) みたいな型名省略ができない">
<span class="comment">// C# 13 までは書けなかった。</span>
<span class="type">TryParse</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">m</span> <span class="operator">=</span> (<span class="variable local">text</span>, <span class="error" title="CS9260"><span class="reserved">out</span> <span class="variable local">result</span></span>) <span class="operator">=&gt;</span> { <span class="variable local">result</span> <span class="operator">=</span> <span class="number">0</span>; <span class="control">return</span> <span class="reserved">true</span>; };

<span class="comment">// out や ref がないならこう書けるのに…</span>
<span class="type">Func</span>&lt;<span class="reserved">string</span>, <span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span> <span class="operator">=</span> (<span class="variable local">text</span>, <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;

<span class="comment">// out が付いた瞬間、型名が必須だった(これなら C# 13 でもコンパイル可能)。</span>
<span class="type">TryParse</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">m13</span> <span class="operator">=</span> (<span class="reserved">string</span> <span class="variable local">text</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable local">result</span>) <span class="operator">=&gt;</span> { <span class="variable local">result</span> <span class="operator">=</span> <span class="number">0</span>; <span class="control">return</span> <span class="reserved">true</span>; };

<span class="reserved">delegate</span> <span class="reserved">bool</span> <span class="type">TryParse</span>&lt;<span class="type param">T</span>&gt;(<span class="reserved">string</span> <span class="variable local">text</span>, <span class="reserved">out</span> <span class="type param">T</span> <span class="variable local">result</span>);
</pre>
<p>これが C# 14 では認められます。</p>
<pre class="source" title="C# 14 で (out x) の類が可能に">
<span class="comment">// C# 14 で可能に。</span>
<span class="type">TryParse</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">m</span> <span class="operator">=</span> (<span class="variable local">text</span>, <em><span class="reserved">out</span> <span class="variable local">result</span></em>) <span class="operator">=&gt;</span> { <span class="variable local">result</span> <span class="operator">=</span> <span class="number">0</span>; <span class="control">return</span> <span class="reserved">true</span>; };
</pre>
<p>対象となる修飾子は <code>out</code>、<code>ref</code>、<code>in</code>、<code>ref readonly</code>、<code>scoped</code> などです。</p>
<pre class="source" title="">
<span class="type">M</span> <span class="variable">m</span> <span class="operator">=</span> (<span class="reserved">in</span> <span class="variable local">a</span>, <span class="reserved">ref</span> <span class="variable local">b</span>, <span class="reserved">out</span> <span class="variable local">c</span>, <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="variable local">d</span>, <span class="reserved">scoped</span> <span class="variable local">e</span>) <span class="operator">=&gt;</span> <span class="variable local">c</span> <span class="operator">=</span> <span class="number">0</span>;

<span class="comment">// C# 13 以前だと以下のように書く必要あり。</span>
<span class="type">M</span> <span class="variable">m13</span> <span class="operator">=</span> (<span class="reserved">in</span> <span class="reserved">int</span> <span class="variable local">a</span>, <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">b</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable local">c</span>, <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="variable local">d</span>, <span class="reserved">scoped</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">e</span>) <span class="operator">=&gt;</span> <span class="variable local">c</span> <span class="operator">=</span> <span class="number">0</span>;

<span class="reserved">delegate</span> <span class="reserved">void</span> <span class="type">M</span>(<span class="reserved">in</span> <span class="reserved">int</span> <span class="variable local">a</span>, <span class="reserved">ref</span> <span class="reserved">int</span> <span class="variable local">b</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable local">c</span>, <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="variable local">d</span>, <span class="reserved">scoped</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">e</span>);
</pre>
<p>ちなみに、これが認められているのは引数リストを <code>()</code> でくくっている場合だけです。
ラムダ式は、引数が1つだけの時は <code>x =&gt; { }</code> というように引数リストの <code>()</code> も省略できるわけですが、
この場合は <code>ref x =&gt; { }</code> みたいな書き方はできません(というか元々、<code>int x =&gt; { }</code> みたいな型名指定も許されていません)。</p>
<pre class="source" title="修飾子をつけたい場合、() は必須">
<span class="comment">// 修飾子をつけたい場合、() は必須。</span>
<span class="type">In</span> <span class="variable">m1</span> <span class="operator">=</span> (<span class="reserved">in</span> <span class="reserved">int</span> <span class="variable local">a</span>) <span class="operator">=&gt;</span> { };
<span class="type">In</span> <span class="variable">m2</span> <span class="operator">=</span> (<span class="reserved">in</span> <span class="variable local">a</span>) <span class="operator">=&gt;</span> { };

<span class="comment">// () 省略不可でエラーに。</span>
<span class="type">In</span> <span class="variable">m3</span> <span class="operator">=</span> <span class="error" title="CS1003"><span class="error" title="CS1525"><span class="reserved">in</span></span></span> <span class="reserved">int</span> a <span class="operator">=&gt;</span> { <span class="error" title="CS1022"><span class="error" title="CS1002">}</span></span>;
<span class="type">In</span> <span class="variable">m4</span> <span class="operator">=</span> <span class="reserved"><span class="error" title="CS1525"><span class="error" title="CS1003">in</span></span></span> a <span class="operator">=&gt;</span> { <span class="error" title="CS1022"><span class="error" title="CS1002">}</span></span>;

<span class="comment">// ちなみに、in を抜こうとすると型が合わなくてエラーになる。</span>
<span class="type">In</span> <span class="variable">m5</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="error" title="CS1676"><span class="variable local">a</span></span>) <span class="operator">=&gt;</span> { };
<span class="type">In</span> <span class="variable">m6</span> <span class="operator">=</span> (<span class="variable local"><span class="error" title="CS1676">a</span></span>) <span class="operator">=&gt;</span> { };
<span class="type">In</span> <span class="variable">m7</span> <span class="operator">=</span> <span class="variable local"><span class="error" title="CS1676">a</span></span> <span class="operator">=&gt;</span> { };

<span class="comment">// 参考: 修飾子がない場合:</span>
<span class="type">Value</span> <span class="variable">v1</span> <span class="operator">=</span> <span class="variable local">a</span> <span class="operator">=&gt;</span> { };
<span class="type">Value</span> <span class="variable">v2</span> <span class="operator">=</span> (<span class="variable local">a</span>) <span class="operator">=&gt;</span> { };
<span class="type">Value</span> <span class="variable">v3</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="variable local">a</span>) <span class="operator">=&gt;</span> { };
<span class="comment">// Value v4 = int a =&gt; { }; はこっちでもダメ。コンパイル エラーに。</span>

<span class="reserved">delegate</span> <span class="reserved">void</span> <span class="type">Value</span>(<span class="reserved">int</span> <span class="variable local">a</span>);
<span class="reserved">delegate</span> <span class="reserved">void</span> <span class="type">In</span>(<span class="reserved">in</span> <span class="reserved">int</span> <span class="variable local">a</span>);
</pre> ]]></description>
				<pubDate>Sat, 29 Jul 2023 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 12.0 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver12/</link>
				<description><![CDATA[ <div class="version version12">Ver. 12.0</div>
<table>
<tr>
<th>リリース時期</th>
<td>2023/11</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>.NET 8.0</li>
</td>
</tr>
</table>
<h2><a id="collection-expression">コレクション式</a></h2>
<p><code>[]</code> 記号を使って配列などの初期化ができるようになりました。
配列だけではなく、コレクション(<code>List&lt;T&gt;</code> 型など)、<code>Span&lt;T&gt;</code> なども全く同じ書き方で初期化できます。
これをコレクション式(collection expression)と言います。</p>
<pre class="source" title="コレクション式">
<span class="reserved">using</span> System<span class="operator">.</span>Collections<span class="operator">.</span>Immutable;

<span class="reserved">int</span>[] <span class="variable">array</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">list</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">ros</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
<span class="type struct">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> <span class="operator">=</span> <em>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</em>;
</pre>
<p>また、コレクション式中では、<code>..</code> を使うことで「別のコレクションの中身の展開」ができます。
これを スプレッド (spread)演算子と言います。</p>
<pre class="source" title="">
<span class="reserved">int</span>[] <span class="variable">array1</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<span class="reserved">int</span>[] <span class="variable">array2</span> <span class="operator">=</span> [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];

<span class="comment">// 0, 1, 2, 3, 4, 5, 6, 7</span>
<span class="reserved">int</span>[] <span class="variable">combined</span> <span class="operator">=</span> [<span class="number">0</span>, <em>..</em><span class="variable">array1</span>, <em>..</em><span class="variable">array2</span>, <span class="number">7</span>];
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/datatype/collection-expression/">コレクション式</a>」で説明します。</p>
<h2><a id="primary-constructor">プライマリ コンストラクター</a></h2>
<p>通常のクラス、構造体に対してプライマリ コンストラクターが使えるようになりました。</p>
<pre class="source" title="">
<span class="reserved">class</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable local">x</span>)
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">X</span> { <span class="reserved">get</span>; } <span class="operator">=</span> <span class="variable local">x</span>;
}
</pre>
<p>レコード型の方を先に実装してしまったがために混乱があるんですが、
通常クラス・構造体の場合はプライマリ コンストラクター引数からプロパティを自動生成する機能はありません。</p>
<p>また、これに伴い、<code>class C;</code> というように、メンバーを1つも持たないでいい場合に <code>{}</code> を書く必要がなくなりました。</p>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oo_construct.html#primary-constructor">プライマリ コンストラクター</a>」で説明します。</p>
<h2><a id="using-any-type">using エイリアスに任意の型を書けるように</a></h2>
<p>C# 11 ではエラーになっていた以下のようなコードをコンパイルできるようになりました。</p>
<pre class="source" title="C# 12 から書ける using エイリアス">
<span class="reserved">using</span> <span class="type struct">Primitive</span> <span class="operator">=</span> <span class="reserved">int</span>;
<span class="reserved">using</span> <span class="type">Array</span> <span class="operator">=</span> <span class="reserved">int</span>[];
<span class="reserved">using</span> <span class="type struct">Nullable</span> <span class="operator">=</span> <span class="reserved">int</span><span class="operator">?</span>;
<span class="reserved">using</span> <span class="type struct">Tuple</span> <span class="operator">=</span> (<span class="reserved">int</span>, <span class="reserved">int</span>);
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_namespace.html#using-any-type">任意の型に対する using エイリアス</a>」で説明します。</p>
<h2><a id="lambda-default">ラムダ式のデフォルト引数</a></h2>
<p>ラムダ式の引数に<a href="https://ufcpp.net/study/csharp/sp4_optional.html#optional">オプション引数</a>にできる(既定値を与えられる)ようになりました。
また、<a href="https://ufcpp.net/study/csharp/sp_params.html">params 引数</a>も使えるようになりました。</p>
<pre class="source" title="ラムダ式の引数の既定値と params 引数">
<span class="comment">// オプション引数(既定値値指定)。</span>
<span class="reserved">var</span> <span class="variable">f1</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="variable local">x</span> <span class="operator">=</span> <span class="number">1</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;

<span class="comment">// params 引数。</span>
<span class="reserved">var</span> <span class="variable">f2</span> <span class="operator">=</span> (<span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;

<span class="comment">// 混在も OK。</span>
<span class="reserved">var</span> <span class="variable">f3</span> <span class="operator">=</span> (<span class="reserved">int</span> <span class="variable local">x</span> <span class="operator">=</span> <span class="number">1</span>, <span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="number">0</span>;
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/functional/fun_localfunctions/#lambda-default">ラムダ式のオプション引数(既定値)と params 引数</a>」で説明します。</p>
<h2><a id="ref-readonly-param">ref readonly 引数</a></h2>
<p>ref 引数、in 引数の亜種として、
「書き換えはしないけども、右辺値は受け付けたくない」ということを表す ref readonly 引数というものを導入しました。</p>
<pre class="source" title="ref readonly 引数">
<span class="comment">// in 引数の代わりに ref readonly 引数。</span>
<span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="variable local">x</span>) { }

<span class="method">m</span>(<span class="warning" title="CS9193"><span class="number">10</span></span>); <span class="comment">// リテラルは警告に。</span>

<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="number">1</span>;
<span class="reserved">var</span> <span class="variable">b</span> <span class="operator">=</span> <span class="number">2</span>;
<span class="method">m</span>(<span class="warning" title="CS9193"><span class="variable">a</span> <span class="operator">+</span> <span class="variable">b</span></span>); <span class="comment">// 式も警告に。</span>

<span class="comment">// in や ref を付けないのも警告。</span>
<span class="method">m</span>(<span class="variable"><span class="warning" title="CS9192">a</span></span>);

<span class="comment">// in を付けると警告が出ない。</span>
<span class="method">m</span>(<span class="reserved">in</span> <span class="variable">a</span>);

<span class="comment">// in 引数と違って、ref 修飾でも OK。</span>
<span class="method">m</span>(<span class="reserved">ref</span> <span class="variable">a</span>);
</pre>
<p>ちなみに、呼び出し側の書き方が変わる以外に差はなく、コンパイル結果の挙動は in 引数と全く同じです。
呼び出し側の差は以下の通りです。</p>
<table>
<thead>
<tr>
	<th>呼び方</th>
	<th>in</th>
	<th>ref readonly</th>
</tr>
</thead>
<tbody>
<tr>
	<td><code>m(ref x)</code></td>
	<td>警告</td>
	<td>OK</td>
</tr>
<tr>
	<td><code>m(in x)</code></td>
	<td>OK</td>
	<td>OK</td>
</tr>
<tr>
	<td><code>m(x)</code>, <code>m(x + y)</code>, <code>m(123)</code></td>
	<td>OK</td>
	<td>警告</td>
</tr>
</tbody>
</table>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_ref.html#ref-readonly-param">ref readonly 引数</a>」で説明します。</p>
<h2><a id="other">その他</h2>
<h3><a id="inline-array">InlineArray</a></h3>
<p>.NET 8 で、<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.runtime.compilerservices.inlinearrayattribute"><code>InlineArray</code> 属性</a> (<code>System.Runtime.CompilerServices</code> 名前空間) というものが入って、「値型の固定長配列」みたいなものを作れるようになりました。</p>
<pre class="source" title="InlineArray 属性">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;

<span class="comment">// この属性を付けると、 .NET ランタイムが特別扱いして、構造体のサイズを拡大する。</span>
<span class="comment">// (コンストラクター引数で Length 指定。)</span>
[<span class="type">InlineArray</span>(<span class="number">3</span>)]
<span class="reserved">struct</span> <span class="type struct">FixedBuffer</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">private</span> <span class="type param">T</span> <span class="field">_value</span>;
}
</pre>
<p>基本的には .NET ランタイム側の機能ですが、
いくつか、C# 側にもこの <code>InlineArray</code> 向けの特殊対応が入っています。</p>
<pre class="source" title="InlineArray 型利用側の特殊対応">
<span class="type struct">FixedBuffer</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">buffer</span> <span class="operator">=</span> <span class="reserved">new</span>();

<span class="comment">// InlineArray に対して直接インデクサーを書ける。</span>
<span class="variable">buffer</span>[<span class="number">0</span>] <span class="operator">=</span> <span class="string">&quot;zero&quot;</span>;
<span class="variable">buffer</span>[<span class="number">1</span>] <span class="operator">=</span> <span class="string">&quot;one&quot;</span>;

<span class="comment">// Span/ReadOnlySpan に暗黙的に変換できる。</span>
<span class="type struct">Span</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <span class="variable">buffer</span>;
<span class="variable">span</span>[<span class="number">2</span>] <span class="operator">=</span> <span class="string">&quot;two&quot;</span>;

<span class="comment">// foreach で列挙できる。</span>
<span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">buffer</span>)
{
    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/datatype/inline-array/">[雑記] InlineArray</a>」で説明します。</p>
<h3><a id="nameof-instance-menbers">nameof の微修正</h3>
<p><a href="https://ufcpp.net/study/csharp/st_string.html#nameof-operator"><code>nameof</code> 演算子</a>にちょっとした修正が入りました。</p>
<p>C# 11 以前だと、以下の例の最後の行のように、
静的メンバー内から「インスタンス メンバーのインスタンス メンバー」みたいな名前の参照ができなかったようです。</p>
<pre class="source" title="C# 11 まではエラーになっていたコードの例">
<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span><span class="operator">?</span> <span class="property">Instance</span> { <span class="reserved">get</span>; }

    <span class="comment">// これは元から行けた。</span>
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="method">InstanceM</span>() <span class="operator">=&gt;</span> <span class="reserved">nameof</span>(<span class="property">Instance</span><span class="operator">.</span><span class="property">Length</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">string</span> <span class="static"><span class="method">StaticM1</span></span>() <span class="operator">=&gt;</span> <span class="reserved">nameof</span>(<span class="reserved">string</span><span class="operator">.</span><span class="property">Length</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">string</span> <span class="method"><span class="static">StaticM2</span></span>() <span class="operator">=&gt;</span> <span class="reserved">nameof</span>(<span class="property">Instance</span>);

    <span class="comment">// これが今までダメだったらしい。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">string</span> <span class="static"><span class="method">StaticM</span></span>() <span class="operator">=&gt;</span> <span class="reserved">nameof</span>(<span class="property"><span class="error" title="CS0120">Instance</span></span><span class="operator">.</span><span class="property">Length</span>);
}
</pre>
<p>これが、C# 12 ではコンパイルできるようになりました。</p>
<p>正直、バグ修正扱い(最新コンパイラーを使うと C# 11 以下でもコンパイルが通るようになる)でもいいレベルだとは思いますが、一応は C# 12 以上限定です。</p>
 ]]></description>
				<pubDate>Wed, 21 Jun 2023 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] 明確な代入ルール</title>
				<link>http://www.ufcpp.net/study/csharp/start/definiteassignment/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<p>C# には「明確な代入(definite assignment)ルール」と呼ばれる、未初期化変数を避ける仕組みがあります。</p>
<h2><a id="undefined">未定義動作問題</a></h2>
<p>大昔のプログラミング言語では、
変数に対して誰も何の値も代入していないことで、不定な値が返ってくるということがありました。
不定な値が得られてしまうことで、<a href="https://ufcpp.net/study/csharp/rm_default.html#uninitialized">未定義な動作</a>になります。
特にまずいのは、「テストの時にはたまたまうまくいっていた(うまくいく値が返っていた)けども、本番でだけ失敗する」みたいな状況です。</p>
<p>この未定義動作はかなりまずい状態なので、
最近のプログラミング言語では大体これを防いでいます。
大体以下のいずれかの手段を取ります。</p>
<ul>
<li>既定値: ある決まった値(<a href="https://ufcpp.net/study/csharp/rm_default.html">C# の場合は 0 や null</a>)を自動的に代入する</li>
<li>明確な代入: 開発者が明示的な代入をすることを義務付ける</li>
</ul>
<p>C# では、<a href="https://ufcpp.net/study/csharp/oo_class.html">クラス</a>のフィールドや<a href="https://ufcpp.net/study/csharp/st_array.html">配列</a>の中身については前者の「既定値による初期化」を行っていて、ローカル変数については後者の「代入の義務付け」を行っています。
この「代入の義務付け」が「明確な代入ルール」です。</p>
<h2><a id="rule">ルールの例</a></h2>
<p>まずわかりやすい例から見ていきましょう。
分岐も何もなければ簡単です。以下のようなコードはコンパイル エラーになります。</p>
<pre class="source" title="未初期化変数を使おうとしてエラーになる例">
<span class="reserved">int</span> <span class="variable">x</span>;

<span class="comment">// x に何も代入しないまま値を取り出そうとした。</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="error" title="CS0165"><span class="variable">x</span></span>);
</pre>
<p>解決策は当然「ちゃんと代入すること」(definitely assigned)なんですが、
変数の宣言と同時に初期値を与えるのでもいいですし、
後からの代入でも構いません。</p>
<pre class="source" title="ちゃんと代入">
<span class="comment">// 変数宣言と同時に初期値を与える。</span>
<span class="reserved">int</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>;

<span class="reserved">int</span> <span class="variable">y</span>;

<span class="comment">// ここで y を使うとまずいけども…</span>

<span class="variable">y</span> <span class="operator">=</span> <span class="number">2</span>;

<span class="comment">// 値の代入後なら大丈夫。</span>

<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">x</span>);
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">y</span>);
</pre>
<p>C# では、この明確な代入を判定する際、分岐も見てくれます。
全ての分岐先でちゃんと代入していれば OK です。</p>
<pre class="source" title="if-else 両方で代入">
<span class="comment">// 大丈夫な例: if-else 両方で代入。</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">m</span></span>(<span class="reserved">bool</span> <span class="variable local">condition</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span>;

    <span class="control">if</span> (<span class="variable local">condition</span>)
    {
        <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>;
    }
    <span class="control">else</span>
    {
        <span class="variable">x</span> <span class="operator">=</span> <span class="operator">-</span><span class="number">1</span>;
    }

    <span class="comment">// 大丈夫。</span>
    <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);
}
</pre>
<pre class="source" title="if でだけ代入">
<span class="comment">// ダメな例: if でだけ代入。</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">m</span></span>(<span class="reserved">bool</span> <span class="variable local">condition</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span>;

    <span class="control">if</span> (<span class="variable local">condition</span>)
    {
        <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>;
    }

    <span class="comment">// エラー。</span>
    <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable"><span class="error" title="CS0165">x</span></span>);
}
</pre>
<p><code>if</code> だけではなく、<code>switch</code> でも判定してくれます。</p>
<pre class="source" title="case が全ての値を網羅">
<span class="comment">// 大丈夫な例: case が全ての値を網羅しているなら大丈夫。</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">m</span></span>(<span class="reserved">byte</span> <span class="variable local">condition</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span>;

    <span class="control">switch</span> (<span class="variable local">condition</span>)
    {
        <span class="control">case</span> <span class="number">0</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="operator">-</span><span class="number">1</span>; <span class="control">break</span>;
        <span class="control">case</span> <span class="number">1</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>; <span class="control">break</span>;
        <span class="control">default</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="number">0</span>; <span class="control">break</span>; <span class="comment">// default は必須。</span>
    }

    <span class="comment">// 大丈夫。</span>
    <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">x</span>);
}
</pre>
<pre class="source" title="case に漏れ">
<span class="comment">// ダメな例: case に漏れがあるとダメ。</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">m</span></span>(<span class="reserved">byte</span> <span class="variable local">condition</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span>;

    <span class="control">switch</span> (<span class="variable local">condition</span>)
    {
        <span class="control">case</span> <span class="number">0</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="operator">-</span><span class="number">1</span>; <span class="control">break</span>;
        <span class="control">case</span> <span class="number">1</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>; <span class="control">break</span>;
        <span class="control">case</span> <span class="operator">&lt;</span> <span class="number">255</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>; <span class="control">break</span>;
        <span class="comment">// この条件だと、condition が 255 の時が漏れてる。</span>
    }

    <span class="comment">// エラー。</span>
    <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="error" title="CS0165"><span class="variable">x</span></span>);
}
</pre>
<pre class="source" title="結構ちゃんと網羅性をチェックしてる">
<span class="comment">// 大丈夫な例: 結構ちゃんと網羅性をチェックしてる。</span>
<span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">m</span></span>(<span class="reserved">sbyte</span> <span class="variable local">condition</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span>;

    <span class="control">switch</span> (<span class="variable local">condition</span>)
    {
        <span class="control">case</span> <span class="operator">&lt;</span> <span class="number">0</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="operator">-</span><span class="number">1</span>; <span class="control">break</span>;
        <span class="control">case</span> <span class="number">0</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="number">0</span>; <span class="control">break</span>;
        <span class="control">case</span> <span class="operator">&gt;</span> <span class="number">0</span>: <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>; <span class="control">break</span>;
        <span class="comment">// 負、0、正 で全ての値を網羅。</span>
    }

    <span class="comment">// 大丈夫。</span>
    <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">x</span>);
}
</pre>
<p>ループも結構ちゃんと判定します。
例えば、<code>while (false)</code> や、<code>break</code> なども追ってくれます。</p>
<pre class="source" title="通らないループ">
<span class="comment">// ダメな例: 通らないループ。</span>
<span class="reserved">int</span> <span class="variable">x</span>;

<span class="control">while</span> (<span class="reserved">false</span>)
{
    <span class="comment">// ここを通らないこともちゃんと判定される。</span>
    <span class="variable"><span class="warning" title="CS0162">x</span></span> <span class="operator">=</span> <span class="number">1</span>;
}

<span class="comment">// エラー。</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable"><span class="error" title="CS0165">x</span></span>);
</pre>
<pre class="source" title="早すぎる break">
<span class="comment">// ダメな例: 早すぎる break。</span>
<span class="reserved">int</span> <span class="variable">x</span>;

<span class="control">while</span> (<span class="reserved">true</span>)
{
    <span class="control">break</span>;
    <span class="comment">// ここを通らないこともちゃんと判定される。</span>
    <span class="variable"><span class="warning" title="CS0162">x</span></span> <span class="operator">=</span> <span class="number">1</span>;
}

<span class="comment">// エラー。</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="error" title="CS0165"><span class="variable">x</span></span>);
</pre>
<pre class="source" title="break 前に代入">
<span class="comment">// 大丈夫な例: break 前に代入。</span>
<span class="reserved">int</span> <span class="variable">x</span>;

<span class="control">while</span> (<span class="reserved">true</span>)
{
    <span class="comment">// これならここを通る。</span>
    <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span>;
    <span class="control">break</span>;
}

<span class="comment">// 大丈夫。</span>
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);</pre>
<pre class="source" title="永久ループ">
<span class="comment">// 大丈夫な例: 永久ループの下。</span>
<span class="reserved">int</span> <span class="variable">x</span>;

<span class="control">while</span> (<span class="reserved">true</span>)
{
}

<span class="comment">// 永久ループの下には来ないので、この行自体呼ばれない。</span>
<span class="comment">// その場合、「代入してない」エラーにはならない。</span>
<span class="comment">// 別途「絶対に通らない」警告は出る。</span>
<span class="type"><span class="static"><span class="warning" title="CS0162">Console</span></span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);
</pre>
<h2><a id="improved-rule">ルールの改善</a></h2>
<h5 class="version version10">Ver. 10</h5>
<p>長らく、<code>?.</code> や <code>??</code> が絡んだ時の明確な代入の判定はあまり賢くありませんでした。
明確に代入されているケースでも、判定漏れでコンパイル エラーになっていました。
(厳しめにエラーになっているので、未定義動作問題は起きません。不便なだけです。)</p>
<p>それが C# 10 で改善されました。
例えば以下のコードは C# 10 以降でだけコンパイルできます。</p>
<pre class="source" title="?. == true">
<span class="comment">// C# 10 から大丈夫な例: ?. == true。</span>
<span class="reserved">void</span> <span class="method">m</span>(<span class="type">Dictionary</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">d</span>)
{
    <span class="control">if</span> (<span class="variable local">d</span><span class="operator">?</span><span class="operator">.</span><span class="method">TryGetValue</span>(<span class="number">123</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">x</span>) <span class="operator">==</span> <span class="reserved">true</span>)
    {
        <span class="comment">// C# 10 から大丈夫になった。</span>
        <span class="comment">// (前までは ?. からの == true は判定漏れでエラー。)</span>
        <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);
    }
}
</pre>
<pre class="source" title="?. ??">
<span class="comment">// C# 10 から大丈夫な例: ?. ??。</span>
<span class="reserved">void</span> <span class="method">m</span>(<span class="type">Dictionary</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">d</span>)
{
    <span class="control">if</span> (<span class="variable local">d</span><span class="operator">?</span><span class="operator">.</span><span class="method">TryGetValue</span>(<span class="number">123</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">x</span>) <span class="operator">??</span> <span class="reserved">false</span>)
    {
        <span class="comment">// C# 10 から大丈夫になった。</span>
        <span class="comment">// (前までは ?. からの ?? も同様。)</span>
        <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);
    }
}
</pre> ]]></description>
				<pubDate>Sat, 15 Apr 2023 16:19:17 +0900</pubDate>
			</item>
			<item>
				<title>関数ポインター</title>
				<link>http://www.ufcpp.net/study/csharp/interop/functionpointer/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<h5 class="version version9">Ver. 9</h5>
<p>関数ポインターとは、メモリ上でメソッドなどの命令列が入ってるアドレスを指すポインターで、
「そのアドレスにジャンプすることでメソッド呼び出しが実現されている」みたいなものです。</p>
<p>.NET の内部的にはこれまでも関数ポインターがあったんですが、
それを C# から効率的に呼ぶ手段がありませんでした。
これに対して、C# 9 では <code>delegate*</code> という記法で関数ポインターを扱えるようになりました。
(<a href="https://ufcpp.net/study/csharp/sp_unsafe.html#unsafe">unsafe コンテキスト</a>内限定で使えます。)</p>
<h2><a id="since1.0">以前からある関数ポインター</a></h2>
<p>関数ポインター自体は .NET には昔からあって、
例えば、関数ポインターの値を <code>IntPtr</code> (<code>nint</code>) で取得する手段は .NET Framework 1.0 (初代。2002年リリース)の頃からありました。</p>
<p>ただ、関数ポインターを使ったメソッド呼び出しの側は、C# には関連機能が一切なく、
一度デリゲート化するひと手間が必要でした。</p>
<pre class="source" title="GetFunctionPointer で関数ポインター取得">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="reserved">var</span> <span class="variable">m</span> <span class="operator">=</span> <span class="reserved">typeof</span>(<span class="type">A</span>)<span class="operator">.</span><span class="method">GetMethod</span>(<span class="string">&quot;M&quot;</span>)<span class="operator">!</span>;

<span class="comment">// GetFunctionPointer で、メソッド M の関数ポインターが取れる。</span>
<span class="reserved">nint</span> <span class="variable">ptr</span> <span class="operator">=</span> <span class="variable">m</span><span class="operator">.</span><span class="property">MethodHandle</span><span class="operator">.</span><span class="method">GetFunctionPointer</span>();

<span class="comment">// かつてはこれを直接呼ぶ手段はなくて、デリゲート化のひと手間が必要だった。</span>
<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="type"><span class="static">Marshal</span></span><span class="operator">.</span><span class="method"><span class="static">GetDelegateForFunctionPointer</span></span>&lt;<span class="type">Action</span>&gt;(<span class="variable">ptr</span>);

<span class="comment">// これで A.M を間接的に呼べる。</span>
<span class="variable">a</span>();

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>() <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;A.M&quot;</span>);
}
</pre>
<h2><a id="pinvoke">ネイティブ コード呼び出し</a></h2>
<p>まあ、C# で完結している分には役に立ちません。
C# で書いたメソッドを C# のデリゲートで受け取るんなら、
直接代入するだけでデリゲート化できます。
前節の例も、単に以下のように書けます。</p>
<pre class="source" title="C# で完結している分には関数ポインターの出番なし">
<span class="comment">// C# で書いたメソッドを C# のデリゲートで受け取るんなら、単に代入でできるわけで、</span>
<span class="comment">// 関数ポインターを介する意味は全くなく。</span>
<span class="type">Action</span> <span class="variable">a</span> <span class="operator">=</span> <span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>;

<span class="comment">// これで A.M を間接的に呼べる。</span>
<span class="variable">a</span>();

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>() <span class="operator">=&gt;</span> <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;A.M&quot;</span>);
}
</pre>
<p>実際に関数ポインターを使う場面があるのは<a href="https://ufcpp.net/study/csharp/sp_pinvoke.html">ネイティブ コード呼び出し</a>になります。</p>
<p>ネイティブ コード呼び出しも、<code>DllImport</code> 属性(.NET 7 以降であれば <code>LibraryImport</code> 属性)を使えば普通の、安全な C# コードだけで呼び出し可能ではあります。
例えば、<code>LibraryImport</code> 属性を使って kernel32.dll 中の <code>Beep</code> メソッドを呼ぶコードは以下のように書けます。</p>
<pre class="source" title="LibraryImport 属性を使ったネイティブ コード呼び出しの例(ビープ音を鳴らす)">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="comment">// 呼び出し側。</span>
<span class="type">Native</span><span class="operator">.</span><span class="static"><span class="method">Beep</span></span>(<span class="number">440</span>, <span class="number">1000</span>);

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Native</span>
{
    <span class="comment">// こんな感じで属性を付けておけば、 .NET ランタイム内でなんかよろしくやってくれてネイティブ コードを呼べる。</span>
    [<span class="type">LibraryImport</span>(<span class="string">&quot;kernel32.dll&quot;</span>)]
    [<span class="reserved">return</span>: <span class="type">MarshalAs</span>(<span class="type">UnmanagedType</span><span class="operator">.</span>Bool)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">bool</span> <span class="method"><span class="static">Beep</span></span>(<span class="reserved">uint</span> <span class="variable local">frequency</span>, <span class="reserved">uint</span> <span class="variable local">duration</span>);
}
</pre>
<p>というか、かつてはネイティブ コードの関数ポインターを取る手段がありませんでした。
(上記の <code>Native.Beep</code> に対して <code>GetFunctionPointer</code> すると、
取れるのはあくまで「ネイティブ コード呼び出しを内部的によろしくやってくれる C# のメソッド」の関数ポインターになります。)</p>
<h2><a id="NativeLibrary">NativeLibrary クラス</a></h2>
<p>「関数ポインターを取る手段がないから使い道がない」と
「関数ポインターが指す先を呼び出す手段がないから取れてもしょうがない」で卵が先か鶏が先かみたいな話になるんですが、
C# に関数ポインターは必要ありませんでした。</p>
<p>ところが、 .NET Core 3.0 (C# 8.0 と同世代)で、<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.nativelibrary"><code>NativeLibary</code></a> (<code>System.Runtime.InteropServices</code> 名前空間)というクラスが入って、
ネイティブ コードの関数ポインターを取得する手段が提供されるようになりました。</p>
<pre class="source" title="NativeLibrary を使ったネイティブ コード呼び出しの例(ビープ音を鳴らす)">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="comment">// DLL のロード。</span>
<span class="reserved">nint</span> <span class="variable">kernel32</span> <span class="operator">=</span> <span class="static"><span class="type">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">Load</span></span>(<span class="string">&quot;kernel32.dll&quot;</span>);

<span class="comment">// 所望の関数の関数ポインターを取得。</span>
<span class="reserved">nint</span> <span class="variable">p</span> <span class="operator">=</span> <span class="type"><span class="static">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">GetExport</span></span>(<span class="variable">kernel32</span>, <span class="string">&quot;Beep&quot;</span>);

<span class="comment">// ただ、C# 8.0 時点だと呼び出しには一度デリゲート化する必要あり。</span>
<span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="type"><span class="static">Marshal</span></span><span class="operator">.</span><span class="static"><span class="method">GetDelegateForFunctionPointer</span></span>&lt;<span class="type">BeepDelegate</span>&gt;(<span class="variable">p</span>);
<span class="variable">a</span>(<span class="number">440</span>, <span class="number">1000</span>);

<span class="comment">// ちなみに、 NativeLibrary の利点として、DLL のアンロードが可能。</span>
<span class="static"><span class="type">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">Free</span></span>(<span class="variable">kernel32</span>);

<span class="comment">// GetDelegateForFunctionPointer にはジェネリックな型は渡せないらしく、</span>
<span class="comment">// Func&lt;uint, uint, int&gt; が使えないので同じ引数・戻り値のデリゲートを定義。</span>
<span class="reserved">delegate</span> <span class="reserved">int</span> <span class="type">BeepDelegate</span>(<span class="reserved">uint</span> <span class="variable local">frequencey</span>, <span class="reserved">uint</span> <span class="variable local">duration</span>);
</pre>
<p><code>NativeLibary</code> は、
<code>DllImport</code> や <code>LibararyImoprt</code> と比べると煩雑ではありますが、
動的にロード・アンロードしたりといった細やかな制御が可能です。</p>
<p>この例のように、C# 8.0 時点では一度デリゲート化する必要があります。
ただ、このデリゲートを介する部分がペナルティになって、
<code>DllImport</code> よりも低速になっていました。</p>
<h2><a id="function-pointer">関数ポインター構文</a></h2>
<h5 class="version version9">Ver. 9</h5>
<p>問題は <code>IntPtr</code> (<code>nint</code>)でポインターを取れても、
引数や戻り値に関する情報がなくなっていて、
どうやって引数を渡して、どうやって戻り値を受け取ればいいかがわからないことです。</p>
<p><code>NativeLibary</code> クラスも入ったことだし、C# でも関数ポインターを扱える構文が欲しいということになり、C# 9 で実際に導入されることになりました。
記法としては <code>delegate*</code> を使います。
先ほどの <code>NativeLibrary</code> を使った <code>Beep</code> 呼び出しの例を関数ポインターで書き換えると以下のようになります。</p>
<pre class="source" title="関数ポインター構文の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="comment">// 関数ポインターを nint で取得。</span>
<span class="reserved">nint</span> <span class="variable">kernel32</span> <span class="operator">=</span> <span class="type"><span class="static">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">Load</span></span>(<span class="string">&quot;kernel32.dll&quot;</span>);
<span class="reserved">nint</span> <span class="variable">p</span> <span class="operator">=</span> <span class="type"><span class="static">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">GetExport</span></span>(<span class="variable">kernel32</span>, <span class="string">&quot;Beep&quot;</span>);

<span class="reserved">unsafe</span>
{
    <span class="comment">// 「関数ポインター型」にキャストして使う。</span>
    <span class="comment">// 構文的には delegate* から初めて、 &lt;&gt; の中に引数を戻り値の型を並べる。</span>
    <span class="comment">// (戻り値の型が最後。Func&lt;&gt; 風。)</span>
    <span class="reserved">var</span> <span class="variable">fp</span> <span class="operator">=</span> (<span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">uint</span>, <span class="reserved">uint</span>, <span class="reserved">int</span>&gt;)<span class="variable">p</span>;
    <span class="variable">fp</span>(<span class="number">440</span>, <span class="number">1000</span>);
}
</pre>
<p><code>delegate*</code> から書き始めて、<code>&lt;&gt;</code> の中に引数と戻り値の型を並べます。</p>
<p><code>&lt;&gt;</code> の中身は、最後の1個が必ず戻り値です。
<code>Func&lt;&gt;</code> と <code>Action&lt;&gt;</code> のように、戻り値の有無で型を分ける必要はなく、
「戻り値がない場合は最後の1個を <code>void</code> にする」という仕様です。</p>
<pre class="source" title="戻り値がないときは void を書く">
<span class="reserved">unsafe</span>
{
    <span class="comment">// 引数 int, 戻り値 int</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">pf</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="method"><span class="static">f</span></span>;

    <span class="comment">// 引数 int, 戻り値なし(void)</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">int</span>, <span class="reserved">void</span>&gt; <span class="variable">pa</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="static"><span class="method">a</span></span>;
}

<span class="comment">// 同じようなコードでも、デリゲートだと Func/Action の分岐が必要。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">df</span> <span class="operator">=</span> <span class="static"><span class="method">f</span></span>;
<span class="type">Action</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">da</span> <span class="operator">=</span> <span class="static"><span class="method">a</span></span>;

<span class="comment">// (こっちも普通に delegate&lt;int, void&gt; とか書きたい気持ちあるものの、現状、そういう仕様はない。)</span>

<span class="reserved">static</span> <span class="reserved">int</span> <span class="method"><span class="static">f</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="variable local">x</span>;
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">a</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>) { }
</pre>
<p>ちなみに、<a href="https://ufcpp.net/study/il/">IL</a> には .NET Framework 1.0 の頃から関数ポインターの仕様がちゃんとあって、「引数が <code>uint</code> 2つ、戻り値が <code>int</code>」みたいなのを指定して関数ポインターが指す先を呼び出す命令(<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.reflection.emit.opcodes.calli"><code>calli</code></a>)がありました。
あくまで C# 8 以前には <code>calli</code> を出力する能力がなかっただけです。</p>
<h3><a id="and-operator">&amp; 演算子</a></h3>
<p>前節の例ですでに使っていますが、
C# で書いたメソッドに対して <code>&amp;</code> 演算子を使えます。
<code>&amp;</code> 演算子で、<code>GetFunctionPointer</code> などのリフレクション介さずにメソッドから直接関数ポインターを得ることができます。</p>
<pre class="source" title="&amp; 演算子">
<span class="reserved">unsafe</span>
{
    <span class="comment">// &amp; で A.M の関数ポインターを取得。</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt; <span class="variable">p</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>;

    <span class="comment">// ちゃんと呼べる。</span>
    <span class="variable">p</span>();
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>() <span class="operator">=&gt;</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="string">&quot;A.M&quot;</span>);
}
</pre>
<p>ただし、<code>&amp;</code> 演算子で関数ポインターを取れるのは静的メソッドだけです。</p>
<pre class="source" title="&amp; で関数ポインターを取れるのは静的メソッドのみ">
<span class="reserved">unsafe</span>
{
    <span class="comment">// 静的メソッドは OK。</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt; <span class="variable">p1</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">Static</span></span>;

    <span class="comment">// インスタンス メソッドは A.Instance みたいな参照の仕方はできないし、</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt; <span class="variable">p2</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="error" title="CS8759"><span class="type">A</span><span class="operator">.</span><span class="method">Instance</span></span>;

    <span class="comment">// デリゲートみたいに「インスタンス.メソッド」での参照も不可。</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt; <span class="variable">p3</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="error" title="CS8759"><span class="reserved">new</span> <span class="type">A</span>()<span class="operator">.</span><span class="method">Instance</span></span>;

    <span class="reserved">var</span> <span class="variable">a</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span>();
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt; <span class="variable">p4</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="error" title="CS8759"><span class="variable">a</span><span class="operator">.</span><span class="method">Instance</span></span>;
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">Static</span></span>() { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Instance</span>() { }
}
</pre>
<p>ちなみに、取れる値(関数ポインターが指すアドレス)自体は、<code>GetFunctionPointer</code> と同じになります。
ただし、<code>Type</code> 型や <code>MethodInfo</code> 型を介さなくていい分、<code>&amp;</code> 演算子を使う方がパフォーマンスはいいそうです。</p>
<pre class="source" title="GetFunctionPointer と同じ値">
<span class="reserved">var</span> <span class="variable">p1</span> <span class="operator">=</span> <span class="reserved">typeof</span>(<span class="type">A</span>)<span class="operator">.</span><span class="method">GetMethod</span>(<span class="string">&quot;M&quot;</span>)<span class="operator">!</span><span class="operator">.</span><span class="property">MethodHandle</span><span class="operator">.</span><span class="method">GetFunctionPointer</span>();
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="variable">p1</span>);

<span class="reserved">unsafe</span>
{
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt; <span class="variable">p2</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>;

    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>((<span class="reserved">nint</span>)<span class="variable">p2</span>); <span class="comment">// p1 と同じ値が取れる。</span>
    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">p1</span> <span class="operator">==</span> (<span class="reserved">nint</span>)<span class="variable">p2</span>); <span class="comment">// true。</span>
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>() { }
}
</pre>
<h3><a id="arguments">引数・戻り値の型</a></h3>
<p><code>delegate*&lt;T&gt;</code> という、一見するとジェネリック型(<code>Func&lt;T&gt;</code> とか <code>Action&lt;T&gt;</code> とか)と似たような構文ですが、関数ポインターの <code>&lt;&gt;</code> の中に書ける型は、ジェネリック型引数よりもだいぶ制限が緩いです。
現状ではジェネリック型引数には書けない以下のような型も、関数ポインターの <code>&lt;&gt;</code> には普通に書けます。</p>
<ul>
<li><code>ref T</code>, <code>out T</code>, <code>in T</code></li>
<li>ポインター型 <code>T*</code></li>
<li><code>ref struct</code> な型</li>
<li><code>void</code></li>
</ul>
<pre class="source" title="ジェネリック型引数よりもだいぶ緩い制約">
<span class="reserved">unsafe</span>
{
    <span class="comment">// in, out, ref が書ける</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">in</span> <span class="reserved">int</span>, <span class="reserved">out</span> <span class="reserved">int</span>, <span class="reserved">ref</span> <span class="reserved">string</span>&gt; <span class="variable">p1</span> <span class="operator">=</span> <span class="reserved">null</span>;

    <span class="comment">// ポインターが書ける</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">ref</span> <span class="reserved">int</span>, <span class="reserved">int</span><span class="operator">*</span>&gt; <span class="variable">p2</span> <span class="operator">=</span> <span class="reserved">null</span>;

    <span class="comment">// ref struct も書けるし、それのさらに ref も書ける</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;, <span class="reserved">ref</span> <span class="type struct">Span</span>&lt;<span class="reserved">int</span>&gt;&gt; <span class="variable">p3</span> <span class="operator">=</span> <span class="reserved">null</span>;

    <span class="comment">// 前述のとおり、戻り値がないときは void</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt; <span class="variable">p4</span> <span class="operator">=</span> <span class="reserved">null</span>;
}
</pre>
<p>関数ポインターの入れ子も可能です。</p>
<pre class="source" title="">
<span class="reserved">unsafe</span>
{
    <span class="comment">// 入れ子</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">int</span>, <span class="reserved">void</span>&gt;, <span class="reserved">int</span>, <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">void</span>&gt;&gt; <span class="variable">p1</span> <span class="operator">=</span> <span class="reserved">null</span>;
}
</pre>
<p>ちなみに、書ける型の制限が緩いので、Unsafe クラスですらできないことが関数ポインター使えば書けたり。</p>
<h3><a id="calling-convention">呼び出し規約</a></h3>
<p>複数のプログラミング言語をまたいでやり取りする場合、
呼び出し規約(calling convention)というものを気にする必要があります。</p>
<p>呼び出し規約は、引数や戻り値の受け渡しの仕方を呼ぶ側・呼ばれる側でそろえるためのルールです。
1つのプログラミング言語で完結している分にはコンパイラー任せで大丈夫ですが、
言語をまたぐときには明示が必要になります。
(「C# から Windows API を呼ぶ分にはデフォルトの規約が同じ」みたいな理由で省略可能なことはあります。)</p>
<p><code>DllImport</code> では <code>CallingConvention</code> プロパティで、
<code>LibraryImport</code> では <code>UnmanagedCallConv</code> 属性で指定します。</p>
<pre class="source" title="DllImport, LibraryImport での呼び出し規約の指定">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>CompilerServices;
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="type">LibraryImports</span><span class="operator">.</span><span class="method"><span class="static">Beep</span></span>(<span class="number">440</span>, <span class="number">1000</span>);
<span class="type">DllImports</span><span class="operator">.</span><span class="method"><span class="static">Beep</span></span>(<span class="number">440</span>, <span class="number">1000</span>);

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">LibraryImports</span>
{
    <span class="comment">// LibraryImport では UnmanagedCallConv 属性を付ける。</span>
    [<span class="type">LibraryImport</span>(<span class="string">&quot;kernel32.dll&quot;</span>)]
    [<span class="type">UnmanagedCallConv</span>(<span class="field">CallConvs</span>  <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="reserved">typeof</span>(<span class="type">CallConvCdecl</span>) })]
    [<span class="reserved">return</span>: <span class="type">MarshalAs</span>(<span class="type">UnmanagedType</span><span class="operator">.</span>Bool)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="reserved">bool</span> <span class="method"><span class="static">Beep</span></span>(<span class="reserved">uint</span> <span class="variable local">frequency</span>, <span class="reserved">uint</span> <span class="variable local">duration</span>);
}

<span class="reserved">class</span> <span class="type">DllImports</span>
{
    <span class="comment">// DllImport では CallingConvention プロパティを指定する。</span>
    [<span class="type">DllImport</span>(<span class="string">&quot;kernel32.dll&quot;</span>, <span class="field">CallingConvention</span> <span class="operator">=</span> <span class="type">CallingConvention</span><span class="operator">.</span>Cdecl)]
    [<span class="reserved">return</span>: <span class="type">MarshalAs</span>(<span class="type">UnmanagedType</span><span class="operator">.</span>Bool)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">bool</span> <span class="method"><span class="static">Beep</span></span>(<span class="reserved">uint</span> <span class="variable local">frequency</span>, <span class="reserved">uint</span> <span class="variable local">duration</span>);
}
</pre>
<p>関数ポインターでは、<code>delegate*</code> と <code>&lt;&gt;</code> の間に、
<code>managed</code> もしくは <code>unmanaged[]</code> という修飾を付けます。</p>
<pre class="source" title="">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="reserved">nint</span> <span class="variable">kernel32</span> <span class="operator">=</span> <span class="static"><span class="type">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">Load</span></span>(<span class="string">&quot;kernel32.dll&quot;</span>);
<span class="reserved">nint</span> <span class="variable">p</span> <span class="operator">=</span> <span class="static"><span class="type">NativeLibrary</span></span><span class="operator">.</span><span class="method"><span class="static">GetExport</span></span>(<span class="variable">kernel32</span>, <span class="string">&quot;Beep&quot;</span>);

<span class="reserved">unsafe</span>
{
    <span class="comment">// 規約を省略。省略時のデフォルトは managed。</span>
    <span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">p1</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="type">A</span><span class="operator">.</span><span class="static"><span class="method">M</span></span>;

    <span class="comment">// managed 規約。C# で書いた普通のメソッドを呼ぶときに使う。</span>
    <span class="comment">// 要は「.NET ランタイム任せ」。</span>
    <span class="reserved">delegate</span><span class="operator">*</span> <span class="reserved">managed</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">p2</span> <span class="operator">=</span> <span class="operator">&amp;</span><span class="type">A</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>;

    <span class="comment">// unmanaged のみ指定。</span>
    <span class="comment">// 呼び出し規約はプラットフォーム依存で、</span>
    <span class="comment">// Windows では stdcall、他のプラットフォームでは cdecl になるっぽい。</span>
    <span class="reserved">var</span> <span class="variable">p3</span> <span class="operator">=</span> (<span class="reserved">delegate</span><span class="operator">*</span> <span class="reserved">unmanaged</span>&lt;<span class="reserved">uint</span>, <span class="reserved">uint</span>, <span class="reserved">int</span>&gt;)<span class="variable">p</span>;

    <span class="comment">// unmanaged[] で呼び出し規約を明示。</span>
    <span class="reserved">var</span> <span class="variable">p4</span> <span class="operator">=</span> (<span class="reserved">delegate</span><span class="operator">*</span> <span class="reserved">unmanaged</span>[Stdcall]&lt;<span class="reserved">uint</span>, <span class="reserved">uint</span>, <span class="reserved">int</span>&gt;)<span class="variable">p</span>;
}

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>, <span class="reserved">int</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="variable local">y</span>;
}
</pre> ]]></description>
				<pubDate>Sat, 01 Apr 2023 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>test</title>
				<link>http://www.ufcpp.net/study/misc/list/test/</link>
				<description><![CDATA[ <p>test</p>
<p>https://github.com/ufcpp/UfcppSample/blob/master/BreakingChanges/VS2015_CS6/KatakanaMiddleDot.cs#L15-22</p>
<p>test</p>
<p>https://gist.github.com/ufcpp/03dd6fc45b643e580d20</p>
<p>test</p>
<p><script src="https://gist.github.com/ufcpp/03dd6fc45b643e580d20.js"></script></p>
<h2>MathJax MathML</h2>
<pre class="xsource" title="">
<code><attvalue></span><span class="attvalue">&lt;</span>math <span class="attribute">xmlns</span><span class="attvalue">="http://www.w3.org/1998/Math/MathML"&gt;</span>
    <span class="attvalue">&lt;</span>mrow<span class="attvalue">&gt;</span>
        <span class="attvalue">&lt;</span>mrow<span class="attvalue">&gt;</span>
            <span class="attvalue">&lt;</span>munder<span class="attvalue">&gt;</span>
                <span class="attvalue">&lt;</span>mrow<span class="attvalue">&gt;&lt;</span>mi <span class="attribute">mathvariant</span><span class="attvalue">="normal"&gt;</span>lim<span class="attvalue">&lt;/</span>mi<span class="attvalue">&gt;&lt;/</span>mrow<span class="attvalue">&gt;</span>
                <span class="attvalue">&lt;</span>mrow<span class="attvalue">&gt;&lt;</span>mi<span class="attvalue">&gt;</span>x<span class="attvalue">&lt;/</span>mi<span class="attvalue">&gt;&lt;</span>mo<span class="attvalue">&gt;</span>→<span class="attvalue">&lt;/</span>mo<span class="attvalue">&gt;&lt;</span>mn<span class="attvalue">&gt;</span>0<span class="attvalue">&lt;/</span>mn<span class="attvalue">&gt;&lt;/</span>mrow<span class="attvalue">&gt;</span>
            <span class="attvalue">&lt;/</span>munder<span class="attvalue">&gt;</span>
        <span class="attvalue">&lt;/</span>mrow<span class="attvalue">&gt;</span>
        <span class="attvalue">&lt;</span>mo<span class="attvalue">&gt;</span>⁡<span class="attvalue">&lt;/</span>mo<span class="attvalue">&gt;</span>
        <span class="attvalue">&lt;</span>mrow<span class="attvalue">&gt;</span>
            <span class="attvalue">&lt;</span>mi<span class="attvalue">&gt;</span>g<span class="attvalue">&lt;/</span>mi<span class="attvalue">&gt;&lt;</span>mfenced <span class="attribute">separators</span><span class="attvalue">="|"&gt;&lt;</span>mrow<span class="attvalue">&gt;&lt;</span>mi<span class="attvalue">&gt;</span>x<span class="attvalue">&lt;/</span>mi<span class="attvalue">&gt;&lt;/</span>mrow<span class="attvalue">&gt;&lt;/</span>mfenced<span class="attvalue">&gt;</span>
        <span class="attvalue">&lt;/</span>mrow<span class="attvalue">&gt;</span>
    <span class="attvalue">&lt;/</span>mrow<span class="attvalue">&gt;</span>
    <span class="attvalue">&lt;</span>mo<span class="attvalue">&gt;</span>=<span class="attvalue">&lt;/</span>mo<span class="attvalue">&gt;</span>
    <span class="attvalue">&lt;</span>mn<span class="attvalue">&gt;</span>0<span class="attvalue">&lt;/</span>mn<span class="attvalue">&gt;</span>
<span class="attvalue">&lt;/</span>math<span class="attvalue">&gt;</span>
</code></pre>
<p>↓</p>
<math xmlns="http://www.w3.org/1998/Math/MathML">
    <mrow>
        <mrow>
            <munder>
                <mrow><mi mathvariant="normal">lim</mi></mrow>
                <mrow><mi>x</mi><mo>→</mo><mn>0</mn></mrow>
            </munder>
        </mrow>
        <mo>⁡</mo>
        <mrow>
            <mi>g</mi><mfenced separators="|"><mrow><mi>x</mi></mrow></mfenced>
        </mrow>
    </mrow>
    <mo>=</mo>
    <mn>0</mn>
</math>
<p><span>
&lt;mml:math xmlns:mml=&quot;http://www.w3.org/1998/Math/MathML&quot; xmlns:m=&quot;http://schemas.openxmlformats.org/officeDocument/2006/math&quot;&gt;&lt;mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:munder&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;lim&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;n&lt;/mml:mi&gt;&lt;mml:mo&gt;→&lt;/mml:mo&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;∞&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;/mml:munder&gt;&lt;/mml:mrow&gt;&lt;mml:mo&gt;⁡&lt;/mml:mo&gt;&lt;mml:mrow&gt;&lt;mml:msup&gt;&lt;mml:mrow&gt;&lt;mml:mfenced separators=&quot;|&quot;&gt;&lt;mml:mrow&gt;&lt;mml:mn&gt;1&lt;/mml:mn&gt;&lt;mml:mo&gt;+&lt;/mml:mo&gt;&lt;mml:mfrac&gt;&lt;mml:mrow&gt;&lt;mml:mn&gt;1&lt;/mml:mn&gt;&lt;/mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;n&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;/mml:mfrac&gt;&lt;/mml:mrow&gt;&lt;/mml:mfenced&gt;&lt;/mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;n&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;/mml:msup&gt;&lt;/mml:mrow&gt;&lt;/mml:mrow&gt;&lt;/mml:math&gt;
</span></p>
<p><span>
&lt;mml:math xmlns:mml=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:munder&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;lim&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;n&lt;/mml:mi&gt;&lt;mml:mo&gt;→&lt;/mml:mo&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;∞&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;/mml:munder&gt;&lt;/mml:mrow&gt;&lt;mml:mo&gt;⁡&lt;/mml:mo&gt;&lt;mml:mrow&gt;&lt;mml:msup&gt;&lt;mml:mrow&gt;&lt;mml:mfenced separators=&quot;|&quot;&gt;&lt;mml:mrow&gt;&lt;mml:mn&gt;1&lt;/mml:mn&gt;&lt;mml:mo&gt;+&lt;/mml:mo&gt;&lt;mml:mfrac&gt;&lt;mml:mrow&gt;&lt;mml:mn&gt;1&lt;/mml:mn&gt;&lt;/mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;n&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;/mml:mfrac&gt;&lt;/mml:mrow&gt;&lt;/mml:mfenced&gt;&lt;/mml:mrow&gt;&lt;mml:mrow&gt;&lt;mml:mi mathvariant=&quot;normal&quot;&gt;n&lt;/mml:mi&gt;&lt;/mml:mrow&gt;&lt;/mml:msup&gt;&lt;/mml:mrow&gt;&lt;/mml:mrow&gt;&lt;/mml:math&gt;
</span></p>
<p><span>
&lt;math xmlns:mml=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;<mrow><mrow><munder><mrow><mi mathvariant="normal">lim</mi></mrow><mrow><mi mathvariant="normal">n</mi><mo>→</mo><mi mathvariant="normal">∞</mi></mrow></munder></mrow><mo>⁡</mo><mrow><msup><mrow><mfenced separators="|"><mrow><mn>1</mn><mo>+</mo><mfrac><mrow><mn>1</mn></mrow><mrow><mi mathvariant="normal">n</mi></mrow></mfrac></mrow></mfenced></mrow><mrow><mi mathvariant="normal">n</mi></mrow></msup></mrow></mrow></math>
</span></p>
<h2>MathJax Tex</h2>
<p><code>$\displaystyle \lim_{x \to 0} g(x) = 0$</code></p>
<p>↓</p>
<p>$\displaystyle \lim_{x \to 0} g(x) = 0$</p>
<h2>Simple tables</h2>
<table>
<thead>
<tr>
	<th>a</th>
	<th>b</th>
	<th>c</th>
</tr>
</thead>
<tbody>
<tr>
	<td>x</td>
	<td>y</td>
	<td>z</td>
</tr>
</tbody>
</table>
<h2>figures</h2>
<p><img src="/media/1033/eto.png" alt="enter image description here" title="テスト用" />
^^^テスト用</p>
<h2>embedded tags</h2>
<div>
<script async class="speakerdeck-embed" data-id="27b8ed9f16104ccaa98b2132e2e5306d" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>
</div>
<h2>versions</h2>
<p>元々 h5 使ってたけど</p>
<h5 class="version version2">Ver. 2.0</h5>
<h5 class="version version3">Ver. 3.0</h5>
<h5 class="version version4">Ver. 4.0</h5>
<h5 class="version version5">Ver. 5.0</h5>
<h5 class="version version6">Ver. 6</h5>
<h5 class="version version7">Ver. 7</h5>
<h5 class="version version8">Ver. 8</h5>
<h5 class="version version9">Ver. 9</h5>
<h5 class="version version10">Ver. 10</h5>
<h5 class="version version11">Ver. 11</h5>
<h5 class="version version12">Ver. 12</h5>
<h5 class="version version13">Ver. 13</h5>
<p>div に変えようかな。</p>
<div class="version version2">Ver. 2.0</div>
<div class="version version3">Ver. 3.0</div>
<div class="version version4">Ver. 4.0</div>
<div class="version version5">Ver. 5.0</div>
<div class="version version6">Ver. 6.0</div>
<div class="version version7">Ver. 7.0</div>
<div class="version version7_1">Ver. 7.1</div>
<div class="version version7_2">Ver. 7.2</div>
<div class="version version7_3">Ver. 7.3</div>
<div class="version version8">Ver. 8.0</div>
<div class="version version9">Ver. 9.0</div>
<div class="version version10">Ver. 10</div>
<div class="version version11">Ver. 11</div>
<div class="version version12">Ver. 12</div>
<div class="version version13">Ver. 13</div>
<div class="version version14">Ver. 14</div>
<div class="version version15">Ver. 15</div>
<div class="version version16">Ver. 16</div>
<div class="version version17">Ver. 17</div>
<div class="version version18">Ver. 18</div>
<div class="version version19">Ver. 19</div>
<h3>source code</h3>
<pre class="source" title="">
<span class="reserved">var</span> <span class="variable">s</span> <span class="operator">=</span> <span class="string">"abcあいう😊😀😁"u8</span>;

<span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">s</span>[..<span class="number">8</span>])
{
    <span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="string">$"</span>{(<span class="reserved">int</span>)<span class="variable">x</span>:<span class="string">X</span>}<span class="string">"</span>);
}

<span class="reserved">readonly</span> <span class="reserved">record</span> <span class="reserved">struct</span> <span class="type struct">S</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="reserved">operator</span> <span class="operator">+</span>(<span class="type struct">S</span> <span class="variable local">x</span>) <span class="operator">=></span> <span class="reserved">true</span>;
}

<span class="reserved">sealed</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_x</span> <span class="operator">=</span> <span class="number">0</span>;
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="property">X</span> <span class="operator">=></span> <span class="field">_x</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>() { }
}

<span class="comment">///</span><span class="comment"> </span><span class="comment"><</span><span class="comment">summary</span><span class="comment">></span>
<span class="comment">///</span><span class="comment"> abc</span>
<span class="comment">///</span><span class="comment"> </span><span class="comment"></</span><span class="comment">summary</span><span class="comment">></span>
<span class="reserved">class</span> <span class="type"><span class="warning" title="CS8981">abc</span></span><span class="error" title="CS1514"><span class="error" title="CS1513"><span class="error" title="CS8803">(<span class="error" title="CS1525"></span></span>)</span>;</span>

<span class="preprocess">#</span><span class="preprocess">if</span> <span class="reserved">false</span>
<span class="excluded">record R();
<span class="preprocess"></span>#</span><span class="preprocess">endif</span>
</pre>
<pre class="source" title="">
<code><span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">int</span> <span class="warning">xxxxxxxxx</span>;

        <span class="reserved">int</span> <span class="error">xxxxxxxxx</span>;
    }

    <span class="reserved">int</span> <span class="method">X</span> { <span class="reserved">get</span>; <span class="suggestion"><span class="reserved">set</span>;</span> }
}
</code></pre>
<pre class="source" title="test code">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System<span class="operator">.</span>Text;
<span class="reserved">using</span> <span class="reserved">static</span> System<span class="operator">.</span>Text<span class="operator">.</span>Unicode<span class="operator">.</span><span class="type">Utf8</span>;

<span class="reserved">const</span> <span class="reserved">double</span> <span class="constant">A</span> <span class="operator">=</span> <span class="number">1.2</span>;

<span class="control">if</span> (<span class="reserved">args</span><span class="operator">.</span><span class="property">Length</span> <span class="operator">&gt;</span> <span class="number">0</span>)
{
    <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="constant">A</span>);

    <span class="reserved">var</span> <span class="variable">buffer</span> <span class="operator">=</span> (<span class="reserved">stackalloc</span> <span class="reserved">byte</span>[<span class="number">256</span>]);

    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="reserved">args</span>)
    {
        <span class="method">FromUtf16</span>(<span class="variable">x</span>, <span class="variable">buffer</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">read</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">writtern</span>);
    }
}

<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="string">$&quot;&quot;&quot;
</span><span class="string">    abc
    </span>{<span class="number">123</span>}<span class="string">
    &quot;&quot;&quot;</span>);

<span class="reserved">internal</span> <span class="reserved">record</span> <span class="reserved">class</span> <span class="type">A</span>();
<span class="reserved">internal</span> <span class="reserved">record</span> <span class="reserved">struct</span> <span class="type struct">B</span>();
<span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="field">PublicField</span>;
    <span class="reserved">private</span> <span class="reserved">int</span> <span class="field">_privateField</span>;

    <span class="reserved">public</span> <span class="type struct">DateOnly</span> <span class="property">Property1</span> { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type struct">TimeSpan</span> <span class="property">Property2</span> { <span class="reserved">get</span>; }

    <span class="reserved">public</span> <span class="reserved">string</span> <span class="property">ComputedProperty</span> <span class="operator">=&gt;</span> <span class="property">Property1</span> <span class="operator">+</span> <span class="string">$&quot;</span>{<span class="property">Property2</span>}<span class="string">&quot;</span>;

    <span class="reserved">public</span> <span class="reserved">int</span> <span class="method">Method</span>(<span class="reserved">int</span> <span class="variable local">p1</span>, <span class="reserved">int</span> <span class="variable local">p2</span>, <span class="reserved">int</span> <span class="variable local">p3</span>)
    {
        <span class="reserved">var</span> <span class="variable">local</span> <span class="operator">=</span> <span class="variable local">p1</span> <span class="operator">+</span> <span class="variable local">p2</span> <span class="operator">+</span> <span class="variable local">p3</span>;
        <span class="control">return</span> <span class="variable">local</span> <span class="operator">+</span> <span class="field">_privateField</span>;
    }
}
<span class="reserved">internal</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">D</span> { }
</code></pre>
<h3>source code (抜粋)</h3>
<p>Program.cs へのコピペで動くソースコードと、「一部分抜粋」でそれだけだと動かないやつ、css 変えようかな。</p>
<pre class="source partial" title="WinForms アプリで、Visual Studio が生成するコード">
<span class="reserved">namespace</span> WinFormsApp1;

<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Form1</span>
{
    <span class="comment">// 前略</span>
    <span class="comment">// この部分は手書きで書き換える想定。</span>

    <span class="preprocess">#</span><span class="preprocess">region</span> Windows Form Designer generated code

    <span class="comment">///</span><span class="comment"> </span><span class="comment">&lt;</span><span class="comment">summary</span><span class="comment">&gt;</span>
    <span class="comment">///</span><span class="comment">  Required method for Designer support - do not modify</span>
    <span class="comment">///</span><span class="comment">  the contents of this method with the code editor.</span>
    <span class="comment">///</span><span class="comment"> </span><span class="comment">&lt;/</span><span class="comment">summary</span><span class="comment">&gt;</span>
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">InitializeComponent</span>()
    {
        <span class="reserved">this</span><span class="operator">.</span><span class="field">components</span> <span class="operator">=</span> <span class="reserved">new</span> System<span class="operator">.</span>ComponentModel<span class="operator">.</span><span class="type">Container</span>();
        <span class="reserved">this</span><span class="operator">.</span>AutoScaleMode <span class="operator">=</span> System<span class="operator">.</span>Windows<span class="operator">.</span>Forms<span class="operator">.</span>AutoScaleMode<span class="operator">.</span>Font;
        <span class="reserved">this</span><span class="operator">.</span>ClientSize <span class="operator">=</span> <span class="reserved">new</span> System<span class="operator">.</span>Drawing<span class="operator">.</span><span class="type struct">Size</span>(<span class="number">800</span>, <span class="number">450</span>);
        <span class="reserved">this</span><span class="operator">.</span>Text <span class="operator">=</span> <span class="string">&quot;Form1&quot;</span>;
    }

    <span class="preprocess">#</span><span class="preprocess">endregion</span>
}
</pre>
<h2>Blazor (外部)</h2>
<div><iframe src="https://black-ocean-009cb0000.2.azurestaticapps.net/?a=quick&i=0&s=0&w=300" width="304" height="332"></iframe></div>
<p>↑のソースコード: <a href="https://github.com/ufcpp/StaticWebApps/tree/main/BlazorWasm/SortVisualizer">https://github.com/ufcpp/StaticWebApps/tree/main/BlazorWasm/SortVisualizer</a></p>
 ]]></description>
				<pubDate>Mon, 31 Oct 2022 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 11.0 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver11/</link>
				<description><![CDATA[ <div class="version version11">Ver. 11.0</div>
<table>
<tr>
<th>リリース時期</th>
<td>2022/11</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>.NET 7.0</li>
<li>Visual Studio 2022 17.4</li>
</td>
</tr>
</table>
<p>執筆予定: <a href="https://github.com/ufcpp/UfcppSample/issues/387">C# 11.0 トラッキング issue</a></p>
<h2><a id="utf8-literal">UTF-8 リテラル</h2>
<p><code>&quot;abc&quot;u8</code> みたいに、文字列リテラルの後ろに u8 接尾辞を付けることで、UTF-8 な byte 列を文字列リテラルの形で書けるようになりました。</p>
<pre class="source" title="u8 リテラルの例">
<code><span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">hex</span> <span class="operator">=</span> <span class="string">&quot;0123456789ABCDEF&quot;u8</span>;
</code></pre>
<p>以下のような byte 列とほぼ同じ意味になります。</p>
<pre class="source" title="u8 リテラルの展開結果の例">
<code><span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">s</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="reserved">byte</span>[] { <span class="number">97</span>, <span class="number">98</span>, <span class="number">99</span> };
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/st_string.html?p=3#utf8-literal">UTF-8 リテラル</a>」で説明します。</p>
<h2><a id="raw-string">生文字列リテラル</a></h2>
<p>C# 11 で、3つ以上の連続した <code>&quot;</code> を使うことで、「一切エスケープが必要ない文字列リテラル」を書けるようになりました。</p>
<pre class="source" title="raw string literal">
<code><span class="comment">// &quot;&quot;&quot; から始まる文字列リテラル(raw string, 生文字列)。</span>
<span class="reserved">var</span> <span class="variable">quote</span> = <span class="string">&quot;&quot;&quot;
    &quot; はそのまま &quot; として使われて、
    \ も \ のままの意味。
    \\ は \ が2個。
    {} とかも特別な解釈はされない。
    &quot;&quot;&quot;</span>;
</code></pre>
<p>この <code>&quot;&quot;&quot;</code> を使った書き方で、さらに文字列補間をすることもできます。</p>
<pre class="source" title="$ を2個にすれば、{ 1個はエスケープなしで書ける">
<code><span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">format</span>(123, <span class="string">&quot;abc&quot;</span>));

<span class="reserved">static</span> <span class="reserved">string</span> <span class="method">format</span>(<span class="reserved">int</span> <span class="variable">id</span>, <span class="reserved">string</span> <span class="variable">name</span>) =&gt; <span class="string">$$&quot;&quot;&quot;
</span><span class="string">    {
      &quot;id&quot;: </span>{{<span class="variable">id</span> <span class="comment">/* ここは補間 */</span> }}<span class="string">,
      &quot;name&quot;: &quot;</span>{{<span class="variable">name</span> <span class="comment">/* ここも補間 */</span>}}<span class="string">&quot;
    }</span><span class="string">
    &quot;&quot;&quot;</span>;
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/st_string.html?p=2#raw-string">生文字列リテラル</a>」で説明します。</p>
<h2><a id="required">required メンバー</a></h2>
<p>プロパティとフィールドに対する <code>required</code> 修飾子というものが追加されました。
これを使うと、<a href="https://ufcpp.net/study/csharp/oo_construct.html#member_initializer">オブジェクト初期化子</a>で何らかの値を代入することを義務付けられます。
例えば以下のようなコードを書いたとき、<code>a1</code> 以外の <code>new A</code> はエラーになります。
(警告ではなくエラーにします。)</p>
<pre class="source" title="required 修飾子">
<span class="reserved">var</span> <span class="variable">a1</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">A</span> { <span class="property">X</span> <span class="operator">=</span> <span class="string">&quot;abc&quot;</span>, <span class="property">Y</span> <span class="operator">=</span> <span class="number">123</span> };

<span class="reserved">var</span> <span class="variable">a2</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type"><span class="error" title="CS9035">A</span></span> { <span class="property">X</span> <span class="operator">=</span> <span class="string">&quot;abc&quot;</span> }; <span class="comment">// Y を代入していないのでエラー。</span>
<span class="reserved">var</span> <span class="variable">a3</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type"><span class="error" title="CS9035">A</span></span> { <span class="property">Y</span> <span class="operator">=</span> <span class="number">123</span> };   <span class="comment">// X を代入していないのでエラー。</span>
<span class="reserved">var</span> <span class="variable">a4</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type"><span class="error" title="CS9035"><span class="error" title="CS9035">A</span></span></span>();             <span class="comment">// X も Y も代入していないのでエラー。</span>

<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <em><span class="reserved">required</span></em> <span class="reserved">string</span> <span class="property">X</span> { <span class="reserved">get</span>; <span class="reserved">init</span>; }
    <span class="reserved">public</span> <em><span class="reserved">required</span></em> <span class="reserved">int</span> <span class="property">Y</span>;
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oo_property.html?p=2#required">required メンバー</a>」で説明します。</p>
<h2><a id="list">リスト パターン</a></h2>
<p>C# 11で、<code>[]</code> を使ってリスト(配列や <code>List&lt;T&gt;</code> など)に対するパターン マッチングができるようになりました。
例えば以下のような <code>switch</code> を書けます。</p>
<pre class="source" title="リスト パターンの例">
<code><span class="reserved">static</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="method">removeBom</span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable local">utf8</span>)
    <span class="operator">=&gt;</span> <span class="variable local">utf8</span> <span class="reserved">is</span> [<span class="number">0xEF</span>, <span class="number">0xBB</span>, <span class="number">0xBF</span>, .. <span class="reserved">var</span> noBom] <span class="operator">?</span> <span class="variable">noBom</span> <span class="operator">:</span> <span class="variable local">utf8</span>;

<span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">palindrome</span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">list</span>) <span class="operator">=&gt;</span> <span class="variable local">list</span> <span class="control">switch</span>
{
    [] <span class="reserved">or</span> [<span class="reserved">_</span>] <span class="operator">=&gt;</span> <span class="reserved">true</span>,
    [<span class="reserved">var</span> first, .. <span class="reserved">var</span> rest, <span class="reserved">var</span> last] <span class="operator">=&gt;</span> <span class="variable">first</span> <span class="operator">==</span> <span class="variable">last</span> <span class="operator">&amp;&amp;</span> <span class="method">palindrome</span>(<span class="variable">rest</span>),
};
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/datatype/patterns/?p=2#list">リスト パターン</a>」で説明します。</p>
<h2><a id="generic-math">Generic Math</a></h2>
<p>インターフェイスの静的メンバーを仮想・抽象にできるようになりました。</p>
<p>この機能の一番の用途は、数値型(<code>int</code> や <code>float</code> など)に対するアルゴリズムを<a href="https://ufcpp.net/study/csharp/sp2_generics.html">ジェネリクス</a>を使って書けるようにすることです。
この最大用途にちなんで、
インターフェイスの静的メンバーなどを含む一連の機能を「generic math」と呼んだりしていました。
(コンセプト的な呼び名で、具体的に generic math という名前の文法やライブラリが追加されたわけではありません。)</p>
<p>generic math 関連で、数値型の演算子関連で3つ新機能が追加されています。</p>
<ul>
<li><a href="#unsigned-right-shift">符号なし右シフト</a></li>
<li><a href="#checked-operator-overload">checked 演算子オーバーロード</a></li>
<li><a href="#relaxing-shift">シフト演算子の右オペランドの制限撤廃</a></li>
</ul>
<h3><a id="static-abstract">インターフェイスの静的抽象メンバー</a></h3>
<p>まず、インターフェイスの静的メンバーについてですが、
例えば以下のようなコードが書けるようになりました。</p>
<pre class="source" title="ジェネリックな Sum メソッド">
<span class="reserved">using</span> System<span class="operator">.</span>Numerics;

<span class="comment">// よくある「和を取るコード」なものですら、これまでだとジェネリックに書く手段がなかった。</span>
<span class="comment">// C# 11 で可能に。</span>
<span class="reserved">static</span> <span class="type param">T</span> <span class="static"><span class="method">Sum</span></span>&lt;<span class="type param">T</span>&gt;(<span class="type">IEnumerable</span>&lt;<span class="type param">T</span>&gt; <span class="variable local">items</span>)
    <span class="reserved">where</span> <span class="type param">T</span> : <span class="type">INumber</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">var</span> <span class="variable">sum</span> <span class="operator">=</span> <span class="type param">T</span><span class="operator">.</span><span class="property"><span class="static">Zero</span></span>;
    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable local">items</span>) <span class="variable">sum</span> += <span class="variable">x</span>;
    <span class="control">return</span> <span class="variable">sum</span>;
}

<span class="comment">// いろんな型に対して sum&lt;T&gt; を呼ぶ。</span>
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="method"><span class="static">Sum</span></span>(<span class="reserved">new</span> <span class="reserved">byte</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span> }));
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="static"><span class="method">Sum</span></span>(<span class="reserved">new</span> <span class="reserved">int</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span> }));
<span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">WriteLine</span></span>(<span class="method"><span class="static">Sum</span></span>(<span class="reserved">new</span> <span class="reserved">float</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span> }));
<span class="static"><span class="type">Console<span class="operator"></span></span>.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="method"><span class="static">Sum</span></span>(<span class="reserved">new</span> <span class="reserved">double</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span> }));
<span class="static"><span class="type">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="method"><span class="static">Sum</span></span>(<span class="reserved">new</span> <span class="reserved">decimal</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span> }));
</pre>
<p>(詳しくは「<a href="https://ufcpp.net/study/csharp/oo_interface.html?p=6#static-abstract">インターフェイスの静的抽象メンバー</a>」で説明します。)</p>
<h3><a id="unsigned-right-shift">符号なし右シフト</a></h3>
<p>符号付き整数(<code>int</code> とか <code>sbyte</code> とか)でも符号なし整数(<code>uint</code> とか <code>byte</code> とか)でも無関係に、
常に「符号なし右シフト(論理シフト)」をするための <code>&gt;&gt;&gt;</code>演算子 (<code>&gt;</code> の数が3つ)が追加されました。</p>
<pre class="source" title="C# にも符号なし右シフト演算子を導入">
<code><span class="reserved">using</span> System.Numerics;

<span class="reserved">sbyte</span> <span class="variable">s</span> = -1;

<span class="comment">// ちゃんと符号なし右シフトに。</span>
<span class="comment">// FF → 7F → 3F → 1F → F → 7 → 3 → 1</span>
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 8; <span class="variable">i</span>++)
{
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">s</span>:<span class="string">X</span>}<span class="string">&quot;</span>);
    <span class="variable">s</span> = <span class="method">LogicalRightShift</span>(<span class="variable">s</span>, 1);
}

<span class="comment">// &gt;&gt;&gt; でどの型に対しても符号なし右シフト。</span>
<span class="reserved">static</span> <span class="type">T</span> <span class="method">LogicalRightShift</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">s</span>, <span class="reserved">int</span> <span class="variable">bits</span>)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">IShiftOperators</span>&lt;<span class="type">T</span>,<span class="type">T</span>&gt;
    =&gt; <span class="variable">s</span> <em>&gt;&gt;&gt;</em> <span class="variable">bits</span>;
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oop/generic-math-operators/#unsigned-right-shift">【Generic Math】 C# 11 での演算子の新機能</a>」で説明します。</p>
<h3><a id="checked-operator-overload">checked 演算子オーバーロード</a></h3>
<p><code>operator</code> キーワードの後ろに <code>checked</code> を付けることで、
「<code>checked</code> 演算子」を定義できるようになりました。
これにより、ユーザー定義の演算子オーバーロードでも <code>checked</code>(オーバーフロー時に例外を投げる)と <code>unchecked</code> (オーバーフローしても例外を投げない)を切り替えられるようになります。</p>
<pre class="source" title="checked 演算子オーバーロードの例">
<code><span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type struct">Int2Bit</span>
{
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">byte</span> <span class="field">Value</span>;
    <span class="reserved">public</span> <span class="type struct">Int2Bit</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="field">Value</span> <span class="operator">=</span> (<span class="reserved">byte</span>)(<span class="variable local">value</span> <span class="operator">&amp;</span> <span class="number">0b11</span>);
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="field">Value</span><span class="operator">.</span><span class="method">ToString</span>();

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">Int2Bit</span> <span class="method">Checked</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="variable local">value</span> <span class="reserved">is</span> <span class="operator">&lt;</span> <span class="number">2</span> <span class="reserved">and</span> <span class="operator">&gt;=</span> <span class="number">0</span> <span class="operator">?</span> <span class="reserved">new</span>(<span class="variable local">value</span>) <span class="operator">:</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">OverflowException</span>();

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">Int2Bit</span> <span class="reserved">operator</span> <span class="operator">+</span>(<span class="type struct">Int2Bit</span> <span class="variable local">x</span>, <span class="type struct">Int2Bit</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">new</span>(<span class="variable local">x</span><span class="operator">.</span><span class="field">Value</span> <span class="operator">+</span> <span class="variable local">y</span><span class="operator">.</span><span class="field">Value</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">Int2Bit</span> <span class="reserved">operator</span> <span class="reserved"><em>checked</em></span> <span class="operator">+</span>(<span class="type struct">Int2Bit</span> <span class="variable local">x</span>, <span class="type struct">Int2Bit</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="method">Checked</span>(<span class="variable local">x</span><span class="operator">.</span><span class="field">Value</span> <span class="operator">+</span> <span class="variable local">y</span><span class="operator">.</span><span class="field">Value</span>);
}
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oop/generic-math-operators/#checked-operator-overload">【Generic Math】 C# 11 での演算子の新機能</a>」で説明します。</p>
<h3><a id="relaxing-shift">シフト演算子の右オペランドの制限撤廃</a></h3>
<p>シフト演算子の右オペランドに <code>int</code> 以外の型を使えるようになりました。</p>
<pre class="source" title="C# 11 で operator &lt;&lt;(A x, A y) とかが書けるように">
<code><span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="comment">// C# 10 以前でも書けるオーバーロード。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="operator">&lt;&lt;</span>(<span class="type struct">A</span> <span class="variable local">x</span>, <span class="reserved">int</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;

    <span class="comment">// C# 11 以降でだけ書けるオーバーロード。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="operator">&lt;&lt;</span>(<span class="type struct">A</span> <span class="variable local">x</span>, <em><span class="type struct">A</span> <span class="variable local">y</span></em>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
}
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oop/generic-math-operators/#relaxing-shift">【Generic Math】 C# 11 での演算子の新機能</a>」で説明します。</p>
<h2><a id="file-local">file ローカル型</h2>
<p><code>file</code> という修飾子を使って「書いたファイル内からだけアクセスできる型」を作れるようになりました。</p>
<pre class="source" title="file 修飾付きの型を使う例">
<span class="number">1</span><span class="operator">.</span><span class="method">M</span>();

<em><span class="reserved">file</span></em> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">Extensions</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=></span> <span class="type"><span class="static">Console</span><span class="operator">.<span class="method"><span class="static">WriteLine</span></span>(<span class="variable local">x</span>);
}
</pre>
<p>これと同じプロジェクト内の別のファイルに以下のようなコードを書いてもエラーにはなりません。</p>
<pre class="source" title="別のファイルに同名の file 修飾付きの型を定義">
<em><span class="reserved">file</span></em> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">Extensions</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=></span> <span class="type"><span class="static">Console</span><span class="operator">.<span class="method"><span class="static">WriteLine</span></span>(<span class="string">"別ファイルの file-local Extensions"</span>);
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/misc/file-local">file ローカル型</a>」で説明します。</p>
<h2><a id="ref-field">ref フィールド</a></h2>
<p><a href="https://ufcpp.net/study/csharp/resource/refstruct/#key-refstruct">ref 構造体</a>のフィールドを <a href="https://ufcpp.net/study/csharp/sp_ref.html#byref"><code>ref</code> (参照渡し)</a>で持てるようになりました。</p>
<p>ref フィールドの書き方は参照引数や参照戻り値と同じく、型の前に <code>ref</code> 修飾を付けます。</p>
<pre class="source" title="ref フィールド">
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">ByReference</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="type param">T</span> <span class="field">Value</span>;
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/resource/refstruct/#ref-field">ref フィールド</a>」で説明します。</p>
<h2><a id="others">その他</a></h2>
<h3><a id="span">ReadOnlySpan に対するパターンマッチ</a></h3>
<p>C# 11 で、<code>ReadOnlySpan&lt;char&gt;</code> に対して<a href="https://ufcpp.net/study/csharp/datatype/patterns/#span">文字列リテラルによる定数パターン</a>が使えるようになりました。</p>
<pre class="source" title="">
<span class="comment">// string を渡せたところには ReadOnlySpan&lt;char&gt; を渡せるように。</span>
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">char</span>&gt; <span class="variable">s</span> <span class="operator">=</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">ReadLine</span></span>();

<span class="comment">// is も</span>
<span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> <span class="string">&quot;a&quot;</span>) { }

<span class="comment">// switch ステートメントも</span>
<span class="control">switch</span> (<span class="variable">s</span>)
{
    <span class="control">case</span> <span class="string">&quot;b&quot;</span>:
        <span class="control">break</span>;
}

<span class="comment">// switch 式も OK。</span>
<span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="variable">s</span> <span class="control">switch</span>
{
    <span class="string">&quot;c&quot;</span> <span class="operator">=&gt;</span> <span class="number">1</span>,
    <span class="reserved">_</span> <span class="operator">=&gt;</span> <span class="number">2</span>,
};
</pre>
<h3><a id="nameof-parameter">nameof(引数) のスコープ変更</h3>
<p><a href="https://ufcpp.net/study/csharp/st_string.html#nameof-parameter"><code>nameof</code></a> にちょっとだけ変更が掛かりました。
以下のように、メソッドに対する属性の中で、そのメソッドの引数の名前が参照できるようになりました。</p>
<pre class="source" title="nameof(引数名)">
<code><span class="reserved">using</span> System<span class="operator">.</span>Diagnostics<span class="operator">.</span>CodeAnalysis;

<span class="comment">// C# 10 までこの属性、 NotNullIfNotNull(&quot;x&quot;) と書かないといけなくて割かしつらかった。</span>
[<span class="reserved">return</span>: <span class="type">NotNullIfNotNull</span>(<span class="reserved">nameof</span>(x))]
<span class="reserved">static</span> <span class="reserved">string</span><span class="operator">?</span> <span class="method">m</span>(<span class="reserved">string</span><span class="operator">?</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span>;
</code></pre>
<h3><a id="auto-default">構造体のフィールドの既定値初期化</a></h3>
<p>C# 11 では、構造体でもフィールドの明示的な初期化が不要になりました。
クラスと同じく、明示的に代入しなかったフィールド・自動プロパティには既定値が入ります。</p>
<pre class="source" title="構造体のフィールドが自動的に 0 初期化されるように">
<code><span class="reserved">struct</span> <span class="type struct">Sample</span>
{
    <span class="reserved">int</span> <span class="field">_x</span>;
    <span class="reserved">int</span> <span class="field">_y</span>;
    <span class="reserved">int</span> <span class="field">_z</span>;

    <span class="reserved">public</span> <span class="type struct">Sample</span>(<span class="reserved">int</span> <span class="variable local">x</span>, <span class="reserved">int</span> <span class="variable local">y</span>)
    {
        <span class="method">M</span>(); <span class="comment">// C# 11 では初期化よりも先に読んでも平気。_x, _y にもこの時点でいったん 0 が入ってる。</span>

        <span class="field">_x</span> <span class="operator">=</span> <span class="variable local">x</span>;
        <span class="field">_y</span> <span class="operator">=</span> <span class="variable local">y</span>;
        <span class="comment">// C# 11 では _z に 0 が自動で入る。</span>
    }

    <span class="reserved">void</span> <span class="method">M</span>() <span class="operator">=&gt;</span> <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="field">_x</span>}<span class="string">, </span>{<span class="field">_y</span>}<span class="string">, </span>{<span class="field">_z</span>}<span class="string">&quot;</span>);
}
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/resource/rm_struct/#auto-default">構造体</a>」や「<a href="https://ufcpp.net/study/csharp/rm_default.html#auto-default">既定値</a>」で説明します。</p>
<h3><a id="generic-attribute">ジェネリックな属性</a></h3>
<p><a href="https://ufcpp.net/study/csharp/sp_attribute.html#generic-attribute">属性をジェネリック クラスにできるようになりました</a>。</p>
<pre class="source" title="C# 11 以降">
<code><span class="comment">// 属性クラスをジェネリックにできるように。</span>
<span class="reserved">class</span> <span class="type">TypeConverter</span>&lt;<span class="type">T</span>&gt; : <span class="type">Attribute</span> { }

<span class="comment">// &lt;&gt; で型引数を指定できる。</span>
[<span class="type">TypeConverter</span>&lt;<span class="type">MyConverter</span>&gt;]
<span class="reserved">class</span> <span class="type">MyClass</span> { }
</code></pre>
<h3><a id="newline-in-interpolation">文字列補間中の改行</a></h3>
<p><a href="https://ufcpp.net/study/csharp/st_string.html#string-interpolation">文字列補間</a>で、以下のようなコードが書けるようになりました
(<code>{}</code> の中で改行を入れれるようになりました)。</p>
<pre class="source" title="{} の中の改行">
<code><span class="reserved">var</span> <span class="variable">a</span> = 1;
<span class="reserved">var</span> <span class="variable">b</span> = 2;
<span class="reserved">var</span> <span class="variable">s</span> = <span class="string">$&quot;</span><span class="string">a: </span>{
    <span class="variable">a</span> <span class="comment">// ここで改行できるのは C# 11 から</span>
    }<span class="string">, b: </span>{<span class="variable">b</span>}<span class="string">&quot;</span>;
</code></pre>
<p>ちなみに、以下のように、<code>$@</code> (文字列補間、かつ、逐語的文字列リテラル)を使う場合には C# 10.0 以前でも以下のようなコードが普通に書けました。</p>
<pre class="source" title="$@ なら10以前でもOK">
<code><span class="reserved">var</span> <span class="variable">a</span> = 1;
<span class="reserved">var</span> <span class="variable">b</span> = 2;
<span class="reserved">var</span> <span class="variable">s</span> = <span class="string">$@&quot;</span><span class="string">a: </span>{
    <span class="variable">a</span> <span class="comment">// $@ の場合は C# 10.0 以前でも OK</span>
    }<span class="string">, b: </span>{<span class="variable">b</span>}<span class="string">&quot;</span>;
</code></pre>
<p>「<code>$&quot;&quot;</code> の場合だけダメだった理由は今となっては思い出せない」というレベルだそうで、
仕様漏れ・バグ修正の類にギリギリの「新機能」になります。</p>
<h3><a id="numeric-intptr">Numeric IntPtr</a></h3>
<p>「C# の新機能」と言っていいのかどうか微妙なラインですが、
<a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver9/#nint"><code>nint</code></a> に関してちょっとした変更がありました。</p>
<p>C# 9.0 の頃には、<code>IntPtr</code>、<code>UIntPtr</code> 型に算術演算子の定義がなく、
<code>nint</code>、<code>nuint</code> に対する演算は C# コンパイラーが特別扱いすることで実装していました。
そのため、
「<code>nint</code>、<code>nuint</code> は内部的には <code>IntPtr</code>、<code>UIntPtr</code> としてコンパイルするけども、
<code>NativeInteger</code> 属性を付けて <code>nint</code>、<code>nuint</code> か <code>IntPtr</code>、<code>UIntPtr</code> を区別する」
みたいなことをしていました。</p>
<p>ところが、 .NET 7 (C# 11 と同世代)では、<a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver11/#generic-math">generic math</a> 導入に伴って、
<code>IntPtr</code>、<code>UIntPtr</code> にも算術演算子が導入されました。
その結果、C# 9.0 時代のような「特別扱い」が不要になったそうです。
そこで C# 11 では、</p>
<ul>
<li>
.NET 7 移行をターゲットにした場合、<code>NativeInteger</code> 属性を付けない
<ul>
<li>正確に言うと、<a href="https://ufcpp.net/blog/2018/12/runtimefeature/"><code>RuntimeFeature</code> クラス</a>を見て分岐</li>
</ul>
</li>
<li><code>NativeInteger</code> 属性がなくても <code>nint</code>、<code>nuint</code> と同じ扱いをする</li>
</ul>
<p>みたいな変更が掛かっています。</p>
<p>一応これが既存のコードに対する破壊的変更になる可能性があって、
例えば、以下のようなコードはこれまで例外が絶対に出なかったのが、C# 11 以降は例外が出る可能性があります。</p>
<pre class="source" title="Numeric IntPtr 関連の破壊的変更">
<span class="reserved">unsafe</span> <span class="reserved">void</span> <span class="method"><span class="warning" title="CS8321">M</span></span>(<span class="reserved">void</span><span class="operator">*</span> <span class="variable local">x</span>, <span class="reserved">int</span> <span class="variable local">y</span>)
{
    <span class="reserved">var</span> <span class="variable">p</span> <span class="operator">=</span> <span class="reserved">checked</span>((<span class="type struct">IntPtr</span>)<span class="variable local">x</span>); <span class="comment">// unsigned → singed 変換扱い</span>
    <span class="reserved">var</span> <span class="variable">z</span> <span class="operator">=</span> <span class="reserved">checked</span>(<span class="variable">p</span> + <span class="variable local">y</span>);
}
</pre>
<h3><a id="cache-static-method-group">静的メソッドをデリゲート化するときのキャッシュ化</a></h3>
<p><a href="#numeric-intptr">Numeric IntPtr</a> の話以上に「C# の新機能と言っていいのかどうか微妙」な話(文法的には何も変わっていないし、挙動も大差ない)ですが、
<code>Func&lt;int, int&gt; f = Method;</code> みたいな書き方をしたときに、デリゲートのインスタンスをキャッシュするようになりました。</p>
<p>例えば以下のようなコードを考えます。</p>
<pre class="source" title="ラムダ式と、メソッド グループからのデリゲート化の例">
<span class="comment">// この X と</span>
<span class="reserved">int</span> <span class="method">X</span>(<span class="reserved">int</span>[] <span class="variable local">data</span>) <span class="operator">=&gt;</span> <span class="variable local">data</span><span class="operator">.</span><span class="method">Sum</span>(<span class="variable local">x</span> <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="variable local">x</span>);

<span class="comment">// この Y、やってることは一緒。</span>
<span class="reserved">int</span> <span class="method">Y</span>(<span class="reserved">int</span>[] <span class="variable local">data</span>) <span class="operator">=&gt;</span> <span class="variable local">data</span><span class="operator">.</span><span class="method">Sum</span>(<span class="static"><span class="method">square</span></span>);
<span class="reserved">static</span> <span class="reserved">int</span> <span class="static"><span class="method">square</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="variable local">x</span>;
</pre>
<p>C# 10 までは、おおむね以下のようなコードに展開されていました。</p>
<pre class="source" title="C# 10 までの展開結果">
<span class="comment">// ラムダ式だと導入当初からキャッシュが効いてた。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable">_anonymous1</span> <span class="operator">=</span> <span class="reserved">null</span>;

<span class="reserved">int</span> <span class="method">X</span>(<span class="reserved">int</span>[] <span class="variable local">data</span>)
{
    <span class="comment">// こんな感じのコードに展開されてて、 new Func&lt;int, int&gt;() のアロケーションは1回限り。</span>
    <span class="variable">_anonymous1</span> <span class="operator">??=</span> <span class="reserved">new</span> <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(<span class="variable local">x</span> <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="variable local">x</span>);
    <span class="control">return</span> <span class="variable local">data</span><span class="operator">.</span><span class="method">Sum</span>(<span class="variable">_anonymous1</span>);
}

<span class="comment">// ところが、メソッド グループを直接渡した場合、都度 new Func&lt;int, int&gt;() してた(C# 10 まで)。</span>
<span class="reserved">int</span> <span class="method">Y</span>(<span class="reserved">int</span>[] <span class="variable local">data</span>)
{
    <span class="comment">// おおむねこういうコードと同じ。</span>
    <span class="reserved">var</span> <span class="variable">f</span> <span class="operator">=</span> <span class="reserved">new</span> <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(<span class="static"><span class="method">square</span></span>);
    <span class="control">return</span> <span class="variable local">data</span><span class="operator">.</span><span class="method">Sum</span>(<span class="variable">f</span>);
}
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method"><span class="static">square</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="variable local">x</span>;
</pre>
<p>メソッド グループをデリゲート化するとき(<code>Y</code> の側)、常に <code>new Func&lt;int, int&gt;()</code> のコストがかかっていました。
これが、C# 11 からは以下のような感じのコードに展開されます。</p>
<pre class="source" title="C# 11 からの展開結果">
<span class="comment">// C# 11 で、メソッド グループの場合でも、static なものはキャッシュするようになった。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable">_square</span> <span class="operator">=</span> <span class="reserved">null</span>;

<span class="reserved">int</span> <span class="method">Y</span>(<span class="reserved">int</span>[] <span class="variable local">data</span>)
{
    <span class="comment">// この類のコードになった。ラムダ式の場合のものと一緒。</span>
    <span class="variable">_square</span> <span class="operator">??=</span> <span class="reserved">new</span> <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(<span class="method"><span class="static">square</span></span>);
    <span class="control">return</span> <span class="variable local">data</span><span class="operator">.</span><span class="method">Sum</span>(<span class="variable">_square</span>);
}
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method"><span class="static">square</span></span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="variable local">x</span> <span class="operator">*</span> <span class="variable local">x</span>;
</pre>
<h3><a id="CS9029">補足: required, scoped, file キーワードと型名</a></h3>
<p>これまでずっと、C# に新しいキーワードを足したいときには、文脈キーワード(特定の状況下でだけキーワード扱いを受ける)にしてきました。</p>
<p>C# 11 で追加される <code>required</code>, <code>scoped</code>, <code>file</code> の3つも文脈キーワードです。
ただ、これらのキーワードは型名と競合しやすい位置に書くことになるので、
型名として使えてしまうと文脈からの弁別が難しくなるようで、
型名として使えなくしたようです。
以下のようにコンパイル エラーになります。</p>
<pre class="source" title="文脈キーワードな型名">
<span class="comment">// 古めの文脈キーワードはクラス名にしても警告にしかならない。</span>
<span class="comment">// 警告の出方も、古いやつは「小文字始まり ASCII のみの型名はやめて欲しい」の CS8981</span>
<span class="reserved">class</span> <span class="type"><span class="warning" title="CS8981">async</span></span> { }
<span class="reserved">class</span> <span class="type"><span class="warning" title="CS8981">await</span></span> { }
<span class="reserved">class</span> <span class="type"><span class="warning" title="CS8981">dynamic</span></span> { }

<span class="comment">// record に関しては専用の警告。CS8860。</span>
<span class="comment">// 今となっては、これもエラーでよかった説はある。</span>
<span class="reserved">class</span> <span class="type"><span class="warning" title="CS8860">record</span></span> { }

<span class="comment">// 最近の文脈キーワードはクラス名にするとエラーにするようにしたみたい。</span>
<span class="reserved">class</span> <span class="error" title="CS9029"><span class="type">required</span></span> { }
<span class="reserved">class</span> <span class="error" title="CS9062"><span class="type">scoped</span></span> { }
<span class="reserved">class</span> <span class="error" title="CS9056"><span class="type">file</span></span> { }

<span class="comment">// ちなみに、この辺りのクラス名をあえて使いたいときは @ を付けとけば OK。</span>
<span class="comment">// (警告にもならない。)</span>
<span class="reserved">class</span> <span class="type">@required</span> { }

<span class="comment">// まあ、@ を付ければ、文脈によらない通常キーワードですら名前に使えるので。</span>
<span class="reserved">class</span> <span class="type">@class</span> { }
</pre>
<h3><a id="pointer-of-managed-types">マネージ型のポインター</a></h3>
<p>C# 11 から、マネージ型のポインターを使えるようになりました。</p>
<pre class="source" title="マネージ型のポインター型/アドレス取得">
<span class="reserved">unsafe</span>
{
    <span class="reserved">string</span> <span class="variable">s</span> <span class="operator">=</span> <span class="string">&quot;&quot;</span>;
    <span class="type struct">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">x</span> <span class="operator">=</span> <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[<span class="number">4</span>];

    <span class="comment">// 以下のような型、アドレス取得はこれまではエラーになっていた。</span>
    <span class="comment">// (C# 11 以降も警告にはなる。多少の緩和があった。)</span>
    <span class="warning" title="CS8500"><span class="reserved">string</span><span class="operator">*</span></span> <span class="variable">ps</span> <span class="operator">=</span> <span class="warning" title="CS8500"><span class="operator">&amp;</span><span class="variable">s</span></span>;
    <span class="warning" title="CS8500"><span class="type struct">Span</span>&lt;<span class="reserved">byte</span>&gt;<span class="operator">*</span></span> <span class="variable">px</span> <span class="operator">=</span> <span class="warning" title="CS8500"><span class="operator">&amp;</span><span class="variable">x</span></span>;
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_unsafe.html#pointer-of-managed-types">unsafe</a>」で説明します。</p>
 ]]></description>
				<pubDate>Thu, 22 Sep 2022 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>file ローカル型</title>
				<link>http://www.ufcpp.net/study/csharp/misc/file-local/</link>
				<description><![CDATA[ <h5 class="version version11">Ver. 11</h5>
<p>C# 11 で、<code>file</code> という修飾子を使って「書いたファイル内からだけアクセスできる型」を作れるようになりました。
これを <strong id="branch" class="key-file-local-type">file ローカル型</strong> (file-local type)と言います。</p>
<p>例えば、あるファイルに以下のようなコードを書いたとします。</p>
<pre class="source" title="file 修飾付きの型を使う例">
<span class="number">1</span><span class="operator">.</span><span class="method">M</span>();

<em><span class="reserved">file</span></em> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">Extensions</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=></span> <span class="type"><span class="static">Console</span><span class="operator">.<span class="method"><span class="static">WriteLine</span></span>(<span class="variable local">x</span>);
}
</pre>
<p>これと同じプロジェクト内の別のファイルに以下のようなコードを書いてもエラーにはなりません。</p>
<pre class="source" title="別のファイルに同名の file 修飾付きの型を定義">
<em><span class="reserved">file</span></em> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">Extensions</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=></span> <span class="type"><span class="static">Console</span><span class="operator">.<span class="method"><span class="static">WriteLine</span></span>(<span class="string">"別ファイルの file-local Extensions"</span>);
}
</pre>
<p>通常、global な場所(どの名前空間にも属さない場所)に、<code>Extensions</code> なんていうよくありそうな名前のクラスを作るとすぐに名前が衝突しますが、
<code>file</code> が付いていることによって、全くの同名の型があってもコンパイルできるようになります。</p>
<h2><a id="vs-internal">private や internal と比べて</a></h2>
<p>この手の「見える範囲を制限する」系の処理の用途の1つとして、
「派生クラス・インターフェイス実装クラスを隠す」というのがあります。</p>
<p>例えば、以下のようなコードを書いて、
<code>Disposable.FromAction</code> 越しに <code>IDisposable</code> でインスタンスを返し、
実装クラスである <code>ActionDisposable</code> は直接は使わせないというようなことがしたいことがあります。</p>
<pre class="source" title="実装クラスを隠す例">
<span class="comment">// file 修飾子を付けると、このファイル内からしかアクセスできない。</span>
<span class="reserved">file</span> <span class="reserved">class</span> <span class="type">ActionDisposable</span> : <span class="type">IDisposable</span>
{
    <span class="reserved">private</span> <span class="type">Action</span> <span class="field">_disposer</span>;
    <span class="reserved">public</span> <span class="type">ActionDisposable</span>(<span class="type">Action</span> <span class="variable local">disposer</span>) <span class="operator">=></span> <span class="field">_disposer</span> <span class="operator">=</span> <span class="variable local">disposer</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() <span class="operator">=></span> <span class="field">_disposer</span>();
}

<span class="comment">// public クラスの、</span>
<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">Disposable</span></span>
{
    <span class="comment">// public メソッドで、</span>
    <span class="comment">// 戻り値は public interface なので大丈夫。</span>
    <span class="comment">// 内部でだけ file-local な型を使う。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IDisposable</span> <span class="method"><span class="static">FromAction</span></span>(<span class="type">Action</span> <span class="variable local">disposer</span>) <span class="operator">=></span> <span class="reserved">new</span> <span class="type">ActionDisposable</span>(<span class="variable local">disposer</span>);
}
</pre>
<p>こういう「隠す」用途であれば、
これまでも、<code>internal</code> や <code>private</code> でもある程度代用できました。</p>
<p><code>private</code> の例:</p>
<pre class="source" title="private で実装を隠す例">
<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">Disposable</span></span>
{
    <span class="comment">// private にしておけば Disposable クラスの外からは触れない。</span>
    <span class="reserved">private</span> <span class="reserved">class</span> <span class="type">ActionDisposable</span> : <span class="type">IDisposable</span>
    {
        <span class="reserved">private</span> <span class="type">Action</span> <span class="field">_disposer</span>;
        <span class="reserved">public</span> <span class="type">ActionDisposable</span>(<span class="type">Action</span> <span class="variable local">disposer</span>) <span class="operator">=></span> <span class="field">_disposer</span> <span class="operator">=</span> <span class="variable local">disposer</span>;
        <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() <span class="operator">=></span> <span class="field">_disposer</span>();
    }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IDisposable</span> <span class="method"><span class="static">FromAction</span></span>(<span class="type">Action</span> <span class="variable local">disposer</span>) <span class="operator">=></span> <span class="reserved">new</span> <span class="type">ActionDisposable</span>(<span class="variable local">disposer</span>);
}
</pre>
<p><code>internal</code> の例:</p>
<pre class="source" title="internal で実装を隠す例">
<span class="comment">// internal にしておけば別プロジェクトからは触れない。</span>
<span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">ActionDisposable</span> : <span class="type">IDisposable</span>
{
    <span class="reserved">private</span> <span class="type">Action</span> <span class="field">_disposer</span>;
    <span class="reserved">public</span> <span class="type">ActionDisposable</span>(<span class="type">Action</span> <span class="variable local">disposer</span>) <span class="operator">=></span> <span class="field">_disposer</span> <span class="operator">=</span> <span class="variable local">disposer</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() <span class="operator">=></span> <span class="field">_disposer</span>();
}

<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">Disposable</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IDisposable</span> <span class="method"><span class="static">FromAction</span></span>(<span class="type">Action</span> <span class="variable local">disposer</span>) <span class="operator">=></span> <span class="reserved">new</span> <span class="type">ActionDisposable</span>(<span class="variable local">disposer</span>);
}
</pre>
<p>多くの場合はこれらで十分ですし、
C# 10 以前ではこれでしのいできました。</p>
<p>ただ、問題になったのが <a href="https://ufcpp.net/study/csharp/misc/analyzer-generator/#analyzer">Source Generator</a> によるコード生成です。
コード生成でクラスを生成したい場合、</p>
<ul>
<li>
複数の Source Generator によって「名前の取り合い」が起きかねない
<ul>
<li>1つのクラスに対して複数の Source Generator を掛けるとき、たとえ <code>private</code> でコード生成しても名前が被る可能性がある</li>
<li>もし異なる作者の Source Generator で名前が被った場合、解決のしようがない</li>
</ul>
</li>
<li>Source Generator のアップデート時にクラス名を変えたり、クラス自体を消したりしたいことがある</li>
</ul>
<p>という懸念・要求が出てきました。
<code>file</code> 修飾子によって得られるのは、この「他とは絶対に名前の取り合いにならない型名」になります。</p>
<p>ということで、<code>file</code> 修飾子があって一番うれしい用途は Source Generator です。
実際これは、.NET 6 で追加された <code>Regex</code> の Source Generator 対応(<code>GeneratedRegex</code>)から出て来た要望で、
<code>GeneratedRegex</code> は .NET 7 で早速この <code>file</code> 修飾子を使ったコード生成をするようになりました。</p>
<pre class="source" title="GeneratedRegex の例">
<span class="reserved">using</span> System<span class="operator">.</span>Text<span class="operator">.</span>RegularExpressions;

<span class="reserved">namespace</span> FileLocal;

<span class="reserved">internal</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">R</span>
{
    <span class="comment">// file 修飾子、Source Generator で使う需要が高い。</span>
    <span class="comment">// 例えば、GeneratedRegex は早速(.NET 7 から)使ってる。</span>
    [<span class="type">GeneratedRegex</span>(<span class="string">@"\d+"</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="type">Regex</span> <span class="method"><span class="static">M</span></span>();

    <span class="comment">// ↑このメソッドから、</span>
    <span class="comment">// file sealed class M_0 : Regex { } みたいなクラスが作られてる。</span>
}
</pre>
<h2><a id="applicable">適用範囲</a></h2>
<p><code>file</code> 修飾子は型にのみ適用できます。
以下のように、フィールドやメソッドなどに使おうとするとコンパイル エラーになります。</p>
<pre class="source" title="file は型のみ">
<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">file</span> <span class="reserved">int</span> <span class="field"><span class="error" title="CS0106">_x</span></span>;

    <span class="reserved">file</span> <span class="reserved">int</span> <span class="method"><span class="error" title="CS0106">M</span></span>() <span class="operator">=></span> <span class="field">_x</span>;
}
</pre>
<p>一方、型であれば何でもよくて、インターフェイス、列挙型、デリゲートなどにも使えます。
以下のコードはいずれも問題なくコンパイルできます。</p>
<pre class="source" title="型なら何でも file を付けれる">
<span class="reserved">file</span> <span class="reserved">interface</span> <span class="type">IA</span> { }
<span class="reserved">file</span> <span class="reserved">enum</span> <span class="type">E</span> { }
<span class="reserved">file</span> <span class="reserved">delegate</span> <span class="reserved">void</span> <span class="type">D</span>();
<span class="reserved">file</span> <span class="reserved">struct</span> <span class="type struct">S</span> { }
<span class="reserved">file</span> <span class="reserved">record</span> <span class="type">R</span>;</span>
<span class="reserved">file</span> <span class="reserved">record</span> <span class="reserved">struct</span> <span class="type struct">RS</span>;
</pre>
<p>インターフェイスであれば、file ローカルなインターフェイスを <code>public</code> な型で実装することもできます。
これを使って、「file ローカルなメソッド」の代用にはなったりします。</p>
<pre class="source" title="file ローカルなインターフェイスを public なクラスで実装する例">
<span class="comment">// file ローカルなインターフェイスも OK だし、</span>
<span class="comment">// それを public な型で実装するのも OK。</span>

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">CX</span> : <span class="type">IX</span> <span class="comment">// OK</span>
{
    <span class="comment">// file ローカルなインターフェイス で明示的実装しておけば実質 file ローカルなメソッドになる。</span>
    <span class="comment">// (ちなみに、別に明示的実装でなく普通に実装しても OK)。</span>
    <span class="reserved">void</span> <span class="type">IX</span><span class="operator">.</span><span class="method">M</span>() { }
}

<span class="reserved">file</span> <span class="reserved">interface</span> <span class="type">IX</span>
{
    <span class="reserved">void</span> <span class="method">M</span>();
}
</pre>
<p>また、<code>file</code> 修飾子は<a href="https://ufcpp.net/study/csharp/oo_conceal.html#level">アクセシビリティ修飾子</a>と同時に使うことはできません。
例えば以下のコードはコンパイル エラーになります。</p>
<pre class="source" title="アクセシビリティとの併用不可">
<em><span class="reserved">internal</span> <span class="reserved">file</span></em> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static"><span class="error" title="CS9052">X</span></span></span>
{
}
</pre>
<p>さらに、 <code>file</code> 修飾子は top-level (global な場所、もしくは、名前空間直下)の型にしか使えません。
言い換えると、入れ子の型は file ローカルにできません。
以下のコードはコンパイル エラーになります。</p>
<pre class="source" title="入れ子の型不可">
<span class="reserved">class</span> <span class="type">A</span>
{
    <em><span class="reserved">file</span></em> <span class="reserved">class</span> <span class="type"><span class="error" title="CS9054">NestedFileClass</span></span>
    {
    }
}</pre>
<h2><a id="implementation">内部実装</a></h2>
<p>file ローカルな型のコンパイル結果は、
C# にはよくある「通常の C# からは参照できない名前」(unspeakable name)に変換されます。
名前付けのルールは仕様化されていなくて、「常に同じ名前で生成される保証はない」とされています。
(この辺りは unspeakable name を生成する他の言語機能も同じです。)</p>
<p>現在の file ローカル型の名前付けでは、
ファイル名と連番が入った「<code>&lt;file_name&gt;f1_ClassName</code>」みたいな名前で生成されています。
file ローカル型の存在意義的に、「プロジェクト全体で一意な名前」であれば十分なはずで、
連番だけでも目的は果たせていそうです。
型名にファイル名が入ってるのはおそらくデバッグ時にスタックトレースを見やすくするためなど、付加的な目的だと思われます。</p>
 ]]></description>
				<pubDate>Thu, 25 Aug 2022 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>【Generic Math】 C# 11 での演算子の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/oop/generic-math-operators/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<h5 class="version version11">Ver. 11</h5>
<p>C# 11 で、数値型の演算子関連で3つ新機能が追加されています。</p>
<ul>
<li><a href="#unsigned-right-shift">符号なし右シフト</a></li>
<li><a href="#checked-operator-overload">checked 演算子オーバーロード</a></li>
<li><a href="#relaxing-shift">シフト演算子の右オペランドの制限撤廃</a></li>
</ul>
<h2><a id="generic-math">背景: Generic Math</a></h2>
<p>C# 11 / .NET 7 でインターフェイスの静的メンバーを仮想・抽象にできる (static abstract members in interfaces)ようになります。
(この機能自体については「<a href="https://ufcpp.net/study/csharp/oo_interface.html?p=6#static-abstract">インターフェイスの静的抽象メンバー</a>」で説明しています。)</p>
<p>この機能の一番の用途は、数値型(<code>int</code> や <code>float</code> など)に対するアルゴリズムを<a href="https://ufcpp.net/study/csharp/sp2_generics.html">ジェネリクス</a>を使って書けるようにすることです。
例えば、以下のようなコードが書けるようになりました。</p>
<pre class="source" title="ジェネリックに「和を取る」コードを書けるように">
<code><span class="reserved">using</span> System.Numerics;

<span class="comment">// よくある「和を取るコード」なものの、</span>
<span class="comment">// これまでだとジェネリックに書く手段がなかった。</span>
<span class="comment">// C# 11 で可能に。</span>
<span class="comment">// (T.Zero や、T に対する + 演算子の定義ができるように)</span>
<span class="reserved">static</span> <span class="type">T</span> <span class="method">sum</span>&lt;<span class="type">T</span>&gt;(<span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; <span class="variable">items</span>)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">INumber</span>&lt;<span class="type">T</span>&gt;
{
    <span class="reserved">var</span> <span class="variable">sum</span> = <span class="type">T</span>.Zero;
    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">items</span>) <span class="variable">sum</span> += <span class="variable">x</span>;
    <span class="control">return</span> <span class="variable">sum</span>;
}

<span class="comment">// いろんな型に対して sum&lt;T&gt; を呼ぶ。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">sum</span>(<span class="reserved">new</span> <span class="reserved">byte</span>[] { 1, 2, 3, 4, 5 }));
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">sum</span>(<span class="reserved">new</span> <span class="reserved">int</span>[] { 1, 2, 3, 4, 5 }));
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">sum</span>(<span class="reserved">new</span> <span class="reserved">float</span>[] { 1, 2, 3, 4, 5 }));
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">sum</span>(<span class="reserved">new</span> <span class="reserved">double</span>[] { 1, 2, 3, 4, 5 }));
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">sum</span>(<span class="reserved">new</span> <span class="reserved">decimal</span>[] { 1, 2, 3, 4, 5 }));
</code></pre>
<p>加減乗除や論理演算はもちろん、<code>float</code> などの一部の型は <code>Math.Sin</code> などの数学関数も使えます。
コンセプト的に、この新機能を使ったジェネリックな数値処理の事を Generic Math と呼んでいたりします。</p>
<p>また、 .NET 5 以降、数値関連の型がいくつか追加されています。</p>
<ul>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.half?WT.mc_id=DT-MVP-4028921"><code>Half</code></a>: 16ビット浮動小数点数</li>
<li><a href="https://github.com/dotnet/runtime/issues/67151"><code>Int128</code>, <code>UInt128</code></a>: 128ビットの整数</li>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.clong?WT.mc_id=DT-MVP-4028921"><code>CLong</code></a>, <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.culong?WT.mc_id=DT-MVP-4028921"><code>CULong</code></a>: C/C++ との相互運用のために使う、環境によってビット幅が違う整数</li>
<li><a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver9/#nint"><code>nint</code>, <code>nuint</code></a>: CPU 依存幅の整数</li>
</ul>
<p>これらの新しい数値型も、Generic Math の対象で、<code>INumber&lt;T&gt;</code> などのインターフェイスを実装しています。</p>
<p>この Generic Math と関連して、数値型の演算子関連で細々とした機能がいくつか追加されています。</p>
<ul>
<li>符号なし右シフト</li>
<li>checked 演算子オーバーロード</li>
<li>シフト演算子の右オペランドの制限撤廃</li>
</ul>
<h2><a id="unsigned-right-shift">符号なし右シフト</a></h2>
<p>右シフト演算には符号付き右シフト(算術シフト)と符号なし右シフト(論理シフト)があって、
右シフトしたときに、最上位ビットの 1 が残るかどうかの差になります。</p>
<p>C# の場合、基本的に、</p>
<ul>
<li>符号<em>付き</em>整数の右シフトは符号<em>付き</em>右シフト(算術シフト)</li>
<li>符号<em>なし</em>整数の右シフトは符号<em>なし</em>右シフト(論理シフト)</li>
</ul>
<p>という方式で右シフトの方式を切り替えます。</p>
<pre class="source" title="右シフトの符号のありなし">
<code><span class="comment">// 符号なし (unsigned) の 0xFF = 255</span>
<span class="reserved">byte</span> <span class="variable">u</span> = 0xFF;

<span class="comment">// 符号付き (signed) の 0xFF = -1</span>
<span class="reserved">sbyte</span> <span class="variable">s</span> = (<span class="reserved">sbyte</span>)<span class="variable">u</span>;

<span class="comment">// 符号なしを右シフトすると、左端には 0 が入る。</span>
<span class="comment">// FF → 7F → 3F → 1F → F → 7 → 3 → 1</span>
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 8; <span class="variable">i</span>++)
{
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">u</span>:<span class="string">X</span>}<span class="string">&quot;</span>);
    <span class="variable">u</span> &gt;&gt;= 1;
}

<span class="comment">// 符号なしを右シフトすると、左端のビットが残る。</span>
<span class="comment">// 元が FF だとずっと FF。</span>
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 8; <span class="variable">i</span>++)
{
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">s</span>:<span class="string">X</span>}<span class="string">&quot;</span>);
    <span class="variable">s</span> &gt;&gt;= 1;
}
</code></pre>
<p>右シフトの符号あり/なしを切り替えたい場合、キャストが必要でした。</p>
<pre class="source" title="byte にキャストしてから右シフトすることで論理シフトに">
<code><span class="reserved">sbyte</span> <span class="variable">s</span> = -1;

<span class="comment">// LogicalRightShift を呼んでいるので、符号なし右シフトになる。</span>
<span class="comment">// FF → 7F → 3F → 1F → F → 7 → 3 → 1</span>
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 8; <span class="variable">i</span>++)
{
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">s</span>:<span class="string">X</span>}<span class="string">&quot;</span>);
    <span class="variable">s</span> = <span class="method">LogicalRightShift</span>(<span class="variable">s</span>, 1);
}

<span class="comment">// 右シフトの符号のあり/なしを切り替えたい場合、キャストを挟む。</span>
<span class="reserved">static</span> <span class="reserved">sbyte</span> <span class="method">LogicalRightShift</span>(<span class="reserved">sbyte</span> <span class="variable">s</span>, <span class="reserved">int</span> <span class="variable">bits</span>)
    =&gt; (<span class="reserved">sbyte</span>)((<span class="reserved">byte</span>)<span class="variable">s</span> &gt;&gt; <span class="variable">bits</span>);
</code></pre>
<p>この方式は、Generic Math の導入に伴って1つ問題がありました。
「型引数 <code>T</code> に対応する符号なしな型」を取得する手段がありません。</p>
<pre class="source" title="unsinged generic T を取る手段がない">
<code><span class="comment">// 符号なしシフトにしたかったらどうすれば？？？</span>
<span class="reserved">static</span> <span class="type">T</span> <span class="method">LogicalRightShift</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">s</span>, <span class="reserved">int</span> <span class="variable">bits</span>)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">IShiftOperators</span>&lt;<span class="type">T</span>,<span class="type">T</span>&gt;
    =&gt; (<span class="type">T</span>)((<span class="comment">/* unsigned T を取得したいけど手段がない */</span>)<span class="variable">s</span> &gt;&gt; bits);
</code></pre>
<p>そこで、C# 11 では普通に「符号なし右シフト演算子」の <code>&gt;&gt;&gt;</code> (<code>&gt;</code> 3つ)を導入することにしました。
(Java にあるやつです。Java の場合は <code>uint</code> などの符号なし整数型がなくて、<code>&gt;&gt;</code> か <code>&gt;&gt;&gt;</code> で右シフトを切り替えます。)</p>
<pre class="source" title="C# にも符号なし右シフト演算子を導入">
<code><span class="reserved">using</span> System.Numerics;

<span class="reserved">sbyte</span> <span class="variable">s</span> = -1;

<span class="comment">// ちゃんと符号なし右シフトに。</span>
<span class="comment">// FF → 7F → 3F → 1F → F → 7 → 3 → 1</span>
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 8; <span class="variable">i</span>++)
{
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">s</span>:<span class="string">X</span>}<span class="string">&quot;</span>);
    <span class="variable">s</span> = <span class="method">LogicalRightShift</span>(<span class="variable">s</span>, 1);
}

<span class="comment">// &gt;&gt;&gt; でどの型に対しても符号なし右シフト。</span>
<span class="reserved">static</span> <span class="type">T</span> <span class="method">LogicalRightShift</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">s</span>, <span class="reserved">int</span> <span class="variable">bits</span>)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">IShiftOperators</span>&lt;<span class="type">T</span>,<span class="type">T</span>&gt;
    =&gt; <span class="variable">s</span> <em>&gt;&gt;&gt;</em> <span class="variable">bits</span>;
</code></pre>
<p>ちなみに、演算子オーバーロードもできます。</p>
<pre class="source" title="&gt;&gt;&gt; 演算子オーバーロードの例">
<code><span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 4; <span class="variable">i</span>++)
{
    <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">Int2Bit</span>(<span class="variable">i</span>);

    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span><span class="string">for </span>{<span class="variable">x</span>}<span class="string">&quot;</span>);

    <span class="control">for</span> (<span class="reserved">int</span> <span class="variable">j</span> = 0; <span class="variable">j</span> &lt;= 2; <span class="variable">j</span>++)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">j</span>}<span class="string"> bit signed: </span>{<span class="variable">x</span> &gt;&gt; <span class="variable">j</span>}<span class="string">, unsigned: </span>{<span class="variable">x</span> &gt;&gt;&gt; <span class="variable">j</span>}<span class="string">&quot;</span>);
    }
}

<span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type">Int2Bit</span>
{
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">byte</span> Value;
    <span class="reserved">public</span> <span class="type">Int2Bit</span>(<span class="reserved">int</span> <span class="variable">value</span>) =&gt; Value = (<span class="reserved">byte</span>)(<span class="variable">value</span> &amp; 0b11);
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() =&gt; Value.<span class="method">ToString</span>();

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Int2Bit</span> <span class="reserved">operator</span> &gt;&gt;(<span class="type">Int2Bit</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>) =&gt; <span class="reserved">new</span>(<span class="variable">x</span>.Value &gt;&gt; <span class="variable">y</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Int2Bit</span> <span class="reserved">operator</span> <em>&gt;&gt;&gt;</em>(<span class="type">Int2Bit</span> x, <span class="reserved">int</span> y) =&gt; <span class="reserved">new</span>(ExtendSign(x.Value) &gt;&gt; y);
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">ExtendSign</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> &gt;= 0b10 ? (-4 | <span class="variable">x</span>) : <span class="variable">x</span>;
}
</code></pre>
<h2><a id="checked-operator-overload">checked 演算子オーバーロード</a></h2>
<p>C# では、<a href="https://ufcpp.net/study/csharp/sp_checked.html">整数演算のオーバーフロー時に何もしないか、それとも例外を投げるかを選べる機能</a>があります。</p>
<ul>
<li><code>checked</code> コンパイラー オプション: プログラム全域でオーバーフローを例外にする</li>
<li><code>checked</code> ブロック: ブロック中のオーバーフローを例外にする</li>
<li><code>checked</code> 式: <code>checked()</code> の <code>()</code> の中に書いた式でオーバーフローを例外にする</li>
</ul>
<p>いずれにせよ <code>checked</code> というオプション名/キーワードを使います。
これが付いている状況を「<code>checked</code> コンテキスト」と言い、
<code>checked</code> コンテキストでの演算(要するに例外が出る演算)を 「<code>checked</code> 演算」と言います。</p>
<p>逆に、<code>unchecked</code> というキーワードで、
「例外を出さない」状態に戻せて、これを「<code>unchecked</code> コンテキスト」、「<code>unchecked</code> 演算」と言います。
(何も指定がない場合の既定動作は <code>unchecked</code> コンテキストになります。)</p>
<p>ちなみに、投げられる例外は <code>OverflowException</code> 型です。</p>
<pre class="source" title="checked 演算の例">
<code><span class="reserved">byte</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">128</span>;
<span class="reserved">byte</span> <span class="variable">y</span> <span class="operator">=</span> <span class="number">128</span>;

<span class="comment">// unchecked 演算。</span>
<span class="comment">// (特にオプション指定がない場合、x + y はこの意味。)</span>
<span class="comment">// 128 + 128 = 256 なものの、オーバーフローして 0 に。</span>
<span class="reserved">var</span> <span class="variable">z</span> <span class="operator">=</span> <span class="reserved">unchecked</span>(<span class="variable">x</span> <span class="operator">+</span> <span class="variable">y</span>);

<span class="comment">// checked 演算。</span>
<span class="comment">// Overflow 例外が出る。</span>
<span class="reserved">var</span> <span class="variable">w</span> <span class="operator">=</span> <span class="reserved">checked</span>(<span class="variable">x</span> <span class="operator">+</span> <span class="variable">y</span>);

<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>((<span class="variable">w</span>, <span class="variable">z</span>));
</code></pre>
<p>C# 10 以前では、<code>checked</code> な演算ができるのは組み込み整数だけでした。
ユーザー定義で <code>int</code> などに準ずる型を作ろうとしても、<code>cheched</code>/<code>unchecked</code> の切り替えはできません。</p>
<p>「<code>int</code> などに準ずる型」をどのくらいの頻度で作るかと言われるとあまりなかったりはするんですが…
ちょうど最近(.NET 7 で)、<code>Int128</code>/<code>UInt128</code> という型が標準ライブラリに追加されています。</p>
<p>また、generic math でも <code>checked</code> を使えるようにしたいしたいです。</p>
<pre class="source" title="generic に checked 演算をやりたい例">
<code><span class="comment">// 例外が出るべき。</span>
<span class="method">CheckedAdd</span>&lt;<span class="reserved">byte</span>&gt;(<span class="number">128</span>, <span class="number">128</span>);

<span class="reserved">static</span> <span class="type param">T</span> <span class="method">CheckedAdd</span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span> <span class="variable local">x</span>, <span class="type param">T</span> <span class="variable local">y</span>)
    <span class="reserved">where</span> <span class="type param">T</span> : <span class="reserved">struct</span>, System<span class="operator">.</span>Numerics<span class="operator">.</span><span class="type">IAdditionOperators</span>&lt;<span class="type param">T</span>, <span class="type param">T</span>, <span class="type param">T</span>&gt;
{
    <span class="comment">// 例外を出したい。</span>
    <span class="control">return</span> <span class="reserved">checked</span>(<span class="variable local">x</span> + <span class="variable local">y</span>);
}
</code></pre>
<p>これまでのように、組み込み型でだけ例外を出せるということになってしまうと、</p>
<ul>
<li>generic に書き換える手段がなくなる</li>
<li>「今現在ライブラリ実装なもの(例えば <code>Int128</code>)が将来的に組み込み型になる」みたいなことをやりにくくなる</li>
</ul>
<p>ということになります。</p>
<p>そこで、C# 11 ではユーザー定義の <code>checked</code> 演算子オーバーロードを書けるようにしました。
構文としては、</p>
<ul>
<li>
<code>operator</code> キーワードの<em>後ろ</em>に <code>checked</code> を付ける
<ul>
<li><code>checked</code> コンテキストで演算子を書いた時に呼ばれる</li>
<li>これを便宜上、「checked 演算子」と呼ぶ</li>
</ul>
</li>
<li>
<code>unchecked</code> コンテキストで呼ばれて欲しい方には今まで通り何も付けない(<code>operator</code> だけ)
<ul>
<li>「<code>checked</code> 演算子」との区別が必要な場合はわざわざ「普通の(regular)演算子」と呼ぶ</li>
</ul>
</li>
</ul>
<p>となります。</p>
<p>例えば、前節の符号なし右シフトでも使った「2ビット整数」を例に、とりあえず加算演算を書くなら以下のようになります。</p>
<pre class="source" title="checked 演算子オーバーロードの例">
<code><span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type struct">Int2Bit</span>
{
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">byte</span> <span class="field">Value</span>;
    <span class="reserved">public</span> <span class="type struct">Int2Bit</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="field">Value</span> <span class="operator">=</span> (<span class="reserved">byte</span>)(<span class="variable local">value</span> <span class="operator">&amp;</span> <span class="number">0b11</span>);
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() <span class="operator">=&gt;</span> <span class="field">Value</span><span class="operator">.</span><span class="method">ToString</span>();

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">Int2Bit</span> <span class="method">Checked</span>(<span class="reserved">int</span> <span class="variable local">value</span>) <span class="operator">=&gt;</span> <span class="variable local">value</span> <span class="reserved">is</span> <span class="operator">&lt;</span> <span class="number">2</span> <span class="reserved">and</span> <span class="operator">&gt;=</span> <span class="number">0</span> <span class="operator">?</span> <span class="reserved">new</span>(<span class="variable local">value</span>) <span class="operator">:</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">OverflowException</span>();

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">Int2Bit</span> <span class="reserved">operator</span> <span class="operator">+</span>(<span class="type struct">Int2Bit</span> <span class="variable local">x</span>, <span class="type struct">Int2Bit</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">new</span>(<span class="variable local">x</span><span class="operator">.</span><span class="field">Value</span> <span class="operator">+</span> <span class="variable local">y</span><span class="operator">.</span><span class="field">Value</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">Int2Bit</span> <span class="reserved">operator</span> <span class="reserved"><em>checked</em></span> <span class="operator">+</span>(<span class="type struct">Int2Bit</span> <span class="variable local">x</span>, <span class="type struct">Int2Bit</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="method">Checked</span>(<span class="variable local">x</span><span class="operator">.</span><span class="field">Value</span> <span class="operator">+</span> <span class="variable local">y</span><span class="operator">.</span><span class="field">Value</span>);
}
</code></pre>
<p><code>checked</code> 演算子を定義できるのは算術演算系の演算子だけです。
例えば <code>+</code> や <code>-</code> は <code>checked</code> にできますが、<code>&amp;</code> や <code>!</code> はできません。</p>
<p>「<code>checked</code> だけでなく <code>unchecked</code> も明示的に書けるようにするかどうか」みたいなことも検討されたんですが、経験上「ほとんどの人が <code>unchecked</code> なコードしか書かない」という事がわかっているので、
「<code>checked</code> だけ追加して、何も書かない場合(regular)を <code>unchecked</code> 扱い」ということになっています。</p>
<h3><a id="checked-only">注意: checked 演算子のみの定義はエラー</a></h3>
<p>ちなみに、通常演算子なしで <code>checked</code> 演算子だけを定義することはできません。</p>
<pre class="source" title="checked のみの定義はコンパイル エラーになる">
<code><span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="comment">// OK: 通常演算子のみ</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="operator">+</span>(<span class="type struct">A</span> <span class="variable local">x</span>, <span class="type struct">A</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;

    <span class="comment">// OK: 通常演算子、checked 演算子両方</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="operator">-</span>(<span class="type struct">A</span> <span class="variable local">x</span>, <span class="type struct">A</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator">-</span>(<span class="type struct">A</span> <span class="variable local">x</span>, <span class="type struct">A</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;

    <span class="comment">// コンパイル エラー: checked 演算子のみ</span>
    <span class="comment">// public static A operator *(A x, A y) =&gt; default; // この行もあれば OK。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="operator"><span class="error">*</span></span>(<span class="type struct">A</span> <span class="variable local">x</span>, <span class="type struct">A</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
}
</code></pre>
<h3><a id="checked-cast">注意: キャスト演算</a></h3>
<p><a href="https://ufcpp.net/study/csharp/oo_operator.html#cast">キャスト</a>も <code>checked</code> にできます。
ただし、<code>explicit</code> (明示的型変換)のみ OK で、<code>implicit</code> (暗黙的型変換)には <code>checked</code> は使えません。</p>
<pre class="source" title="">
<code><span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="comment">// OK: explicit キャスト</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">explicit</span> <span class="reserved">operator</span> <span class="type struct">A</span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">explicit</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="type struct">A</span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;

    <span class="comment">// OK: 通常演算子、checked 演算子両方</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="type struct">A</span>(<span class="reserved">float</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>; <span class="comment">// これは大丈夫</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="error"><span class="reserved">checked</span> <span class="type struct">A</span></span>(<span class="reserved">float</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>; <span class="comment">// これはダメ</span>
}
</code></pre>
<h3><a id="checked-responsibility">注意: あくまでユーザー裁量</a></h3>
<p>あくまでユーザー定義なので、悪意を持って実装すれば「通常演算子で例外を投げて、checked 演算子で投げない」みたいなこともできてしまいます。</p>
<pre class="source" title="逆に実装">
<code><span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="comment">// なぜかこっちが例外を出して</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">explicit</span> <span class="reserved">operator</span> <span class="type struct">A</span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="control">throw</span> <span class="reserved">new</span> <span class="type">OverflowException</span>();

    <span class="comment">// こっちが出さない実装をしても別に怒られない…</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">explicit</span> <span class="reserved">operator</span> <span class="reserved">checked</span> <span class="type struct">A</span>(<span class="reserved">int</span> <span class="variable local">x</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
}
</code></pre>
<p>そこの禁止まではしてないので注意してください。</p>
<h3>コンパイル結果</h3>
<p>(<code>&gt;&gt;&gt;</code> のとこにも同様の話を)</p>
<p>通常演算子は <code>op_Addition</code> みたいな名前のメソッドになってる。</p>
<p>checked 演算子は <code>op_AdditionChecked</code> みたいに、通常演算子の後ろに <code>Checked</code> が付いた名前に</p>
<h2><a id="relaxing-shift">シフト演算子の右オペランドの制限撤廃</a></h2>
<p>C# ではこれまで、シフト演算子の右オペランド(何ビットシフトするかを決める方)には <code>int</code> しか使えないという制限がありました。
<code>&lt;&lt;</code> や <code>&gt;&gt;</code> という記号をシフト以外の意味で使わせるつもりはないのと、
であれば、シフトの右オペランドに <code>int</code> 以外のものを使いたい場面がほとんどないためです。</p>
<p>例えば、以下のコードはコンパイル エラーになります。
「1.1 ビットのシフト」とか言われても意味が解らないので、まあこれは妥当な制限でしょう。</p>
<pre class="source" title="右オペランドが整数じゃないのでエラー">
<code><span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">1</span> <span class="error"><span class="operator">&lt;&lt;</span> <span class="number">1.1</span></span>;
</code></pre>
<p>ただ、以下のようなコードもコンパイル エラーになります。
右オペランドが <code>uint</code> や <code>long</code> の場合ですら制限されていて、
ちょっと厳しい感じがします。</p>
<pre class="source" title="U や L がついてもダメ">
<code><span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="error"><span class="number">1</span> <span class="operator">&lt;&lt;</span> <span class="number">1U</span></span>;
<span class="reserved">var</span> <span class="variable">y</span> <span class="operator">=</span> <span class="error"><span class="number">1</span> <span class="operator">&lt;&lt;</span> <span class="number">1L</span></span>;
</code></pre>
<p>必要かと言われると別に要らないので、厳しかろうと誰も文句は言わなかったんですが。</p>
<p>ところがここに来て、generic math が入りました。
generic math で使えるメソッドの中にはシフト演算の右オペランドで使えそうなものがいくつかあったりします。
例えば、<code>LeadingZeroCount</code> や <code>TrailingZeroCount</code> などが代表例でが、
これらの戻り値は <code>int</code> ではなく、<code>TSelf</code> (型引数になっている型)です。</p>
<pre class="source" title="シフト演算の右オペランドに使えそうな値を返す generic math メソッド">
<code><span class="reserved">using</span> System<span class="operator">.</span>Numerics;

<span class="method">M</span>&lt;<span class="reserved">byte</span>&gt;(<span class="number">0x8</span>);
<span class="method">M</span>&lt;<span class="reserved">byte</span>&gt;(<span class="number">0xF</span>);
<span class="method">M</span>&lt;<span class="reserved">byte</span>&gt;(<span class="number">0x10</span>);
<span class="method">M</span>&lt;<span class="reserved">byte</span>&gt;(<span class="number">0x30</span>);

<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>&lt;<span class="type param">T</span>&gt;(<span class="type param">T</span> <span class="variable local">x</span>)
    <span class="reserved">where</span> <span class="type param">T</span> : <span class="type">IBinaryInteger</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="comment">// pop count = 1 になっているビットの個数を求める関数。</span>
    <span class="type param">T</span> <span class="variable">count</span> <span class="operator">=</span> <span class="type param">T</span><span class="operator">.</span><span class="method">PopCount</span>(<span class="variable local">x</span>);

    <span class="comment">// leading zero count = 上位ビットに 0 が何個並んでいるか。</span>
    <span class="type param">T</span> <span class="variable">leading</span> <span class="operator">=</span> <span class="type param">T</span><span class="operator">.</span><span class="method">LeadingZeroCount</span>(<span class="variable local">x</span>);

    <span class="comment">// trailing zero count = 下位ビットに 0 が何個並んでいるか。</span>
    <span class="type param">T</span> <span class="variable">trailing</span> <span class="operator">=</span> <span class="type param">T</span><span class="operator">.</span><span class="method">TrailingZeroCount</span>(<span class="variable local">x</span>);

    <span class="comment">// これらの戻り値が int ではなく T (ジェネリック)。</span>
    <span class="comment">// こういう「ビット数」系の値はシフト演算の右オペランドで使うことがある。</span>

    <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>((<span class="variable">count</span>, <span class="variable">leading</span>, <span class="variable">trailing</span>));
}
</code></pre>
<p>これにより、「シフト演算の右オペランドは <code>int</code> だけでいい」という前提が崩れました。</p>
<p>まあ、元が厳しすぎたという話なので、C# 11 で制限を撤廃することになりました。
以下のようなコードが認められるようになっています。</p>
<pre class="source" title="C# 11 で operator &lt;&lt;(A x, A y) とかが書けるように">
<code><span class="reserved">struct</span> <span class="type struct">A</span>
{
    <span class="comment">// C# 10 以前でも書けるオーバーロード。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="operator">&lt;&lt;</span>(<span class="type struct">A</span> <span class="variable local">x</span>, <span class="reserved">int</span> <span class="variable local">y</span>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;

    <span class="comment">// C# 11 以降でだけ書けるオーバーロード。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">A</span> <span class="reserved">operator</span> <span class="operator">&lt;&lt;</span>(<span class="type struct">A</span> <span class="variable local">x</span>, <em><span class="type struct">A</span> <span class="variable local">y</span></em>) <span class="operator">=&gt;</span> <span class="reserved">default</span>;
}
</code></pre>
<h3><a id="shift-guideline">注意: シフト以外の用途で &lt;&lt; を使わせたくはない</a></h3>
<p>思想的な話でいうと、
「<code>&lt;&lt;</code> や <code>&gt;&gt;</code> という記号をシフト以外の意味で使わせるつもりはない」という方針はこれまで通りです。</p>
<p>ただ、構文的な制限はなくなったので、
思想に反するコードも書けるようになっています。
例えば以下のように、悪名高い「<code>&lt;&lt;</code> を &quot;write&quot; とか &quot;append&quot; 的な意味で使う」みたいなこともできます。</p>
<pre class="source" title="某言語的な &lt;&lt;">
<code><span class="reserved">using</span> <span class="reserved">static</span> <span class="type">Iostream</span>;

<span class="comment">// C# の思想的には書かせたくないコードの例。</span>
<span class="comment">// 書けてしまうように。</span>
<span class="reserved">_</span> <span class="operator">=</span> <em><span class="field">cout</span> &lt;&lt; <span class="string">&quot;Hellow World!&quot;</span> &lt;&lt; <span class="field">endl</span></em>;

<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Iostream</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">readonly</span> <span class="type struct">ConsoleOut</span> <span class="field">cout</span> <span class="operator">=</span> <span class="reserved">new</span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">readonly</span> <span class="type struct">ConsoleEndLine</span> <span class="field">endl</span> <span class="operator">=</span> <span class="reserved">new</span>();

    <span class="reserved">public</span> <span class="reserved">struct</span> <span class="type struct">ConsoleOut</span>
    {
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">ConsoleOut</span> <span class="reserved">operator</span> <span class="operator">&lt;&lt;</span>(<span class="type struct">ConsoleOut</span> <span class="variable local">x</span>, <span class="reserved">string</span> <span class="variable local">value</span>) { <span class="type">Console</span><span class="operator">.</span><span class="method">Write</span>(<span class="variable local">value</span>); <span class="control">return</span> <span class="variable local">x</span>; }
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="type struct">ConsoleOut</span> <span class="reserved">operator</span> <span class="operator">&lt;&lt;</span>(<span class="type struct">ConsoleOut</span> <span class="variable local">x</span>, <span class="type struct">ConsoleEndLine</span> <span class="variable local">_</span>) { <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(); <span class="control">return</span> <span class="variable local">x</span>; }
    }

    <span class="reserved">public</span> <span class="reserved">struct</span> <span class="type struct">ConsoleEndLine</span> { }
}
</code></pre>
<p>ただ、まあこういうコードは推奨されていないというのは今となっては割と有名な話ですし、
いわゆるガイドラインとかベストプラクティス集みたいなドキュメントで「やるべきではない」と書いておけば十分だろいうという判断が下されました。</p>
<p>なので、今回のシフト演算子の制限緩和でも、「<code>INumber&lt;T&gt;</code> インターフェイスを実装した型に限る」みたいな制限は掛けない(緩めるのであれば一切の制限をしない)ことになりました。</p>
 ]]></description>
				<pubDate>Mon, 06 Jun 2022 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 10.0 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver10/</link>
				<description><![CDATA[ <div class="version version10">Ver. 10.0</div>
<table>
<tr>
<th>リリース時期</th>
<td>2021/11</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>.NET 6.0</li>
<li>Visual Studio 2022</li>
</td>
</tr>
<tr>
<th>要約・目玉機能</ht>
<td>
<ul>
<li></li>
</ul>
</td>
</tr>
</table>
<p>※一部、まだ記事化(めったに使わない機能や細かい修正の紹介)が完了していません:</p>
<ul>
<li><a id="async-builder">Async method builder override</a></li>
<li>Enhanced <code>#line</code> directive</li>
</ul>
<p>執筆予定: <a href="https://github.com/ufcpp/UfcppSample/issues/342">C# 10.0 トラッキング issue</a></p>
<h2><a id="record-struct">record struct</a></h2>
<p>C# 9.0 (レコード型の最初のバージョン)では、レコード型は常に<a href="/study/csharp/oo_reference.html#reftype">参照型</a>(クラスと同系統の型)になります。
これに対して C# 10.0 では<a href="/study/csharp/oo_reference.html#valtype">値型</a>も選べるようにしました。
そのため、以下のように、<code>record class</code> と <code>record struct</code> というキーワードで書き分けができるようになりました。</p>
<pre class="source" title="C# 10.0 の record class と record struct">
<code><span class="reserved">record</span> <span class="reserved">class</span> <span class="type">Reference</span>(<span class="reserved">int</span> <span class="variable">X</span>, <span class="reserved">int</span> <span class="variable">Y</span>); <span class="comment">// record だけ書いた場合こちらと同じ意味</span>
<span class="reserved">record</span> <span class="reserved">struct</span> <span class="type">Value</span>(<span class="reserved">int</span> <span class="variable">X</span>, <span class="reserved">int</span> <span class="variable">Y</span>);
</code></pre>
<p>詳しくは 「<a href="https://ufcpp.net/study/csharp/datatype/record/">レコード型</a>」のページ内に色々と追記しました。</p>
<h2><a id="struct-parameterless-ctor">構造体の引数なしコンストラクター</h2>
<p>構造体に引数なしコンストラクターとかフィールド初期化子を書けるようになりました。</p>
<pre class="source" title="構造体の引数なしコンストラクターの例">
<code><span class="reserved">struct</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="type">A</span>() =&gt; X = 1;
}
</code></pre>
<p>これで、<code>new A()</code> で <code>X</code> が1になります。
詳しくは「<a href="/study/csharp/resource/rm_struct/#parameterless-ctor">引数なしコンストラクター</a>」で説明します。</p>
<h2><a id="string-interpolation">文字列補間</h2>
<p><a href="/study/csharp/st_string.html#string-interpolation">文字列補間</a>に2点ほど改善が入りました。</p>
<h3><a id="improved-string-interpolation">パフォーマンス改善</h3>
<p><code>string.Format</code> を使った実装ではどうしてもパフォーマンス上の改善が難しく、
別の型を使って結構複雑なコードに変換する最適化が入りました。
条件を満たす場合、</p>
<pre class="source" title="文字列補間の例">
<code><span class="reserved">var</span> formatted = <span class="literal">$"({</span>x<span class="literal">}, {</span>y<span class="literal">})"</span>;
</code></pre>
<p>このコードは <code>string.Format</code> ではなく、以下のようなコードに展開されます。</p>
<pre class="source" title="C# 10.0 での文字列補間の展開結果の例">
<code><span class="type">DefaultInterpolatedStringHandler</span> handler = <span class="reserved">new</span> <span class="type">DefaultInterpolatedStringHandler</span>(4, 2);
handler.<span class="method">AppendLiteral</span>(<span class="string">"("</span>);
handler.<span class="method">AppendFormatted</span>(x);
handler.<span class="method">AppendLiteral</span>(<span class="string">", "</span>);
handler.<span class="method">AppendFormatted</span>(y);
handler.<span class="method">AppendLiteral</span>(<span class="string">")"</span>);
<span class="reserved">string</span> s = handler.<span class="method">ToStringAndClear</span>();
</code></pre>
<p>詳しくは「<a href="/study/csharp/start/improvedinterpolatedstring/">C# 10.0 の補間文字列の改善</a>」で説明します。</p>
<h3><a id="improved-string-interpolation">const 文字列補間</h3>
<p><a href="/study/csharp/st_string.html#string-interpolation">文字列補間</a>でも、<code>{}</code> の中身が <code>const</code> 文字列な場合に限り、補完結果も <code>const</code> にできます。
例えば以下のような <code>const</code> 文字列を作れます。</p>
<pre class="source" title="const 文字列補間">
<code><span class="reserved">const</span> <span class="reserved">string</span> A = <span class="string">"Abc"</span>;
<span class="reserved">const</span> <span class="reserved">string</span> B = <span class="string">"Xyz"</span>;
<span class="reserved">const</span> <span class="reserved">string</span> C = <span class="string">$"</span>{<span class="reserved">nameof</span>(A)}<span class="string">: </span>{A}<span class="string">, </span>{<span class="reserved">nameof</span>(B)}<span class="string">: </span>{B}<span class="string">"</span>; <span class="comment">// "A: Abc, B: Xyz"</span>
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp_const.html#constant-string-interpolation">const 文字列補間</a>」で説明します。</p>
<h2><a id="CallerArgumentExpression">CallerArgumentExpression 属性</h2>
<p><code>CallerArgumentExpression</code> 属性を使って、メソッド呼び出し元でどの引数にどういう式を渡したかを文字列として取れるようになりました。</p>
<pre class="source" title="CallerArgumentExpression の利用例">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

m(2 * 3 * 5);

<span class="reserved">static</span> <span class="reserved">void</span> m(
    <span class="reserved">int</span> x,
    [<span class="type">CallerArgumentExpression</span>(<span class="string">"x"</span>)] <span class="reserved">string</span>? expression = <span class="reserved">null</span>)
{
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{expression}<span class="string"> = </span>{x}<span class="string">"</span>);
}
</code></pre>
<pre class="console" title="CallerArgumentExpression の利用例">
<code>2 * 3 * 5 = 30
</code></pre>
<p>詳しくは「<a href="/study/csharp/start/miscreservedattribute/#CallerInfo">呼び出し元情報(caller info)</a>」で説明します。</p>
<h2><a id="simple-program">シンプル プログラム</h2>
<p>C# 9.0 の<a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver9/#top-level-statements">トップ レベル ステートメント</a>に続いて、シンプルなプログラムであればシンプルなソースコードで書けるようになる機能が増えています。</p>
<p>これらの機能によって、いわゆる <a href="https://ja.wikipedia.org/wiki/Hello_world">Hello World プログラム</a>を以下の1行で書けるようになりました。</p>
<pre class="source" title="新コンソール アプリ テンプレート">
<code><span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"Hello, World!"</span>);
</code></pre>
<p>実際、 .NET 6 からはコンソール アプリのプロジェクト テンプレートがこの1ファイル、1行だけのものになっています。</p>
<p>また、Web アプリ用のテンプレートも以下のような1ファイルのコードになりました。</p>
<pre class="source" title="Web アプリの .NET 6 新テンプレート">
<code><span class="reserved">var</span> <span class="variable">builder</span> = <span class="type">WebApplication</span>.<span class="method">CreateBuilder</span>(<span class="variable">args</span>);
<span class="reserved">var</span> <span class="variable">app</span> = <span class="variable">builder</span>.<span class="method">Build</span>();

<span class="variable">app</span>.<span class="method">MapGet</span>(<span class="string">&quot;/&quot;</span>, () =&gt; <span class="string">&quot;Hello World!&quot;</span>);

<span class="variable">app</span>.<span class="method">Run</span>();
</code></pre>
<p>参考: 「<a href="https://ufcpp.net/blog/2021/8/newprojecttemplate/">最初の C# プログラム</a>」</p>
<p>これらを実現するために、C# の文法にもいくつかの新機能が追加されました。</p>
<h3><a id="file-scoped-namespace">ファイル スコープ名前空間</h3>
<p>C# 10.0 から <code>{}</code> なしの以下のような書き方で名前空間を指定できるようになりました。</p>
<pre class="source" title="C# 10 からできる名前空間の書き方">
<code><span class="reserved">namespace</span> Namespace;

<span class="reserved">class</span> <span class="type">A</span> { }
</code></pre>
<p>これで以下のコードと同じ意味になります。</p>
<pre class="source" title="同じ意味のコード">
<code><span class="reserved">namespace</span> Namespace
{
    <span class="reserved">class</span> <span class="type">A</span> { }
}
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_namespace.html#file-scoped-namespace">ファイル スコープ namespace</a>」で説明します。</p>
<h3><a id="global-using">global using</h3>
<p><code>using</code> ディレクティブの前に <code>global</code> という修飾を付けることで、
<a href="https://ufcpp.net/study/csharp/package/project/?p=2#project">プロジェクト</a>内全域に対して影響を及ぼす <code>using</code> (名前空間の参照)ができるようになりました。</p>
<p>例えば、プロジェクト内のどこか1つのファイルに以下のようなコードを書いたとします。</p>
<pre class="source" title="global using の例">
<code><span class="reserved">global</span> <span class="reserved">using</span> System;
</code></pre>
<p>これで、このプロジェクト内のすべてのファイルで、ファイルの先頭に <code>using System;</code> を書いたのと同じ状態になります。</p>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_namespace.html#global-using">global using</a>」で説明します。</p>
<h3><a id="lambda-improvement">ラムダ式の改善(自然な型決定、戻り値明示、属性指定)</h3>
<p>Web アプリ用テンプレートの <code>MapGet</code> を実現するために、
ラムダ式とデリゲートに以下の3つの機能が追加されました。</p>
<ul>
<li>自然な型決定</li>
<li>ラムダ式の戻り値の明示</li>
<li>ラムダ式への属性</li>
</ul>
<p>これらにより、ラムダ式やデリゲートを以下のように書けるようになりました。</p>
<pre class="source" title="ラムダ式の戻り値明示、属性指定と、デリゲートの自然な型決定">
<code><span class="reserved">var</span> <span class="variable">f</span> =
    [<span class="type">A</span>]
    [<span class="reserved">return</span>: <span class="type">B</span>]
    <span class="reserved">static</span> <span class="reserved">int</span> ([<span class="type">C</span>] <span class="reserved">int</span> <span class="variable">x</span>)
    =&gt; <span class="variable">x</span>;
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp_delegate.html#natural-type">デリゲートの自然な型</a>」と「<a href="/study/csharp/functional/fun_localfunctions/#lambda-csharp10">ラムダ式の戻り値の明示と属性</a>」で説明します。</p>
<h2><a id="others">その他</h2>
<h3><a id="sub-pattern-name">プロパティ パターンの拡張(入れ子のメンバー参照)</h3>
<p>入れ子のプロパティ・フィールド参照でプロパティ パターンを書けるようになりました。</p>
<pre class="source" title="入れ子のプロパティ参照">
<code>    <span class="control">if</span> (x <span class="reserved">is</span> { <em>Name.Length: 1</em> })
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"single-char Name"</span>);
    }
</code></pre>
<p>詳しくは「<a href="/study/csharp/datatype/patterns/?p=2#sub-pattern-name">プロパティ パターン</a>」で説明します。</p>
<h3><a id="mixed-deconstruction">分解宣言と分解代入の混在</h3>
<p>分解代入と分解宣言の混在もできるようになりました。</p>
<pre class="source" title="分解宣言と分解代入の混在">
<code><span class="reserved">int</span> x;
(x, <em><span class="reserved">var</span> u</em>) = (1, 2);
</code></pre>
<p>ただし、式の途中に分解宣言 (var 付きの宣言) が来るようなコードは C# 10.0 でも書けません。</p>
<pre class="source" title="ただし、分解宣言は式の途中には書けない">
<code><span class="reserved">int</span> x, y;
(x, <span class="reserved">var</span> u) = (<span class="error"><span class="reserved">var</span> v</span>, y) = (1, 2);
</code></pre>
<h3><a id="definite-assignment">明確な初期化ルールの改善</h3>
<p>明確な初期化ルール(未初期化のまま変数から値を読めないようにするフロー解析)に関する改善がありました。
これまでは <code>?.</code> や <code>??</code> が絡んだ時の判定があまり賢くなかったんですが、C# 10 で改善しました。</p>
<p>例えば以下のコードは C# 10 以降でだけコンパイルできます。</p>
<pre class="source" title="?. == true">
<span class="comment">// C# 10 から大丈夫な例: ?. == true。</span>
<span class="reserved">void</span> <span class="method">m</span>(<span class="type">Dictionary</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;<span class="operator">?</span> <span class="variable local">d</span>)
{
    <span class="control">if</span> (<span class="variable local">d</span><span class="operator">?</span><span class="operator">.</span><span class="method">TryGetValue</span>(<span class="number">123</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">x</span>) <span class="operator">==</span> <span class="reserved">true</span>)
    {
        <span class="comment">// C# 10 から大丈夫になった。</span>
        <span class="comment">// (前までは ?. からの == true は判定漏れでエラー。)</span>
        <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="static"><span class="method">WriteLine</span></span>(<span class="variable">x</span>);
    }
}
</pre>
<p>「<a href="https://ufcpp.net/study/csharp/start/definiteassignment/">[雑記] 明確な代入ルール</a>」で説明しています。</p>
 ]]></description>
				<pubDate>Sun, 24 Oct 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 10.0 の補間文字列の改善</title>
				<link>http://www.ufcpp.net/study/csharp/start/improvedinterpolatedstring/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version10">Ver. 10</h5>
<p>C# 10.0 で、補間文字列(interpolated string)のコンパイル結果に変更が掛かって、
これまでよりもかなり高速化されました。
詳細は気にせず単に高速化の恩恵だけを受けたい場合、
言語バージョン、SDK バージョンを C# 10.0/.NET  6.0 にアップデートして再コンパイルするだけで速くなります。</p>
<p>一方、本項では、
C# 9.0 までの補間文字列の問題点と、
C# 10.0 から補間文字列がどのように展開されるかについて説明します。
仕組みがわかれば、補間文字列の解釈を結構自由にカスタマイズすることができます。</p>
<p>サンプル コード: <a href="https://github.com/ufcpp/UfcppSample/tree/master/Demo/2021/Csharp10/InterpolatedStrings">InterpolatedStrings</a></p>
<h2><a id="csharp9">C# 9.0 までの補間文字列</h2>
<p>例えば以下のようなコードがあったとします。</p>
<pre class="source" title="補間文字列の例">
<code><span class="reserved">static</span> <span class="reserved">string</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b, <span class="reserved">int</span> c, <span class="reserved">int</span> d) =&gt; <span class="string">$"</span>{a}<span class="string">.</span>{b}<span class="string">.</span>{c}<span class="string">.</span>{d}<span class="string">"</span>;
</code></pre>
<p>C# 9.0 までは、このコードは以下のように展開されていました。</p>
<pre class="source" title="string.Format への展開">
<code><span class="reserved">static</span> <span class="reserved">string</span> m(<span class="reserved">int</span> a, <span class="reserved">int</span> b, <span class="reserved">int</span> c, <span class="reserved">int</span> d) =&gt; <span class="reserved">string</span>.<span class="method">Format</span>(<span class="string">"{0}.{1}.{2}.{3}"</span>, a, b, c, d);
</code></pre>
<p>要は <code>string.Format</code> メソッド呼び出しへの展開でした。
ちなみに、ここで呼ばれている <code>Format</code> メソッドは以下のようなオーバーロードです。</p>
<pre class="source" title="Format(format, args)">
<code><span class="reserved">public static string</span> <span class="method">Format</span>(<span class="reserved">string</span> format, <span class="reserved">params</span> <span class="reserved">object</span>?[] args)
</code></pre>
<p>この展開方法では以下のようなコストがどうしても避けられず、用途によっては使うのがためらわれていました。</p>
<ul>
<li><a href="/study/csharp/sp_params.html"><code>params</code></a> を介していて、<code>new object[4]</code> のコストが発生する</li>
<li><code>object</code> を介していて、<code>int</code> などの値を渡すと<a href="/study/csharp/RmBoxing.html">ボックス化</a> のコストが発生する</li>
<li>(ログレベルの変更などで)実際には文字列を全く使わない状況でも必ず文字列インスタンスが作られる</li>
<li><a href="/study/csharp/resource/span/"><code>Span</code> 構造体</a>を渡せない</li>
</ul>
<p>そこで、C# 10.0 では以下のように、<code>AppendLiteral</code>, <code>AppendFormatted</code> メソッドを何度も呼び出す方針に変更されました。</p>
<pre class="source" title="C# 10.0 での文字列補間の展開結果の例">
<code><span class="type">DefaultInterpolatedStringHandler</span> handler = <span class="reserved">new</span> <span class="type">DefaultInterpolatedStringHandler</span>(3, 4);
handler.<span class="method">AppendFormatted</span>(a);
handler.<span class="method">AppendLiteral</span>(<span class="string">"."</span>);
handler.<span class="method">AppendFormatted</span>(b);
handler.<span class="method">AppendLiteral</span>(<span class="string">"."</span>);
handler.<span class="method">AppendFormatted</span>(c);
handler.<span class="method">AppendLiteral</span>(<span class="string">"."</span>);
handler.<span class="method">AppendFormatted</span>(d);
<span class="reserved">string</span> s = handler.<span class="method">ToStringAndClear</span>();
</code></pre>
<h2><a id="handler-pattern">ハンドラー パターン</h2>
<p>前述の通り、C# 10.0 からは補間文字列(<code>$&quot;&quot;</code>)を<code>AppendFormatted</code>や<code>AppendLiteral</code>メソッドに展開します。
これは<a href="/study/csharp/misc/miscpatternbased/#key-pattern-based">パターン ベース</a>になっていて、
所定のパターンを満たしていればどんな型であっても可能です。</p>
<p>まず、以下の条件を満たす型を補間文字列ハンドラー (interpolated string handler)と呼びます。
(以下、このページ内では単に「ハンドラー型」と呼びます。)</p>
<ul>
<li><code>InterpolatedStringHandler</code> 属性(<code>System.Runtime.CompilerServices</code>名前空間)が付いている</li>
<li>
最低限、以下の引数を持つコンストラクターを持つ
<ul>
<li><code>int literalLength</code>: 補間文字列のリテラル部分(<code>$&quot;&quot;</code> の中から <code>{}</code> を除いた部分)の文字列長</li>
<li><code>int formattedCount</code>: <code>{}</code> (interpolation hole: 補間穴)の個数</li>
<li>追加で、<code>out bool</code> なアウト引数を持てる</li>
<li><code>InterpolatedStringHandlerArgument</code> 属性と組み合わせ得て、追加で任意の引数を足せる</li>
</ul>
</li>
<li>
リテラル部分を書き込むための <code>AppendLiteral(string)</code> メソッドを持つ
<ul>
<li><code>void</code> か <code>bool</code> 戻り値(後述)</li>
</ul>
</li>
<li>
<code>{}</code> の部分を書き込むための `AppendFormatted(T)' メソッドを持つ
<ul>
<li><code>void</code> か <code>bool</code> 戻り値(後述)</li>
<li>追加で <code>int alignment</code> 引数(フォーマット時の幅指定)を持てる</li>
<li>追加で <code>string format</code> 引数(フォーマット指定文字列)を持てる</li>
</ul>
</li>
</ul>
<p>最低ライン必要なメンバーをそろえた型を作ると以下のようになります。
(本当に「コンパイルが通る」レベルで、中身が何もないので <code>Dummy</code> という名前にしてあります。)</p>
<pre class="source" title="補間文字列ハンドラーに必要な最低限だけ持った型の例">
<code>
[System.Runtime.CompilerServices.<span class="type">InterpolatedStringHandler</span>]
<span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">DummyHandler</span>
{
    <span class="reserved">public</span> <span class="type">DummyHandler</span>(<span class="reserved">int</span> literalLength, <span class="reserved">int</span> formattedCount) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendLiteral</span>(<span class="reserved">string</span> s) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x) { }
}
</code></pre>
<h3><a id="assign-to-handler">ハンドラー型への直接代入</h3>
<p>まず、補間文字列をハンドラー型に直接渡す場合、
コンストラクター、<code>AppendLiteral</code>、<code>AppendFormatted</code> メソッドの呼び出しに展開されます。</p>
<p>例えば以下のようなコードがあるとき、</p>
<pre class="source" title="補間文字列をハンドラー型に直接渡す例">
<code><span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b)
{
    <span class="type">DummyHandler</span> h = <span class="string">$"</span>{a}<span class="string"> / </span>{b}"</span>;
}
</code></pre>
<p>以下のように展開されます。</p>
<pre class="source" title="補間文字列をハンドラー型に直接渡す例の展開結果">
<code><span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b)
{
    <span class="type">DummyHandler</span> temp = <span class="reserved">new</span>(3, 2);
    temp.<span class="method">AppendFormatted</span>(a);
    temp.<span class="method">AppendLiteral</span>(<span class="string">" / "</span>);
    temp.<span class="method">AppendFormatted</span>(b);
    <span class="type">DummyHandler</span> h = temp;
}
</code></pre>
<h3><a id="assign-to-string">string への代入</h3>
<p><code>string</code> 型は特殊で、補間文字列を <code>string</code> 型に渡す場合、
以下のような展開が行われます。</p>
<ul>
<li>
<code>DefaultInterpolatedStringHandler</code> 型(<code>System.Runtime.CompilerServices</code> 名前空間)が利用可能な場合
<ul>
<li>まず、この型に対する代入処理と同様に <code>AppendLiteral</code>、<code>AppendFormatted</code> メソッドを呼び出す</li>
<li>最後に <code>DefaultInterpolatedStringHandler.ToStringAndClear</code> メソッドを呼んで文字列化する</li>
</ul>
</li>
<li>利用できない場合、<code>string.Format</code> に展開する(C# 9.0 までの挙動と同じ)</li>
</ul>
<p><code>DefaultInterpolatedStringHandler</code> 型が存在するならほとんどの場合はこれを利用可能です。
そして、この型は .NET 6.0 からは標準ライブラリに入っています。
例えば以下のようなコードを書いて .NET 6.0 向けにコンパイルした場合、</p>
<pre class="source" title="補間文字列を string 型に渡す例">
<code><span class="reserved">string</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b) =&gt; <span class="string">$"</span>{a}<span class="string"> / </span>{b}<span class="string">"</span>;
</code></pre>
<p>以下のように展開されます。
(<code>DefaultInterpolatedStringHandler</code> 型への代入の展開結果 + <code>ToStringAndClear</code> 呼び出しみたいなコードになります。)</p>
<pre class="source" title="補間文字列を string 型に渡す例の展開結果">
<code><span class="reserved">string</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b)
{
    <span class="type">DefaultInterpolatedStringHandler</span> h = <span class="reserved">new</span>(3, 2);
    h.<span class="method">AppendFormatted</span>(a);
    h.<span class="method">AppendLiteral</span>(<span class="string">" / "</span>);
    h.<span class="method">AppendFormatted</span>(b);
    <span class="reserved">return</span> <em>h.<span class="method">ToStringAndClear</span>()</em>;
}
</code></pre>
<p><code>DefaultInterpolatedStringHandler</code> 型自体は存在するのに補間文字列として利用できない状況は、
補間穴(<code>{}</code>)の中に <a href="/study/csharp/sp5_async.html#async"><code>await</code></a> を含む場合などです。
<code>DefaultInterpolatedStringHandler</code> 型は <a href="/study/csharp/resource/refstruct/">ref 構造体</a>なので、<code>await</code> と共存できません。
例えば以下のようなコードを書くと <code>string.Format</code> に展開されます。</p>
<pre class="source" title="DefaultInterpolatedStringHandler に展開できない補間文字列の例">
<code><span class="reserved">async</span> <span class="type">Task</span>&lt;<span class="reserved">string</span>&gt; <span class="method">m</span>(<span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; a) =&gt; <span class="string">$"result: </span>{<em><span class="reserved">await</span> a</em>}<span class="string">"</span>;
</code></pre>
<p>ちなみに、<code>DefaultInterpolatedStringHandler</code> 型は標準ライブラリ中のものでなくても構いません。
もし .NET 5.0 以前をターゲットにした場合でも同様の最適化が掛かって欲しいなら、
<code>DefaultInterpolatedStringHandler</code> 型を移植すれば可能です。
.NET 6.0 にしかない機能をちらほら使っているので 5.0 以前への移植は<a href="https://github.com/ufcpp/UfcppSample/issues/355#issuecomment-916822451">多少面倒ですが、できなくはないレベルかと思います</a>。</p>
<h3><a id="AppendFormatted-overload">AppendFormatted メソッドのオーバーロード</h3>
<p>ハンドラー型を作る際、<code>AppendFormatted</code> メソッドはいくつオーバーロードがあっても構いません。
よく使いそうなのは、ジェネリック型引数として使えない <code>ReadOnlySpan&lt;char&gt;</code> や、
その他最適化のために具象型を直接受け取りたい場合(<code>string</code> など)用のオーバーロードなどです。</p>
<pre class="source" title="AppendFormatted のオーバーロードを増やす例">
<code><span class="type">DummyHandler</span> h = <span class="string">$"</span>{123}<span class="string">, </span>{<span class="string">"abc"</span>}<span class="string">, </span>{<span class="reserved">stackalloc</span> <span class="reserved">char</span>[1]}<span class="string">"</span>;

[System.Runtime.CompilerServices.<span class="type">InterpolatedStringHandler</span>]
<span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">DummyHandler</span>
{
    <span class="reserved">public</span> <span class="type">DummyHandler</span>(<span class="reserved">int</span> literalLength, <span class="reserved">int</span> formattedCount) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendLiteral</span>(<span class="reserved">string</span> s) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"(literal)"</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"ジェネリック版"</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>(<span class="reserved">string</span> x) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"string 版"</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>(<span class="type">ReadOnlySpan</span>&lt;<span class="reserved">char</span>&gt; x) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"ReadOnlySpan 版"</span>);
}
</code></pre>
<pre class="console" title="AppendFormatted のオーバーロードを増やす例">
<code>ジェネリック版
(literal)
string 版
(literal)
ReadOnlySpan 版
</code></pre>
<h3><a id="formatting">書式指定</h3>
<p>補間文字列の <code>{}</code> の中では<a href="/study/csharp/st_string.html#formatting">書式指定</a>ができます。
(ハンドラー型が使える状況下で)書式指定した場合、<code>AppendFormatted</code> メソッドの第2、第3引数に書式が渡ります。
例えば以下のようなコードを書いた場合、</p>
<pre class="source" title="書式指定付きの補間文字列の例">
<code><span class="reserved">string</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b, <span class="reserved">int</span> c) =&gt; <span class="string">$"(</span>{a<em>, 8:<span class="string">X</span></em>}<span class="string">) (</span>{b<em>:<span class="string">X</span></em>}<span class="string">) (</span>{c<em>,4</em>}<span class="string">)"</span>;
</code></pre>
<p>以下のように展開されます。</p>
<pre class="source" title="書式指定付きの補間文字列の例の展開結果">
<code><span class="reserved">string</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b, <span class="reserved">int</span> c)
{
    <span class="type">DefaultInterpolatedStringHandler</span> h = <span class="reserved">new</span>(8, 3);
    h.<span class="method">AppendLiteral</span>(<span class="string">"("</span>);
    h.<span class="method">AppendFormatted</span>(a, <em>8, <span class="string">"X"</span></em>);
    h.<span class="method">AppendLiteral</span>(<span class="string">") ("</span>);
    h.<span class="method">AppendFormatted</span>(b, <em><span class="string">"X"</span></em>);
    h.<span class="method">AppendLiteral</span>(<span class="string">") ("</span>);
    h.<span class="method">AppendFormatted</span>(c, <em>4</em>);
    h.<span class="method">AppendLiteral</span>(<span class="string">")"</span>);
    <span class="reserved">return</span> h.ToStringAndClear();
}
</code></pre>
<p>ハンドラー型を自作する場合、<code>AppendFormatted</code> メソッドの引数は、
以下のようにオーバーロードをいくつか用意しても構いませんし、</p>
<pre class="source" title="AppendFormatted メソッドの引数の例(オーバーロードをいくつか用意)">
<code>    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="reserved">int</span> alignment) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="reserved">string</span> format) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="reserved">int</span> alignment, <span class="reserved">string</span> format) { }
</code></pre>
<p>以下のようにオプション引数で1つのメソッドにまとめても構いません。</p>
<pre class="source" title="AppendFormatted メソッドの引数の例(オプション引数)">
<code>    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="reserved">int</span>? alignment = <span class="reserved">null</span>, <span class="reserved">string</span>? format = <span class="reserved">null</span>) { }
</code></pre>
<h3><a id="bool-return">bool 戻り値</h3>
<p>ハンドラー型のコンストラクターでは第3引数に <code>out bool</code> を、
<code>AppendLiteral</code>、<code>AppendFormatted</code> メソッドでは戻り値として <code>bool</code> を返すことができます。
この場合、false が返ってきたら処理を途中で打ち切るようなコードに展開されます。
例えば以下のようなハンドラー型があったとします。</p>
<pre class="source" title="bool 戻り値を持つ補間文字列ハンドラー型の例">
<code>[<span class="type">InterpolatedStringHandler</span>]
<span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">DummyHandler</span>
{
    <span class="reserved">public</span> <span class="type">DummyHandler</span>(<span class="reserved">int</span> literalLength, <span class="reserved">int</span> formattedCount, <span class="reserved">out</span> <span class="reserved">bool</span> result) =&gt; result = <span class="reserved">true</span>;
    <span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">AppendLiteral</span>(<span class="reserved">string</span> s) =&gt; <span class="reserved">true</span>;
    <span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">AppendFormatted</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x) =&gt; <span class="reserved">true</span>;
}
</code></pre>
<p>このハンドラー型に対して、例えば以下のように補間文字列を渡した場合、</p>
<pre class="source" title="bool 戻り値を持つ補間文字列ハンドラー型の利用例">
<code><span class="type">DummyHandler</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b, <span class="reserved">int</span> c, <span class="reserved">int</span> d) =&gt; <span class="string">$"</span>{a}<span class="string">.</span>{b}<span class="string">.</span>{c}<span class="string">.</span>{d}<span class="string">"</span>;
</code></pre>
<p>以下のような展開結果になります。</p>
<pre class="source" title="bool 戻り値を持つ補間文字列ハンドラー型の利用例の展開結果">
<code><span class="type">DummyHandler</span> <span class="method">m</span>(<span class="reserved">int</span> a, <span class="reserved">int</span> b, <span class="reserved">int</span> c, <span class="reserved">int</span> d)
{
    <span class="type">DummyHandler</span> h = <span class="reserved">new</span>(3, 4, <span class="reserved">out</span> <span class="reserved">var</span> result);
    <span class="reserved">if</span> (result
        &amp;&amp; h.<span class="method">AppendFormatted</span>(a)
        &amp;&amp; h.<span class="method">AppendLiteral</span>(<span class="string">"."</span>)
        &amp;&amp; h.<span class="method">AppendFormatted</span>(b)
        &amp;&amp; h.<span class="method">AppendLiteral</span>(<span class="string">"."</span>)
        &amp;&amp; h.<span class="method">AppendFormatted</span>(c)
        &amp;&amp; h.<span class="method">AppendLiteral</span>(<span class="string">"."</span>))
        h.<span class="method">AppendFormatted</span>(d);
    <span class="reserved">return</span> h;
}
</code></pre>
<p>これを使って、例えば、「一定文字数を超えたらそこで処理を打ち切り」とか、
「ログ レベル的に全く文字列化処理が必要ない場合、 <code>AppendLiteral</code>/<code>AppendFormatted</code> を一切呼ばない」とかができます。</p>
<h3><a id="InterpolatedStringHandlerArgument">InterpolatedStringHandlerArgument 属性</h3>
<p><code>InterpolatedStringHandlerArgument</code> 属性(<code>System.Runtime.CompilerServices</code> 名前空間)を使って、
ハンドラー型のコンストラクターに追加の引数を渡すことができます。
例えば以下のような使い方をします。
(実際、<code>DefaultInterpolatedStringHandler</code> がそういう使い方をしています。)</p>
<ul>
<li>カルチャー指定して文字列を作りたいとき用に、引数で <code>IFormatProvider</code> を渡す</li>
<li>文字列を作る際に使うバッファーとして外から <code>Span&lt;char&gt;</code> を渡す</li>
</ul>
<p>これを使うためにはまず、以下のようにコンストラクターに追加の引数を持ったハンドラー型を作ります。</p>
<pre class="source" title="コンストラクターに追加の引数を持ったハンドラー型">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

[<span class="type">InterpolatedStringHandler</span>]
<span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">DummyHandler</span>
{
    <span class="reserved">public</span> <span class="type">DummyHandler</span>(<span class="reserved">int</span> literalLength, <span class="reserved">int</span> formattedCount) : <span class="reserved">this</span>(literalLength, formattedCount, <span class="reserved">null</span>, <span class="reserved">default</span>) { }

    <span class="comment">// 追加の引数持ち</span>
    <span class="reserved">public</span> <span class="type">DummyHandler</span>(<span class="reserved">int</span> literalLength, <span class="reserved">int</span> formattedCount, <span class="type">IFormatProvider</span>? provider)
        : <span class="reserved">this</span>(literalLength, formattedCount, provider, <span class="reserved">default</span>) { }

    <span class="reserved">public</span> <span class="type">DummyHandler</span>(<span class="reserved">int</span> literalLength, <span class="reserved">int</span> formattedCount, <span class="type">IFormatProvider</span>? provider, <span class="type">Span</span>&lt;<span class="reserved">char</span>&gt; initialBuffer)
    <span class="comment">// 以下略</span>
}
</code></pre>
<p>次に、以下のように、<code>InterpolatedStringHandlerArgument</code> 属性を使って、メソッドの引数とハンドラー型のコンストラクター引数の結び付けるメソッドを書きます。</p>
<pre class="source" title="InterpolatedStringHandlerArgument 属性を使った引数の結び付け">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Formatter</span>
{
    <span class="comment">// 追加の引数なし。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Format</span>(<span class="type">DummyHandler</span> handler)
    <span class="comment">// 省略</span>

    <span class="comment">// provider を追加。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Format</span>(
        <span class="type">IFormatProvider</span> provider,
        [<span class="type">InterpolatedStringHandlerArgument</span>(<span class="string">"provider"</span>)] <span class="type">DummyHandler</span> handler)
        =&gt; <span class="method">Format</span>(handler);

    <span class="comment">// provider と initialBuffer を追加。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Format</span>(
        <span class="type">IFormatProvider</span> provider, <span class="type">Span</span>&lt;<span class="reserved">char</span>&gt; initialBuffer,
        [<span class="type">InterpolatedStringHandlerArgument</span>(<span class="string">"provider"</span>, <span class="string">"initialBuffer"</span>)] <span class="type">DummyHandler</span> handler)
        =&gt; <span class="method">Format</span>(handler);
}
</code></pre>
<p>そしてこれらのメソッドを呼ぶと、ハンドラー型に追加の引数が渡るようになります。</p>
<pre class="source" title="ハンドラー型に引数を渡す例">
<code><span class="reserved">using</span> System.Globalization;

<span class="comment">// Format(DummyHandler) を呼んでて、</span>
<span class="comment">// new DummyHandler(5, 2) が作られる。</span>
<span class="type">Formatter</span>.<span class="method">Format</span>(<span class="string">$"abc </span>{1}<span class="string"> </span>{2}<span class="string">"</span>);

<span class="comment">// Format(IFormatProvider, DummyHandler) を呼んでて、</span>
<span class="comment">// new DummyHandler(5, 2, CultureInfo.InvariantCulture) が作られる。</span>
<span class="type">Formatter</span>.<span class="method">Format</span>(<span class="type">CultureInfo</span>.InvariantCulture, <span class="string">$"abc </span>{1}<span class="string"> </span>{2}<span class="string">"</span>);

<span class="comment">// Format(IFormatProvider, Span&lt;char&gt;, DummyHandler) を呼んでて、</span>
<span class="comment">// new DummyHandler(5, 2, CultureInfo.InvariantCulture, stackalloc char[128]) が作られる。</span>
<span class="type">Formatter</span>.<span class="method">Format</span>(<span class="type">CultureInfo</span>.InvariantCulture, <span class="reserved">stackalloc</span> <span class="reserved">char</span>[128], <span class="string">$"abc </span>{1}<span class="string"> </span>{2}<span class="string">"</span>);
</code></pre>
<h2><a id="overload-resolution">オーバーロード解決</h2>
<p>C# 10.0 でハンドラー型の仕様が追加され、
C# 9.0 まででも <a href="/study/csharp/st_string.html#FormattableString">FormattableString</a> の仕様があるので、
補間文字列を受け取る候補となるメソッドを3つ同時に定義できます。</p>
<pre class="source" title="補間文字列を受け取る候補となる3つのメソッド">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">DefaultInterpolatedStringHandler</span> _) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"handler"</span>);
<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> _) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"string"</span>);
<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">IFormattable</span> _) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"formattable"</span>);
</code></pre>
<p>こういう状況では、ハンドラー型 &gt; <code>string</code> 型 &gt; FormattableString 
(ハンドラー型が一番呼ばれやすい) という優先順位になります。</p>
<pre class="source" title="ハンドラー型 &gt; string &gt; FormattableString">
<code><span class="comment">// ハンドラー型最優先。</span>
<span class="method">M</span>(<span class="string">$"</span>{1}<span class="string">"</span>); <span class="comment">// handler</span>

<span class="comment">// ただの文字列の場合は string に行く。</span>
<span class="method">M</span>(<span class="string">"abc"</span>); <span class="comment">// string</span>

<span class="comment">// ちょっと混乱しそうなのが、const になる場合に限り、 $ がついてても string 行き。</span>
<span class="method">M</span>(<span class="string">$""</span>); <span class="comment">// string</span>
<span class="method">M</span>(<span class="string">$"abc </span>{<span class="string">"abc"</span>}<span class="string"> abc"</span>); <span class="comment">// string</span>

<span class="comment">// もちろん、キャストしてしまえば任意に呼び分け可能。</span>
<span class="method">M</span>(<span class="string">$"</span>{1}<span class="string">"</span>); <span class="comment">// handler</span>
<span class="method">M</span>((<span class="reserved">string</span>)<span class="string">$"</span>{1}<span class="string">"</span>); <span class="comment">// string</span>
<span class="method">M</span>((<span class="type">IFormattable</span>)<span class="string">$"</span>{1}<span class="string">"</span>); <span class="comment">// formattable</span>
</code></pre>
<p><code>string</code> 型が真ん中なのがちょっと不思議な仕様ですが、
これは FormattableString のときの反省からです。
FormattableString を優先してほしいのに優先してもらえなくて困るので、
<a href="/study/csharp/st_string.html#FormattableString-overload"><code>RawString</code></a>みたいな「<code>string</code> 型を覆った別の型」を1段挟むことで無理やり FormattableString 優先になるようにする手法が知られていました。
ハンドラー型では同じ轍を踏まないよう、最初からハンドラー型優先になっています。</p>
<p>ちなみに、ハンドラーの条件を満たす型が複数あって、
それでオーバーロードした場合、オーバーロード解決できません。</p>
<pre class="source" title="">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> Caller()
{
    <span class="comment">// 優先度は付かないので不明瞭エラーを起こす。</span>
    <span class="error">M</span>(<span class="string">$""</span>);

    <span class="comment">// 明示的にキャストすれば呼び分け可能。</span>
    <span class="method">M</span>((<span class="type">Handler1</span>)<span class="string">$""</span>);
    <span class="method">M</span>((<span class="type">Handler2</span>)<span class="string">$""</span>);
}

<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">Handler1</span> _) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"Handler1"</span>);
<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">Handler2</span> _) =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"Handler2"</span>);
</code></pre>
<h2><a id="api-in-net6">.NET 6.0 で追加された API</h2>
<p>ここまで補間文字列ハンドラーの説明してきましたが、
実際のところ、ハンドラー型を自作することは少ないでしょう。
一方で、標準ライブラリ中に存在するハンドラー型(を使っているメソッド)を使うことで、
補間文字列のパフォーマンス改善によって間接的な利益になる場面は多々あると思います。</p>
<p>C# 10.0 と同時に出た .NET 6.0 ではハンドラー型や、それを使ったメソッドがいくつか追加されています。
本項では最後に、.NET 6.0 で追加されたいくつかのメソッドを紹介して終わりにしたいと思います。</p>
<h3><a id="string.Create">string.Create</h3>
<p><code>string.Create</code> に以下の2つのオーバーロードが追加されています。</p>
<ul>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.string.create?view=net-6.0#System_String_Create_System_IFormatProvider_System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__"><code>Create(IFormatProvider, DefaultInterpolatedStringHandler)</code></a></li>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.string.create?view=net-6.0#System_String_Create_System_IFormatProvider_System_Span_System_Char__System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__"><code>Create(IFormatProvider, Span&lt;Char&gt;, DefaultInterpolatedStringHandler)</code></a></li>
</ul>
<p>「<a href="https://ufcpp.net/study/csharp/start/improvedinterpolatedstring/">InterpolatedStringHandlerArgument 属性</a>」で例に挙げた通り、カルチャー指定で文字列補間するための引数と、初期バッファーを渡すための引数です。</p>
<h4><a id="string.Create-culture">カルチャー指定</h4>
<p>C# の補間文字列はカルチャー依存で、何も指定しないと <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.globalization.cultureinfo.currentculture"><code>CurrentCulture</code></a> が使われます。
その結果、手元の環境で実行すると日本式のフォーマットになるけど、
サーバー上で実行すると米国式のフォーマットになったりすることがあります。</p>
<pre class="source" title="カルチャー依存で文字列補間の結果が変わる例">
<code><span class="reserved">using</span> System.Globalization;

<span class="comment">// サンプルなので明示的に指定。</span>
<span class="comment">// 手元の環境が ja-jp カルチャーだとして…</span>
<span class="type">Thread</span>.CurrentThread.CurrentCulture = <span class="type">CultureInfo</span>.<span class="method">GetCultureInfo</span>(<span class="string">"ja-jp"</span>);

<span class="comment">// 日本式。</span>
<span class="comment">// yyyy/MM/dd hh:mm:ss</span>
<span class="type">Console</span>.WriteLine(<span class="string">$"</span>{<span class="type">DateTime</span>.Now}<span class="string">"</span>);

<span class="comment">// 一方、サーバーとかで別カルチャーだったりすると…</span>
<span class="comment">// (最近、データ量削減のために「CurrentCulture が常に InvariantCulture」みたいなモードがあったりする。)</span>
<span class="type">Thread</span>.CurrentThread.CurrentCulture = <span class="type">CultureInfo</span>.InvariantCulture;

<span class="comment">// .NET の InvariantCulture は Invariant (不変)と言いつつ、米国基準。</span>
<span class="comment">// MM/dd/yyyy hh:mm:ss</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$"</span>{<span class="type">DateTime</span>.Now}<span class="string">"</span>);
</code></pre>
<pre class="console" title="カルチャー依存で文字列補間の結果が変わる例">
<code>2021/09/23 22:39:39
09/23/2021 22:39:39
</code></pre>
<p><code>CurrentCulture</code> 依存が怖いなら、<code>string.Create</code> メソッドを使ってカルチャーを明示します。</p>
<pre class="source" title="string.Create でカルチャーを明示する例">
<code><span class="reserved">using</span> System.Globalization;

<span class="comment">// どこか日本でも Invariant でもない適当なカルチャー。</span>
<span class="type">Thread</span>.CurrentThread.CurrentCulture = <span class="type">CultureInfo</span>.GetCultureInfo(<span class="string">"fr-fr"</span>);

<span class="comment">// これは CurrentCulture 依存。</span>
<span class="type">Console</span>.WriteLine(<span class="string">$"</span>{<span class="type">DateTime</span>.Now}<span class="string">"</span>);

<span class="comment">// string.Create を使ってカルチャーを明示すれば CurrentCulture 依存はなくなる。</span>
<span class="type">Console</span>.WriteLine(<span class="reserved">string</span>.Create(<span class="type">CultureInfo</span>.InvariantCulture, <span class="string">$"</span>{<span class="type">DateTime</span>.Now}<span class="string">"</span>));
</code></pre>
<pre class="console" title="string.Create でカルチャーを明示する例">
<code>23/09/2021 22:39:39
09/23/2021 22:39:39
</code></pre>
<p>ちなみに<a href="https://github.com/ufcpp/UfcppSample/tree/master/Demo/2021/Csharp10/InterpolatedStrings/InvariantGlobalization">サンプル コード</a>では、以下のようなハンドラー型を提供していたりします。</p>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/blob/master/Demo/2021/Csharp10/InterpolatedStrings/InvariantGlobalization/Invariant.cs"><code>Invariant</code></a>: 常に <code>InvariantCulture</code> で文字列補間する型</li>
<li><a href="https://github.com/ufcpp/UfcppSample/blob/master/Demo/2021/Csharp10/InterpolatedStrings/InvariantGlobalization/Iso8601.cs"><code>Iso8601</code></a>: 常に <code>InvariantCulture</code> を使いつつ、日付だけは MM/dd/yyyy を許さず、ISO 8601 形式で文字列補間する型</li>
</ul>
<h4><a id="string.Create-buffer">初期バッファー指定</h4>
<p>冒頭での説明通り、C# 10.0 で再コンパイルするだけで文字列補間は高速化されます。
ただ、パフォーマンスを求めるのであれば、素の <code>$&quot;&quot;</code> を使うよりも、
<code>string.Create</code> で初期バッファーを与える方がいいです。
特に、補間結果の文字数がある程度わかっている場合には初期バッファーの指定でパフォーマンスが劇的に改善することがあります。</p>
<p>例えば<a href="https://github.com/ufcpp/UfcppSample/blob/master/Demo/2021/Csharp10/InterpolatedStrings/Benchmark/Program.cs">サンプル コードのベンチマーク</a>では以下のようなもののパフォーマンス比較を行っています。</p>
<ul>
<li>OldStyle: C# 9.0 までの展開結果である <code>string.Format</code> を使ったコード</li>
<li>Improved: C# 10.0 の文字列補間に任せる(<code>DefaultInterpolatedStringHandler</code> が使われる)</li>
<li>InitialBuffer: <code>string.Create(_currentCulture, stackalloc char[InitialBufferSize], $&quot;{a}.{b}.{c}.{d}&quot;)</code> で初期バッファー指定</li>
</ul>
<p>手元の環境でベンチマーク計測した結果、これらは以下のような実行結果になりました。</p>
<table>
<thead>
<tr>
	<th>Method</th>
	<th align="right">Mean</th>
	<th align="right">Error</th>
	<th align="right">StdDev</th>
	<th align="right">Gen 0</th>
	<th align="right">Allocated</th>
</tr>
</thead>
<tbody>
<tr>
	<td>OldStyle</td>
	<td align="right">978.2 us</td>
	<td align="right">0.97 us</td>
	<td align="right">0.76 us</td>
	<td align="right">228.5156</td>
	<td align="right">1,875 KB</td>
</tr>
<tr>
	<td>Improved</td>
	<td align="right">530.8 us</td>
	<td align="right">0.77 us</td>
	<td align="right">0.64 us</td>
	<td align="right">46.8750</td>
	<td align="right">391 KB</td>
</tr>
<tr>
	<td>InitialBuffer</td>
	<td align="right">377.2 us</td>
	<td align="right">0.73 us</td>
	<td align="right">0.61 us</td>
	<td align="right">47.3633</td>
	<td align="right">391 KB</td>
</tr>
</tbody>
</table>
<h3><a id="StringBuilder.Append">StringBuilder.Append</h3>
<p>これまで <code>StringBuilder</code> (<code>System.Text</code> 名前空間)に対して
<code>builder.Append($&quot;{1} {2} {3}&quot;);</code> みたいなコードを書くと、
一度 <code>string.Format</code> で文字列インスタンスを作った上で、それを <code>Append</code> していました。</p>
<p>一方、C# 10.0/.NET 6.0 では、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.text.stringbuilder.append?view=net-6.0#System_Text_StringBuilder_Append_System_Text_StringBuilder_AppendInterpolatedStringHandler__"><code>Append(AppendInterpolatedStringHandler)</code></a> というオーバーロードが追加されています。
このオーバーロードを呼ぶと、
<code>builder.Append($&quot;{1} {2} {3}&quot;);</code> を、以下のようなコードとそん色ないパフォーマンスで呼ぶことができます。</p>
<pre class="source" title="$&quot;{1} {2} {3}&quot; 相当コード">
<code>builder.<span class="method">Append</span>(1);
builder.<span class="method">Append</span>(<span class="string">" "</span>);
builder.<span class="method">Append</span>(2);
builder.<span class="method">Append</span>(<span class="string">" "</span>);
builder.<span class="method">Append</span>(3);
</code></pre>
<h3><a id="MemoryExtensions.TryWrite">MemoryExtensions.TryWrite</h3>
<p><code>MemoryExtensions</code> (<code>System</code> 名前空間)に <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.memoryextensions.trywrite?view=net-6.0#System_MemoryExtensions_TryWrite_System_Span_System_Char__System_MemoryExtensions_TryWriteInterpolatedStringHandler__System_Int32__"><code>TryWrite</code></a> と言う名前で、
<code>Span&lt;char&gt;</code> バッファーに直接書き込みするメソッドも追加されています。
<code>string.Create</code> の場合は最終的に必ず1個は <code>new string()</code> が発生しますが、
<code>MemoryExtensions.TryWrite</code> なら完全にアロケーションなしで文字列補間ができます。
バッファー管理がちょっと大変ですが、一応、最速を目指すならこのメソッドを使うことになります。</p>
<pre class="source" title="TryWrite">
<code><span class="reserved">void</span> m(<span class="reserved">int</span> a,<span class="reserved">int</span> b,<span class="reserved">int</span> c,<span class="reserved">int</span> d)
{
    <span class="type">Span</span>&lt;<span class="reserved">char</span>&gt; buffer = <span class="reserved">stackalloc</span> <span class="reserved">char</span>[128];
    buffer.<span class="method">TryWrite</span>(<span class="string">$"</span>{a}<span class="string">.</span>{b}<span class="string">.</span>{c}<span class="string">.</span>{d}<span class="string">"</span>, <span class="reserved">out</span> <span class="reserved">var</span> charsWritten);

    <span class="comment">// デモ用なので ToString しちゃってるけども…</span>
    <span class="comment">// 工夫次第ではこの ToString 負担も避けれる。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(buffer[..charsWritten].ToString());
}
</code></pre>
<h3><a id="Debug.Assert">Debug.Assert</h3>
<p><code>Debug.Assert</code> (<code>System.Diagnostics</code> 名前空間)に<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.debug.assert?view=net-6.0#System_Diagnostics_Debug_Assert_System_Boolean_System_Diagnostics_Debug_AssertInterpolatedStringHandler__">ハンドラー型を受け取るオーバーロード</a>が増えています。</p>
<p>このオーバーロードを使うと、<code>condition</code> 引数が <code>false</code> の時だけ <code>AppendLiteral</code>/<code>AppendFormatted</code> を呼び出します。</p>
<pre class="source" title="Debug.Assert">
<code><span class="reserved">using</span> System.Diagnostics;

<span class="type">Debug</span>.<span class="method">Assert</span>(<span class="reserved">true</span>, <span class="string">$@"condition が true な限り、Append は全く呼ばれない。
(Assert の condition はバグがない限り true になっている想定でコードを書く物なので、めったに通らない。)
なので重たい処理を書いても割かし平気。</span>
{<span class="type">DateTime</span>.Now}
{<span class="type">Environment</span>.StackTrace}
{<span class="type">Environment</span>.UserName}
<span class="string">"</span>);
</code></pre> ]]></description>
				<pubDate>Thu, 23 Sep 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>パターン マッチング</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/patterns/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p><a href="/study/csharp/datatype/typeswitch/">前項</a>で説明した通り、C# 7.0で、<code>is</code>演算子と<code>swtich</code>ステートメントが拡張されて、<code>is</code>/<code>case</code>の後ろにパターンを書けるようになりました。
パターンには以下のようなものがあります。</p>
<table>
<thead>
<tr>
	<th>パターン</th>
	<th>バージョン</th>
	<th>概要</th>
	<th>例</th>
</tr>
</thead>
<tbody>
<tr>
	<td><a href="#declaration">型パターン</a></td>
	<td>C# 7.0</td>
	<td>型の判定</td>
	<td><code>int i</code>、<code>string s</code></td>
</tr>
<tr>
	<td><a href="#constant">定数パターン</a></td>
	<td>C# 7.0</td>
	<td>定数との比較</td>
	<td><code>null</code>、<code>1</code></td>
</tr>
<tr>
	<td><a href="#var">var パターン</a></td>
	<td>C# 7.0</td>
	<td>何にでもマッチ・変数で受け取り</td>
	<td><code>var x</code></td>
</tr>
<tr>
	<td><a href="#discard">破棄パターン</a></td>
	<td>C# 8.0</td>
	<td>何にでもマッチ・無視</td>
	<td><code>_</code></td>
</tr>
<tr>
	<td><a href="?p=2#positional">位置パターン</a></td>
	<td>C# 8.0</td>
	<td><a href="/study/csharp/datatype/deconstruction/">分解</a>と同じ要領で、再帰的にマッチングする</td>
	<td><code>(1, var i, _)</code></td>
</tr>
<tr>
	<td><a href="?p=2#property">プロパティ パターン</a></td>
	<td>C# 8.0</td>
	<td>プロパティに対して再帰的にマッチングする</td>
	<td><code>{ A: 1, B: var i }</code></td>
</tr>
<tr>
	<td><a href="?p=3#pattern-combintor">パターンの組み合わせ</a></td>
	<td>C# 9.0</td>
	<td><code>and</code> や <code>or</code> などでパターンの組み合わせができる</td>
	<td><code>int x and (x is 0 or 1)</code></td>
</tr>
<tr>
	<td><a href="?p=3#relational-patterns">関係演算パターン</a></td>
	<td>C# 9.0</td>
	<td><code>&lt;</code> や <code>&gt;</code> などで数値の範囲を指定してマッチングする</td>
	<td><code>&lt;= 0 and &lt; 10</code></td>
</tr>
<tr>
	<td><a href="?p=2#list">リスト パターン</a></td>
	<td>C# 11.0</td>
	<td>配列やリストなどにマッチ</td>
	<td><code>[]</code>, <code>[_, ..]</code></td>
</tr>
</tbody>
</table>
<p>サンプル コード: <a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Data/Patterns">https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Data/Patterns</a></p>
<h2><a id="nonrecursive">非再帰パターン</h2>
<h5 class="version version7">Ver. 7.0</h5>
<p>C# の文法上の区別する意味はないんですが、
パターンのうち、C# 7.0 で入ったものと 8.0 で入ったものの一番の差は再帰があるかどうかです。
C# 7.0 からあるパターンは1層限り、8.0 で追加されたパターンは再帰的に何層もマッチできます。
(再帰がある方が難しいので後からの追加になりました。)</p>
<p>ここではまず、文法が簡単な再帰のないパターンから説明していきます。</p>
<h3><a id="declaration">型パターン (宣言パターン)</h3>
<p>C# 6.0以前から元々あった <a href="/study/csharp/oo_polymorphism.html#is-operator"><code>is</code> 演算子</a>の自然な拡張になっているのが型パターン(type pattern)です。
以下のように、型の後ろに続けて、マッチした結果を変数で受け取れます。</p>
<pre class="source" title="型パターンの例">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <em><span class="reserved">int</span> <span class="variable">i</span></em>) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;int &quot;</span> + <span class="variable">i</span>);
    <span class="control">else</span> <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <em><span class="reserved">string</span> <span class="variable">s</span></em>) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;string &quot;</span> + <span class="variable">s</span>);
}
</code></pre>
<p><code>is</code> や <code>case</code> の後ろで変数宣言をしているような形なので、宣言パターン(declaration pattern)とも呼びます。
(というか、C# 8.0以降は宣言パターンの方が正式な呼び方に変わっていそうです。)</p>
<p>型パターンは、旧来からある <code>is</code> 演算子や <code>as</code> 演算子とほぼ同じ挙動です。
上記の例は、概ね以下のコードと同じ動作になります。</p>
<pre class="source" title="型パターンの挙動">
<code><span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">int</span>)
{
    <span class="reserved">var</span> <span class="variable">i</span> = (<span class="reserved">int</span>)<span class="variable">x</span>;
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;int &quot;</span> + <span class="variable">i</span>);
}
<span class="control">else</span>
{
    <span class="reserved">string</span> <span class="variable">s</span> = <span class="variable">x</span> <span class="reserved">as</span> <span class="reserved">string</span>;
    <span class="control">if</span> (<span class="variable">s</span> != <span class="reserved">null</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;string &quot;</span> + <span class="variable">s</span>);
    }
}
</code></pre>
<p><code>as</code> + <code>!= null</code> になっていることからわかる通り、
型パターンは null にはマッチしません。
(以下のように、たとえ変数の型が一致していたとしても、null にはマッチしません。)</p>
<pre class="source" title="型パターンは null にはマッチしない">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
{
    <span class="method">M</span>(<span class="string">&quot;abc&quot;</span>); <span class="comment">// matched abc</span>
    <span class="method">M</span>(<span class="reserved">null</span>);  <span class="comment">// 何も表示されない</span>
}
 
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">x</span>)
{
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">string</span> <span class="variable">s</span>) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;matched &quot;</span> + <span class="variable">s</span>);
}
</code></pre>
<h4><a id="simplified-type-pattern">型パターンの簡単化</h4>
<h5 class="version version9">Ver. 9.0</h5>
<p>C# 9.0 で型パターンがちょっとだけシンプルになりました。</p>
<p>型パターンは元々 C# 1.0 からある <code>is</code> 演算子の延長として作られています。
ところが、<code>is</code> の場合は <code>x is T</code> と書けるのに、<code>switch</code> では <code>T _</code> のように変数宣言か <code>_</code> (破棄) を伴う必要がありました。
これが C# 9.0 で改善されています。</p>
<pre class="source" title="型パターンの簡単化">
<code><span class="reserved">int</span> <span class="method">Is</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">string</span>)
    {
        <span class="control">return</span> 1;
    }
    <span class="control">return</span> 0;
}
 
<span class="reserved">int</span> <span class="method">Switch</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="control">switch</span> (<span class="variable">x</span>)
    {
        <span class="comment">// C# 8.0 までは string _ と書く必要あり</span>
        <span class="control">case</span> <span class="reserved">string</span>: <span class="control">return</span> 1;
    }
    <span class="control">return</span> 0;
}
 
<span class="reserved">int</span> <span class="method">SwitchExpr</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    <span class="comment">// C# 8.0 までは string _ と書く必要あり</span>
    <span class="reserved">string</span> =&gt; 1,
    <span class="reserved">_</span> =&gt; 0,
};
</code></pre>
<p>C# 9.0 時点でこれが書けたなかったのは次節の<a href="#constant">定数パターン</a>との混同を避けるためです。
例えば C# 9.0 では以下のようなコードが書けます。
こんなコードを書くこと自体少ないと思いますが、<code>is</code>の場合と<code>switch</code>の場合で、型と定数、どちらが優先されるかが違うので注意が必要です。</p>
<pre class="source" title="型パターンと定数パターンの区別">
<code><span class="reserved">class</span> <span class="type">X</span> { }
 
<span class="reserved">class</span> <span class="type">Program1</span>
{
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
    {
        <span class="type">X</span> =&gt; 1, <span class="comment">// これは x の型がクラス X</span>
        <span class="reserved">_</span> =&gt; 0,
    };
}
 
<span class="reserved">class</span> <span class="type">Program2</span>
{
    <span class="reserved">const</span> <span class="reserved">int</span> X = 1;
 
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M1</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
    {
        X =&gt; 1, <span class="comment">// これは定数 1</span>
        <span class="reserved">_</span> =&gt; 0,
    };
 
    <span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">M2</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="type">X</span>; <span class="comment">// でもこれはクラス X (C# 8.0 以前との互換性のため)</span>
}
</code></pre>
<h3><a id="constant">定数パターン</h3>
<p><code>is</code>や<code>case</code>の後ろには定数も書けます。これを定数パターン(constant pattern)と言います。
単体で見ると普通に <code>==</code> を使えば済むことも多いわけですが、
定数パターンであれば他のパターンとの混在ができます。</p>
<pre class="source" title="定数パターンの例">
<code><span class="control">switch</span> (<span class="variable">x</span>)
{
    <span class="comment">// 定数パターン</span>
    <span class="control">case</span> 0: <span class="control">return</span> 0;
    <span class="comment">// 型パターン</span>
    <span class="control">case</span> <span class="reserved">string</span> <span class="variable">s</span>: <span class="control">return</span> <span class="variable">s</span>.Length;
    <span class="control">default</span>: <span class="control">return</span> -1;
}
</code></pre>
<p>名前通り定数しか使えません。
変数との値比較がしたければ、<code>when</code>句を使うなどが必要です。</p>
<pre class="source" title="文字通り、定数パターンは定数のみ受け付ける">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">comparand</span>)
{
    <span class="control">switch</span> (<span class="variable">x</span>)
    {
        <span class="comment">// case comparand: とは書けない。</span>
        <span class="comment">// 型パターン + when 句を使う。</span>
        <span class="control">case</span> <span class="reserved">int</span> <span class="variable">i</span> <span class="reserved">when</span> <span class="variable">i</span> == <span class="variable">comparand</span>: <span class="control">return</span> 0;
        <span class="control">default</span>: <span class="control">return</span> -1;
    }
}
</code></pre>
<p>ちなみに、定数パターンでは、<a href="/study/csharp/oo_operator.html#udo">ユーザー定義演算子</a>を見ません。
以下のように、<code>==</code>と<code>is</code>で挙動が違う場合があります。</p>
<pre class="source" title="定数パターンはユーザー定義の演算子を見ない">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">X</span>
{
    <span class="comment">// 全てのインスタンスが等しいという挙動。</span>
    <span class="comment">// 当然、x == null も常に true。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="reserved">operator</span> ==(<span class="type">X</span> <span class="variable">a</span>, <span class="type">X</span> <span class="variable">b</span>) =&gt; <span class="reserved">true</span>;
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="reserved">operator</span> !=(<span class="type">X</span> <span class="variable">a</span>, <span class="type">X</span> <span class="variable">b</span>) =&gt; <span class="reserved">false</span>;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">X</span>();
 
        <span class="comment">// なんでも true なので、== null も true</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span> <span class="method">==</span> <span class="reserved">null</span>);
 
        <span class="comment">// ユーザー定義の == は見ない。x が本当に null かどうかを見て、false になる</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">null</span>);
    }
}
</code></pre>
<h4><a id="pointer-null">ポインターの null 比較</h4>
<h5 class="version version8">Ver. 8.0</h5>
<p>細かい修正ですが、C# 8.0 からポインターに対してもパターン マッチングが使えるようになりました。
といってもプロパティや <code>Deconstruct</code> メソッドを持っているわけではないので、実質的には <code>is null</code> チェック用です。</p>
<pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">unsafe</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span>* <span class="variable">p</span>)
{
    <span class="comment">// 元々 OK。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">p</span> == <span class="reserved">null</span>);
 
    <span class="comment">// C# 8.0 から OK。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">p</span> <span class="reserved">is</span> <span class="reserved">null</span>);
}
</code></pre>
<h4><a id="span">ReadOnlySpan に対するパターンマッチ</a></h4>
<h5 class="version version11">Ver. 11</h5>
<p>C# 11 で、<code>ReadOnlySpan&lt;char&gt;</code> に対して文字列リテラルによる定数パターンが使えるようになりました。</p>
<pre class="source" title="">
<span class="comment">// string を渡せたところには ReadOnlySpan&lt;char&gt; を渡せるように。</span>
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">char</span>&gt; <span class="variable">s</span> <span class="operator">=</span> <span class="type"><span class="static">Console</span></span><span class="operator">.</span><span class="method"><span class="static">ReadLine</span></span>();

<span class="comment">// is も</span>
<span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> <span class="string">&quot;a&quot;</span>) { }

<span class="comment">// switch ステートメントも</span>
<span class="control">switch</span> (<span class="variable">s</span>)
{
    <span class="control">case</span> <span class="string">&quot;b&quot;</span>:
        <span class="control">break</span>;
}

<span class="comment">// switch 式も OK。</span>
<span class="reserved">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="variable">s</span> <span class="control">switch</span>
{
    <span class="string">&quot;c&quot;</span> <span class="operator">=&gt;</span> <span class="number">1</span>,
    <span class="reserved">_</span> <span class="operator">=&gt;</span> <span class="number">2</span>,
};
</pre>
<p>文字列処理に対して <code>ReadOnlySpan&lt;char&gt;</code> を使う機会が多くなってきたので特殊対応したそうです。</p>
<p>(パターンに書かれているのは <code>&quot;&quot;</code> みたいな「定数」ですが、
そこに <code>string</code> から <code>ReadOnlySpan&lt;char&gt;</code> の変換が挟まっていて定数とは言い切れない状態です。
C# チーム自身はそれほど実装に乗り気ではなく、外部からのコントリビューションで実装された機能になります。)</p>
<h3><a id="var">var パターン</h3>
<p>型パターンと似ていますが、具体的な型名の代わりに <code>var</code> キーワードを使うと、
任意の型にマッチするパターンになります。
これを var パターン (var pattern)と言います。</p>
<p><code>switch</code> の最後に書いて「その他全部」な分岐に使ったりします。</p>
<pre class="source" title="var パターンを「その他全部」の意味で使う例">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="control">switch</span>(<span class="variable">x</span>)
    {
        <span class="control">case</span> 0: <span class="control">return</span> 0;
        <span class="control">case</span> <span class="reserved">string</span> <span class="variable">s</span>: <span class="control">return</span> <span class="variable">s</span>.Length;
        <span class="control">case</span> <em><span class="reserved">var</span> other</em>: <span class="control">return</span> <span class="variable">other</span>.<span class="method">GetHashCode</span>();
        <span class="comment">// あるいは、変数で受け取る必要がないときは _ にしておけば破棄の意味なる</span>
        <span class="comment">// case var _:</span>
    }
}
</code></pre>
<p>あと、少し悪用気味ではありますが、式中での変数宣言に使えたりします。</p>
<pre class="source" title="式中での変数宣言代わりに var パターンを利用">
<code><span class="control">while</span> (<span class="type">Console</span>.<span class="method">ReadLine</span>() <span class="reserved">is</span> <em><span class="reserved">var</span> line</em> &amp;&amp; !<span class="reserved">string</span>.<span class="method">IsNullOrEmpty</span>(<span class="variable">line</span>))
{
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">line</span>);
}
</code></pre>
<p>1つ注意が必要な点として、var パターンは型パターンと違って、null にもマッチします。</p>
<pre class="source" title="var パターンは null にもマッチ">
<code><span class="reserved">string</span> <span class="variable">s</span> = <span class="reserved">null</span>;
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span> <span class="reserved">is</span> <span class="reserved">string</span> <span class="variable">x</span>); <span class="comment">// false</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span> <span class="reserved">is</span> <span class="reserved">var</span> y);    <span class="comment">// true</span>
</code></pre>
<p>null をはじきたい場合は、var ではなく、後述するプロパティ パターンを使って<code>x is {} nonNull</code>と書いたりします。</p>
<h3><a id="discard">破棄パターン</h3>
<h5 class="version version8">Ver. 8.0</h5>
<p>何にでもマッチして、マッチ結果を受け取る必要がない場合、<code>_</code> を使って値を破棄できます。これを破棄パターン(discard pattern)と言います。</p>
<p>再帰はしないんですが、<code>switch</code>式の中と、再帰パターン内でしか使えないので C# 8.0 での実装になります。
<code>is</code>やステートメントの方の<code>switch</code>の<code>case</code>の後ろでは<code>var _</code>と書く必要がありますが、<code>switch</code>式の場合は<code>_</code>だけで値を破棄します。</p>
<pre class="source" title="switch 式中では、_ だけで値を破棄できる">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
    =&gt; <span class="variable">x</span> <span class="reserved">switch</span>
    {
        0 =&gt; 0,
        <span class="reserved">string</span> <span class="variable">s</span> =&gt; <span class="variable">s</span>.Length,
        <em><span class="reserved">_</span></em> =&gt; -1
    };
</code></pre>
<h3><a id="breaking-change-in-discard">余談: 破棄パターンが C# 8.0 からな理由</h3>
<p>ちなみに、<code>is</code> や <code>switch</code>ステートメント内で <code>_</code> だけでの値の破棄ができないのは既存コードとの互換性のためです。
普通書かないようなコードですが、一応、以下のようなコードが元々合法なため、意味を変えることができませんでした。</p>
<pre class="source" title="_ クラス、 _ 定数">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">_Type</span>
{
    <span class="reserved">class</span> <span class="type">_</span> { }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span> <span class="reserved">is</span> <span class="type">_</span>); <span class="comment">// class _ とのマッチ</span>
    }
}
 
<span class="reserved">class</span> <span class="type">_Constant</span>
{
    <span class="reserved">const</span> <span class="reserved">int</span> _ = 0;
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
    {
        <span class="control">switch</span> (<span class="variable">x</span>)
        {
            <span class="control">case</span> _: <span class="comment">// 定数 _ とのマッチ</span>
                <span class="control">break</span>;
        }
    }
}
</code></pre>
<p>(あまりにも紛らわしいので、このコードを C# 8.0 でコンパイルすると警告が出ます。)</p>
<!-- pageBreak -->
<h2><a id="recursive">再帰パターン</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 7.0 の範囲で使えるものは、「パターン」と呼ぶのが仰々しいくらい単純なものでした。
C# 8.0 で、再帰的に使えるパターンが追加されて、ようやくパターン マッチングらしくなりました。</p>
<p>例えば以下のような感じです。</p>
<pre class="source" title="再帰パターンの例">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="method">Point</span>(<span class="reserved">int</span> <span class="variable">x</span> = 0, <span class="reserved">int</span> <span class="variable">y</span> = 0) =&gt; (X, Y) = (<span class="variable">x</span>, <span class="variable">y</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">y</span>) =&gt; (<span class="variable">x</span>, <span class="variable">y</span>) = (X, Y);
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>)
        =&gt; <span class="variable">obj</span> <span class="reserved">switch</span>
    {
        0 =&gt; 1,
        <span class="reserved">int</span> <span class="variable">i</span> =&gt; 2,
        <em><span class="type">Point</span> (1, <span class="reserved">_</span>)</em> =&gt; 4, <span class="comment">// new!</span>
        <em><span class="type">Point</span> { X: 2, Y: <span class="reserved">var</span> y }</em> =&gt; <span class="variable">y</span>, <span class="comment">// new!</span>
        <span class="reserved">_</span> =&gt; 0
    };
}
</code></pre>
<h3><a id="positional">位置パターン</h3>
<p>位置パターン (positional pattern)は、
<a href="/study/csharp/datatype/deconstruction/">分解</a>と同じ要領で再帰的なマッチングを行うパターンです。</p>
<p>分解と同様、<code>Deconstruct</code>メソッドを呼んでメンバーを取り出した上で、
それぞれのメンバーの値に対してマッチングを行います。
例えば、先ほど例として使った<code>Point</code>クラスを引き続き使うとして、以下のように書けます。</p>
<pre class="source" title="位置パターンの例">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="type">Point</span> <span class="variable">p</span>)
    =&gt; <span class="variable">p</span> <span class="reserved">switch</span>
{
    (1, 2) =&gt; 0,
    (<span class="reserved">var</span> x, <span class="reserved">_</span>) <span class="reserved">when</span> x &gt; 0 =&gt; <span class="variable">x</span>,
    <span class="reserved">_</span> =&gt; -1
};
</code></pre>
<p>このコードは概ね以下のような意味になります。</p>
<pre class="source" title="位置パターンの展開結果">
<code><span class="variable">p</span>.<span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">x</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">y</span>);
<span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> 1 &amp;&amp; <span class="variable">y</span> <span class="reserved">is</span> 2) <span class="control">return</span> 0;
<span class="control">if</span> (<span class="variable">x</span> &gt; 0) <span class="control">return</span> <span class="variable">x</span>;
<span class="control">return</span> -1;
</code></pre>
<p>サブパターンの順序に意味があるため「位置」パターンという呼び名になっています。</p>
<p>上記の例では元々型が<code>Point</code>だとわかっているので型名を省略していますが、
型の明示もできます。</p>
<pre class="source" title="位置パターンでの型の明示">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>)
    =&gt; <span class="variable">obj</span> <span class="reserved">switch</span>
{
    <span class="reserved">int</span> <span class="variable">i</span> =&gt; <span class="variable">i</span>,
    <span class="reserved">string</span> <span class="variable">s</span> =&gt; <span class="variable">s</span>.Length,
    <em><span class="type">Point</span>(<span class="reserved">var</span> x, <span class="reserved">var</span> y)</em> =&gt; 0,
    <span class="reserved">_</span> =&gt; -1
};
</code></pre>
<p>また、後述しますが、プロパティ パターンとの混在や、
型パターンのように変数を付け足すこともできます。</p>
<pre class="source" title="位置パターン、プロパティ パターン、型パターンの組み合わせ">
<code><span class="variable">obj</span> <span class="reserved">switch</span>
{
    <span class="type">Point</span> (<span class="reserved">var</span> x, <span class="reserved">_</span>) { Y: <span class="reserved">var</span> y } p =&gt; <span class="variable">x</span> * <span class="variable">y</span>
};
</code></pre>
<p>位置パターンとか言いつつ、名前付き引数のノリで、名前付きなパターン マッチングもできます。</p>
<pre class="source" title="名前付き位置パターン">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">NamedPattern</span>(<span class="type">Point</span> <span class="variable">p</span>)
    =&gt; <span class="variable">p</span> <span class="reserved">switch</span>
{
    (<em><span class="variable">x</span>:</em> 1, <em><span class="variable">y</span>:</em> 2) =&gt; 0,
    (<em><span class="variable">x</span>:</em> <span class="reserved">var</span> x, <em><span class="variable">y</span>:</em> <span class="reserved">_</span>) <span class="reserved">when</span> <span class="variable">x</span> &gt; 0 =&gt; <span class="variable">x</span>,
    <span class="reserved">_</span> =&gt; -1
};
</code></pre>
<h4><a id="constructor-vs-positional">補足: コンストラクター呼び出しの逆</h4>
<p>位置パターンは、コンストラクター呼び出し(<code>new</code>)の逆に当たる構文です。
書き方も、コンストラクターと対になっています。</p>
<pre class="source" title="コンストラクター呼び出しと位置パターン">
<code><span class="comment">// 位置指定で構築できるんなら、位置指定でマッチングできるべき</span>
<span class="reserved">var</span> <span class="variable">p1</span> = <span class="reserved">new</span> <span class="type">Point</span>(1, 2);
<span class="reserved">var</span> <span class="variable">r1</span> = <span class="variable">p1</span> <span class="reserved">is</span> <span class="type">Point</span> (1, 2);
 
<span class="comment">// 名前指定で構築できるんなら、名前指定でマッチングできるべき</span>
<span class="reserved">var</span> <span class="variable">p2</span> = <span class="reserved">new</span> <span class="type">Point</span>(<span class="variable">x</span>: 1, <span class="variable">y</span>: 2);
<span class="reserved">var</span> <span class="variable">r2</span> = <span class="variable">p2</span> <span class="reserved">is</span> <span class="type">Point</span> (<span class="variable">x</span>: 1, <span class="variable">y</span>: 2);
 
<span class="comment">// 型推論が効く場合に new の後ろの型名は省略可能(になる予定)なら</span>
<span class="comment">// 型が既知なら型名を省略してマッチングできるべき</span>
<span class="type">Point</span> <span class="variable">p3</span> = <span class="reserved">new</span> (1, 2);
<span class="reserved">var</span> <span class="variable">r3</span> = <span class="variable">p3</span> <span class="reserved">is</span> (1, 2);
 
<span class="comment">// 階層的に new できるんなら、階層的にマッチングできるべき</span>
<span class="reserved">var</span> <span class="variable">line</span> = <span class="reserved">new</span> <span class="type">Line</span>(<span class="reserved">new</span> <span class="type">Point</span>(1, 2), <span class="reserved">new</span> <span class="type">Point</span>(3, 4));
<span class="reserved">var</span> <span class="variable">r4</span> = <span class="variable">line</span> <span class="reserved">is</span> ((1, 2), (3, 4));
</code></pre>
<h4><a id="how-to-deconstruct">分解方法</h4>
<p>位置パターンは <a href="/study/csharp/datatype/deconstruction/">分解</a>と同じ要領でメンバーの値を取り出します。
分解もそうなんですが、<a href="/study/csharp/datatype/tuples/">タプル</a>(C# のタプル構文を使って作る <code>ValueTuple</code> 構造体の値)の場合とそうでない場合で内部的な挙動が少し変わります。</p>
<p>まず、タプルの場合、コンパイラーの最適化によって、タプルのフィールドを直接参照するようなコードが生成されます。
例えば以下のようなコードを書いた場合、</p>
<pre class="source" title="タプルに対する位置パターン">
<code><span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">TupleSyntax</span>((<span class="reserved">int</span> a, <span class="reserved">int</span> b) <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> (1, 2);
</code></pre>
<p>以下のようなコードと同じような挙動をします。</p>
<pre class="source" title="タプルに対する位置パターンの展開結果">
<code><span class="comment">// ValueTuple の場合は直接フィールドを参照する。</span>
<span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">TupleSyntax</span>((<span class="reserved">int</span> a, <span class="reserved">int</span> b) <span class="variable">x</span>)
{
    <span class="control">return</span> <span class="variable">x</span>.a == 1 &amp;&amp; <span class="variable">x</span>.b == 2;
}
</code></pre>
<p>そうでない場合、まずはコンパイル時に <code>Deconstruct</code> メソッドを探します。
見つかった場合は、それを使うコードが生成されます。
例として以下のようなクラスを用意します。</p>
<pre class="source" title="分解可能なクラス">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

<span class="reserved">class</span> <span class="type">X</span> : <span class="type">ITuple</span>
{
    <span class="reserved">public</span> <span class="reserved">object</span> <span class="reserved">this</span>[<span class="reserved">int</span> <span class="variable">index</span>] =&gt; <span class="variable">index</span>;
    <span class="reserved">public</span> <span class="reserved">int</span> Length =&gt; 2;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">a</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">b</span>) =&gt; (<span class="variable">a</span>, <span class="variable">b</span>) = (0, 1);
}
</code></pre>
<p>この型に対して以下のようなコードを書いた場合、</p>
<pre class="source" title="コンパイル時に Deconstruct メソッドが見つかる場合">
<code><span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">Deconstruct</span>(<span class="type">X</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> (1, 2);
</code></pre>
<p>以下のようなコードと同じような挙動をします。</p>
<pre class="source" title="コンパイル時に Deconstruct メソッドが見つかる場合の展開結果">
<code><span class="comment">// コンパイル時に Deconstruct メソッドが見つかる場合はそれを使って分解。</span>
<span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">Deconstruct</span>(<span class="type">X</span> <span class="variable">x</span>)
{
    <span class="variable">x</span>.<span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">a</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">b</span>);
    <span class="control">return</span> <span class="variable">a</span> == 1 &amp;&amp; <span class="variable">b</span> == 2;
}
</code></pre>
<p>分解代入や分解変数宣言とは違って、位置パターンの場合はコンパイル時に <code>Deconstruct</code> メソッドが見つからない場合があります。
この場合、<code>ITuple</code>インターフェイス(<code>System.Runtime.CompilerServices</code>名前空間)を使って分解を試みます。
例えば以下のように<code>object</code>で値を渡すコードを書いた場合、</p>
<pre class="source" title="コンパイル時に Deconstruct メソッドが見つからない場合">
<code><span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">Object</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> (1, 2);
</code></pre>
<p>以下のようなコードと同じような挙動をします。</p>
<pre class="source" title="コンパイル時に Deconstruct メソッドが見つからない場合の展開結果">
<code><span class="comment">// コンパイル時の解決ができない場合、ITuple を実装しているかどうかを見る。</span>
<span class="comment">// Length とインデクサーを使ってマッチング。</span>
<span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">Object</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="control">return</span> <span class="variable">x</span> <span class="reserved">is</span> <span class="type">ITuple</span> <span class="variable">t</span>
        &amp;&amp; <span class="variable">t</span>.Length == 2
        &amp;&amp; <span class="variable">t</span>[0] <span class="reserved">is</span> <span class="reserved">int</span> <span class="variable">a</span> &amp;&amp; <span class="variable">a</span> == 1
        &amp;&amp; <span class="variable">t</span>[1] <span class="reserved">is</span> <span class="reserved">int</span> <span class="variable">b</span> &amp;&amp; <span class="variable">b</span> == 1
        ;
}
</code></pre>
<h4><a id="tuple-switch">タプル switch</h4>
<p>位置パターンに伴って、<code>switch</code>ステートメントの <code>()</code> の中に、複数の値を <code>,</code> 区切りで書けるようになりました。</p>
<pre class="source" title="複数の値に対する switch">
<code><span class="reserved">int</span> <span class="method">Compare</span>(<span class="reserved">int</span>? <span class="variable">a</span>, <span class="reserved">int</span>? <span class="variable">b</span>)
{
    <em><span class="control">switch</span> (<span class="variable">a</span>, <span class="variable">b</span>)</em>
    {
        <span class="control">case</span> (<span class="reserved">null</span>, <span class="reserved">null</span>): <span class="control">return</span> 0;
        <span class="control">case</span> (<span class="reserved">int</span> <span class="reserved">_</span>, <span class="reserved">null</span>): <span class="control">return</span> -1;
        <span class="control">case</span> (<span class="reserved">null</span>, <span class="reserved">int</span> <span class="reserved">_</span>): <span class="control">return</span> -1;
        <span class="control">case</span> (<span class="reserved">int</span> <span class="variable">a1</span>, <span class="reserved">int</span> <span class="variable">b1</span>): <span class="control">return</span> <span class="variable">a1</span>.<span class="method">CompareTo</span>(<span class="variable">b1</span>);
    }
}
</code></pre>
<p>このコードは、まず <code>(a, b)</code> というタプルを作って、それを <code>switch</code> ステートメントに掛ける挙動になります。<code>case</code> の後ろに書かれているのは位置パターンです。</p>
<p>要するに、意味としては <code>switch ((a, b))</code> と書くのと同じです。
なので実体としては「複数の値に対する<code>switch</code>」というより、「タプルに限り、<code>()</code> を一段省略できる」という機能です。</p>
<h4><a id="zero-or-one">0、1要素の分解</h4>
<p>タプル構築や分解代入・分解宣言では0、1要素のもの( <code>()</code> や <code>(x)</code>) は認められていませんが、
位置パターンでは認められるようになりました。
それぞれ、0、1引数の<code>Deconstruct</code>メソッドが調べられます。</p>
<pre class="source" title="">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">X</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>() { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">a</span>) =&gt; <span class="variable">a</span> = 0;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>() =&gt; <span class="method">M</span>(<span class="reserved">new</span> <span class="type">X</span>());
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">X</span> <span class="variable">x</span>)
    {
        <span class="comment">// 0 引数の位置パターン。</span>
        <span class="comment">// Deconstruct() を持っていることが使える条件。</span>
        <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> ()) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Deconstruct()&quot;</span>);
 
        <span class="comment">// 1 引数の位置パターン。</span>
        <span class="comment">// Deconstruct(out T) を持っていることが使える条件。</span>
        <span class="comment">// ただ、キャストの () との区別が難しいらしく、素直に x is (int a) とは書けない。</span>
        <span class="comment">// 前後に余計な var や _ を付ける必要あり。</span>
        <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> (<span class="reserved">int</span> <span class="variable">a</span>) <span class="reserved">_</span>) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;Deconstruct(</span>{<span class="variable">a</span>}<span class="string">)&quot;</span>);
    }
}
</code></pre>
<p>0引数のものは単に <code>()</code> で OK です。</p>
<p>一方で、1引数のものは、キャストの <code>()</code> との区別が難しいそうで、
素直に <code>(constant)</code> とか <code>(T variable)</code> とかは書けません。
<code>var (subpattern)</code> とか <code>(subpattern) _</code> とか、前後に余計なものを付けることでキャストと区別します。</p>
<h3><a id="remove-deconstruct">最適化での Deconstruct 削除</h3>
<p>位置パターンでは、コンパイラーの最適化によって <code>Deconstruct</code> メソッドの呼び出しが消えることがあります。
以下のように、すべて <code>_</code> で値を破棄してしまう場合には <code>Deconstruct</code> メソッドを呼び出す必要がなく、
実際、呼び出しが消えてなくなります。</p>
<pre class="source" title="Deconstruct が常に呼ばれる保証はない">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">X</span>
{
    <span class="comment">// Deconstruct に副作用を持たせる</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>() =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Deconstruct()&quot;</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">a</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Deconstruct(out int a)&quot;</span>);
        <span class="variable">a</span> = 0;
    }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">a</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">b</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Deconstruct(out int a, out int b)&quot;</span>);
        (<span class="variable">a</span>, <span class="variable">b</span>) = (0, 0);
    }
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">X</span>();
 
        <span class="comment">// Deconstruct() がないとコンパイル エラーになるけど、</span>
        <span class="comment">// Deconstruct() は呼ばれない。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span> <span class="reserved">is</span> ());
 
        <span class="comment">// Deconstruct(out int) がないとコンパイル エラーになるけど、</span>
        <span class="comment">// Deconstruct(out int) は呼ばれない。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">var</span> (<span class="reserved">_</span>));
 
        <span class="comment">// Deconstruct(out int, out int) がないとコンパイル エラーになるけど、</span>
        <span class="comment">// Deconstruct(out int, out int) は呼ばれない。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span> <span class="reserved">is</span> (<span class="reserved">_</span>, <span class="reserved">_</span>));
    }
}
</code></pre>
<p>また、引数の数が同じ位置パターンをいくつか並べた際にも、<code>Deconstruct</code> メソッドの呼び出しは1回にまとめられます。</p>
<pre class="source" title="引数の数が同じ位置パターンを並べる例">
<code><span class="reserved">class</span> <span class="type">X</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> Value { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="method">X</span>(<span class="reserved">int</span> <span class="variable">value</span>) =&gt; Value = <span class="variable">value</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">value</span>) =&gt; <span class="variable">value</span> = Value;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="type">X</span> <span class="variable">x</span>)
        =&gt; <span class="variable">x</span> <span class="reserved">switch</span>
    {
        <span class="comment">// 引数の数が同じ位置パターンを3回。</span>
        <span class="comment">// この場合、Deconstruct(out int) の呼び出しは1回にまとめられる。</span>
        (0) <span class="reserved">_</span> =&gt; 1,
        (1) <span class="reserved">_</span> =&gt; 2,
        (2) <span class="reserved">_</span> =&gt; 0,
        <span class="reserved">_</span> =&gt; <span class="variable">x</span>.Value
    };
}
</code></pre>
<p>ちなみに、仕様上は「必ず消える」という保証もないです(「消えることがある」という仕様)。
なので、<code>Deconstruct</code> メソッドは副作用を起こさないように作ることが推奨されます。</p>
<h3><a id="property">プロパティ パターン</h3>
<p>プロパティ パターン(property pattern)は、プロパティに対して再帰的なマッチングを行うパターンです。
(プロパティ パターンという名前に反して、フィールドも使えます。)</p>
<p>書き方は、<code>{ PropertyName: SubPattern, ... }</code> というように、
プロパティ名と、そのプロパティに対して掛けたいパターンを <code>:</code> でつなぎます。
複数のプロパティに対して使う場合はそれぞれを <code>,</code> で区切ります。
位置パターンとは違って、名前の省略はできません。</p>
<p>再び <code>Point</code> クラス(<code>int</code> 型の2つのプロパティ <code>X</code>、<code>Y</code> を持つ)を例に挙げます。
以下のような書き方ができます。</p>
<pre class="source" title="プロパティ パターンの例">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="type">Point</span> <span class="variable">p</span>)
    =&gt; <span class="variable">p</span> <span class="reserved">switch</span>
{
    { X: 1, Y: 2 } =&gt; 0,
    { X: <span class="reserved">var</span> x, Y: <span class="reserved">_</span> } <span class="reserved">when</span> <span class="variable">x</span> &gt; 0 =&gt; <span class="variable">x</span>,
    <span class="reserved">_</span> =&gt; -1
};
</code></pre>
<p>このコードは概ね以下のような意味になります。</p>
<pre class="source" title="プロパティ パターンの展開結果">
<code><span class="reserved">var</span> <span class="variable">x</span> = <span class="variable">p</span>.X;
<span class="reserved">var</span> <span class="variable">y</span> = <span class="variable">p</span>.Y;
<span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> 1 &amp;&amp; <span class="variable">y</span> <span class="reserved">is</span> 2) <span class="control">return</span> 0;
<span class="control">if</span> (<span class="variable">x</span> &gt; 0) <span class="control">return</span> <span class="variable">x</span>;
<span class="control">return</span> -1;
</code></pre>
<p>位置パターンと同様、型の明示もできます。</p>
<pre class="source" title="プロパティ パターンでの型の明示">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>)
    =&gt; <span class="variable">obj</span> <span class="reserved">switch</span>
{
    <span class="reserved">int</span> <span class="variable">i</span> =&gt; <span class="variable">i</span>,
    <span class="reserved">string</span> <span class="variable">s</span> =&gt; <span class="variable">s</span>.Length,
    <em><span class="type">Point</span> { X: 0, Y: 0 }</em> =&gt; 0,
    <span class="type">Point</span> (<span class="reserved">_</span>, <span class="reserved">_</span>) =&gt; 1,
    <span class="reserved">_</span> =&gt; -1
};
</code></pre>
<p>ちなみに、プロパティ パターンと言いつつ、フィールドも参照できます。</p>
<pre class="source" title="プロパティ パターンでフィールドを参照する例">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">X</span>
{
    <span class="comment">// (外から見て) get-only なプロパティ</span>
    <span class="reserved">public</span> <span class="reserved">int</span> GetOnly { <span class="reserved">get</span>; <span class="reserved">private</span> <span class="reserved">set</span>; }
 
    <span class="comment">// get/set 可能なプロパティ</span>
    <span class="reserved">public</span> <span class="reserved">int</span> GetSet { <span class="reserved">get</span>; <span class="reserved">set</span>; }
 
    <span class="comment">// フィールド</span>
    <span class="reserved">public</span> <span class="reserved">int</span> Field;
 
    <span class="comment">// set-only なプロパティ</span>
    <span class="reserved">public</span> <span class="reserved">int</span> SetOnly { <span class="reserved">set</span> =&gt; GetOnly = <span class="reserved">value</span>; }
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// オブジェクト初期化子では、set が public なプロパティか readonly ではないフィールドを指定可能</span>
        <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">X</span> { GetSet = 1, Field = 2, SetOnly = 3 };
 
        <span class="comment">// プロパティ パターンでは、get が public なプロパティかフィールドを指定可能</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span> <span class="reserved">is</span> { GetOnly: 3, GetSet: 1, Field: 2 });
    }
}
</code></pre>
<h4><a id="initializer-vs-property">オブジェクト初期化子の逆</h4>
<p>「位置パターンはコンストラクター呼び出しの逆」という話をしましたが、
同様に、プロパティ パターンは<a href="/study/csharp/oo_construct.html#member_initializer">オブジェクト初期化子</a>と対になるものです。</p>
<pre class="source" title="オブジェクト初期化子とプロパティ パターン">
<code><span class="comment">// 初期化子でプロパティ指定できるんなら、プロパティ指定でマッチングできるべき</span>
<span class="reserved">var</span> <span class="variable">p1</span> = <span class="reserved">new</span> <span class="type">Point</span> { X = 1, Y = 2 };
<span class="reserved">var</span> <span class="variable">r1</span> = <span class="variable">p1</span> <span class="reserved">is</span> { X: 1, Y: 2 };
 
<span class="comment">// 混在で構築できるんなら、混在でマッチングできるべき</span>
<span class="reserved">var</span> <span class="variable">p2</span> = <span class="reserved">new</span> <span class="type">Point</span>(<span class="variable">x</span>: 1) { Y = 2 };
<span class="reserved">var</span> <span class="variable">r2</span> = <span class="variable">p2</span> <span class="reserved">is</span> (1, <span class="reserved">_</span>) { Y: 2 };
</code></pre>
<p>ただ、<code>=</code> は代入の意味なのでパターンとしては使えず、代わりに <code>:</code> になっています。
<code>:</code> を使っているのは、位置パターンと構文を共通化できて実装が楽だからだそうです。</p>
<h4><a id="no-order">位置パターンとプロパティ パターンの順序</h4>
<p>位置パターンとプロパティ パターンを混在して使う場合、
<code>Deconstruct</code>メソッドとプロパティのアクセサーの呼び出し順序には<em>保証がない</em>そうです。</p>
<p>残念ながら、以下のようなコードには動作保証がないそうです。</p>
<pre class="source" title="順序保障がないとまずいコードの例">
<code><span class="reserved">using</span> System;
 
<span class="reserved">enum</span> <span class="type">Type</span> { A, B }
 
<span class="reserved">class</span> <span class="type">X</span>
{
    <span class="reserved">public</span> <span class="type">Type</span> Type { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="method">X</span>(<span class="type">Type</span> <span class="variable">type</span>) =&gt; Type = <span class="variable">type</span>;
 
    <span class="comment">// それぞれ Type が一致しているときだけ値を取り出せ、そうでなければ例外</span>
    <span class="reserved">public</span> <span class="reserved">int</span> A =&gt; Type == <span class="type">Type</span>.A ? 1 : <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">InvalidOperationException</span>();
    <span class="reserved">public</span> <span class="reserved">int</span> B =&gt; Type == <span class="type">Type</span>.B ? 2 : <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">InvalidOperationException</span>();
 
    <span class="comment">// 分解でタイプ判定</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="type">Type</span> <span class="variable">t</span>) =&gt; <span class="variable">t</span> = Type;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">M</span>(<span class="reserved">new</span> <span class="type">X</span>(<span class="type">Type</span>.A)));
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">M</span>(<span class="reserved">new</span> <span class="type">X</span>(<span class="type">Type</span>.B)));
    }
 
    <span class="comment">// 以下のコードはたまたま動く可能性はあるものの、C# の言語使用としては保証がない。</span>
    <span class="comment">// Deconstruct よりも先にプロパティのアクセスがあると例外が出ることがある。</span>
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="type">X</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">switch</span>
    {
        (<span class="type">Type</span>.A) { A: <span class="reserved">var</span> a } =&gt; <span class="variable">a</span>,
        (<span class="type">Type</span>.B) { B: <span class="reserved">var</span> b } =&gt; <span class="variable">b</span>,
        <span class="reserved">_</span> =&gt; 0
    };
}
</code></pre>
<h4><a id="non-null">非 null マッチング</h4>
<p>プロパティ パターンは、暗黙的にnullチェックが挟まって、非 null であることが保証されます。
しかも、<code>x is { }</code> というように、中身が空っぽであっても null チェックだけは挿入されるので、 <code>x is { }</code>を「<code>x</code>はnullではない」の意味で使えます。</p>
<p>C# 7.0 までのパターンだと、null チェックを楽に書く手段がなかったです。</p>
<pre class="source" title="C# 7.0 時点のパターンでの非 null パターン">
<code><span class="reserved">struct</span> <span class="type">LongLongNamedStruct</span> { }
 
<span class="reserved">void</span> <span class="method">M1</span>(<span class="type">LongLongNamedStruct</span>? <span class="variable">x</span>)
{
    <span class="comment">// こういう書き方だと null チェックになる。</span>
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="type">LongLongNamedStruct</span> <span class="variable">nonNull</span>)
    {
        <span class="comment">// obj が null じゃない時だけここが実行される。</span>
        <span class="comment">// でも、x の型が既知なのに、長いクラス名をわざわざ書くのはしんどい…</span>
    }
}
 
<span class="reserved">void</span> <span class="method">M2</span>(<span class="type">LongLongNamedStruct</span>? <span class="variable">x</span>)
{
    <span class="comment">// が、var パターンは null にもマッチしちゃう。</span>
    <span class="comment">// (var は「何にでもマッチ」。null でも true になっちゃう。)</span>
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">var</span> nullable)
    {
        <span class="comment">// obj が null でもここが実行される。</span>
    }
}
</code></pre>
<p>単に null チェックだけなら <code>!(x is null)</code> とか <code>x.HasValue</code> だけでいいんですけども、 値を使いたければその後ろで <code>var nonNull = x.GetValueOrDefault();</code> とかが必要で、何を使うにしても微妙に長くなりがちでした。</p>
<p>そこで先ほどの <code>x is { }</code> を使います。
以下のような書き方で、null 許容型の null チェックをしつつ、値を変数に受け取れます。</p>
<pre class="source" title="C# 8.0 での非 null パターン">
<code><span class="reserved">void</span> <span class="method">M3</span>(<span class="type">LongLongNamedStruct</span>? <span class="variable">x</span>)
{
    <span class="comment">// (C# 8.0) プロパティ パターンであれば、null チェックを含む。</span>
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> { } nonNull)
    {
        <span class="comment">// obj が null じゃない時だけここが実行される。</span>
    }
}
</code></pre>
<h4><a id="sub-pattern-name">プロパティ パターンの拡張(入れ子のメンバー参照)</h4>
<h5 class="version version10">Ver. 10</h5>
<p>C# 10.0 で、以下のように、入れ子のプロパティ・フィールド参照でプロパティ パターンを書けるようになりました。</p>
<pre class="source" title="入れ子のプロパティ参照">
<code><span class="method">m</span>(<span class="reserved">null</span>);
<span class="method">m</span>(<span class="reserved">new</span> <span class="type">X</span> { Name = <span class="string">""</span> });
<span class="method">m</span>(<span class="reserved">new</span> <span class="type">X</span> { Name = <span class="string">"a"</span> });
<span class="method">m</span>(<span class="reserved">new</span> <span class="type">X</span> { Name = <span class="string">"abc"</span> });

<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">m</span>(<span class="type">X</span>? x)
{
    <span class="control">if</span> (x <span class="reserved">is</span> { <em>Name.Length: 1</em> })
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"single-char Name"</span>);
    }
}

<span class="reserved">class</span> <span class="type">X</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span>? Name { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</code></pre>
<p>この例でいう <code>{ Name.Length: 1 }</code> の部分は、<code>{ Name: { Length: 1 } }</code> と全く同じ意味になります。</p>
<p>ここで注意点というか、1つ、一瞬迷いそうな点として、
<code>Name.Length</code> と言う書き方でも <code>Name</code> の null チェックを含んでいます。
<code>{ Name: { Length: 1 } }</code> をさらに展開すると、以下のようなコードとほぼ同じ意味になります。</p>
<pre class="source" title="入れ子のプロパティ パターンは null チェックを含む">
<code>    <span class="control">if</span> (x <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span>)
    {
        <span class="reserved">var</span> name = x.Name;
        <span class="control">if</span> (name <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span>)
        {
            <span class="reserved">var</span> length = name.Length;
            <span class="control">if</span> (length == 1)
            {
                <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">"single-char Name"</span>);
            }
        }
    }
</code></pre>
<h3><a id="list">リスト パターン</a></h3>
<h5 class="version version11">Ver. 11</h5>
<p>C# 11で、<code>[]</code> を使ってリスト(配列や <code>List&lt;T&gt;</code> など)に対するパターン マッチングができるようになりました。
例えば以下のような <code>switch</code> を書けます。</p>
<pre class="source" title="リストパターンの例">
<code><span class="reserved">var</span> <span class="variable">array</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span> };

<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">array</span> <span class="control">switch</span>
{
    [] <span class="operator">=&gt;</span> <span class="string">&quot;空の配列&quot;</span>,
    [<span class="number">1</span>] <span class="operator">=&gt;</span> <span class="string">&quot;長さ1で、1要素目が1&quot;</span>,
    [<span class="reserved">_</span>] <span class="operator">=&gt;</span> <span class="string">&quot;長さ1の配列&quot;</span>,
    [<span class="number">1</span>, <span class="number">2</span>] <span class="operator">=&gt;</span> <span class="string">&quot;長さ2で、1要素目が1、2要素目が2&quot;</span>,
    [<span class="number">1</span>, <span class="reserved">_</span>] <span class="operator">=&gt;</span> <span class="string">&quot;長さ2で、1要素目が1&quot;</span>,
});
</code></pre>
<p>このような <code>[]</code> を使ったパターンを<strong id="key-list-pattern" class="keyword">リスト パターン</strong>(list pattern)と言います。</p>
<h4><a id="square-bracket">注意: 角カッコ</a></h4>
<p>C# で新文法を追加する際には、既存の文法と比べて違和感がないような選択をすることが多いです。</p>
<p>そういう意味ではリスト パターンの <code>[]</code> は珍しくちょっと見慣れない感じの選択でした。
これまで <code>[]</code> を使う文法というと、配列作成の <code>new T[N]</code> か、インデクサーの <code>x[i]</code> な分けですが、
これらはの場合 <code>[]</code> の内側には「個数」や「何番目か」の数値が入ります。
リスト パターンの <code>[]</code> の中に入るのは「要素に対するパターン」で、ちょっと方針が異なります。</p>
<p>初期案では、配列初期化子 <code>new[] { a, b, c }</code> からの類推ができるよう、リスト パターンには <code>{}</code> を使おうかという話もありました。
ただ、<code>is {}</code> だと<a href="?p=2#property">プロパティ パターン</a>との弁別が難しかったようです。</p>
<p>これに対して、(C# 11 では入らなかったんですが、将来) 「コレクション リテラル」みたいな文法で <code>[]</code> を使う事を考えたりもしているようです。</p>
<pre class="source" title="[] でコレクション初期化">
<code><span class="comment">// (C# 11 時点で提案段階)</span>
<span class="reserved">using</span> System.Collections.Immutable;

<span class="reserved">int</span>[] <span class="variable">array</span> = [ 1, 2 ];
<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">span</span> = [ 1, 2 ];
<span class="type">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">ros</span> = [ 1, 2 ];
<span class="type">List</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">list</span> = [ 1, 2 ];
<span class="type">ImmutableArray</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">immutable</span> = [1, 2];
</code></pre>
<p>これが入れば、初期化・生成側と、パターン マッチ・分解側の間の違和感が緩和されるかと思います。</p>
<h4><a id="slice-pattern">.. (スライス パターン)</a></h4>
<p>パターンに対して <code>[a, b]</code> と書く場合、2要素ピッタリのリスト出ないとマッチしません。</p>
<pre class="source" title="個数がピッタリでないとマッチしない">
<code><span class="reserved">var</span> <span class="variable">array</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span> };

<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">array</span> <span class="reserved">is</span> [<span class="number">1</span>, <span class="number">2</span>]); <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">array</span> <span class="reserved">is</span> [<span class="number">1</span>]);    <span class="comment">// false。部分一致ではダメ。</span>
</code></pre>
<p>部分一致させたい場合、余る部分に <code>..</code> を置けばマッチさせることができます。
例えば、以下のようなコードで、「1, 2 で始まって、長さ2以上のリスト」にマッチできます。</p>
<pre class="source" title="「1, 2 で始まって、長さ2以上のリスト」にマッチ">
<code><span class="reserved">var</span> <span class="variable">array</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span> };

<span class="method">match</span>(<span class="reserved">new</span>[] { <span class="number">1</span> }); <span class="comment">// false</span>
<span class="method">match</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span> }); <span class="comment">// true (ちょうどでもOK)</span>
<span class="method">match</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> }); <span class="comment">// true (過剰でもOK)</span>
<span class="method">match</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span> }); <span class="comment">// true</span>

<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">match</span>(<span class="reserved">int</span>[] <span class="variable local">array</span>)
    <span class="operator">=&gt;</span> <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable local">array</span> <span class="reserved">is</span> [<span class="number">1</span>, <span class="number">2</span>, ..]);
</code></pre>
<p>このような <code>..</code> を<strong id="key-slice-pattern" class="keyword">スライス パターン</strong>(slice pattern)と言います。</p>
<p>ちなみに、スライス パターンはリスト パターンの <code>[]</code> の内側にだけ書けます。
例えば <code>array is ..</code> みたいな書き方は認められていません。</p>
<p><code>..</code> は先頭や中間にも書けます。</p>
<pre class="source" title="先頭、中間の ..">
<code><span class="reserved">var</span> <span class="variable">a1</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span> };
<span class="reserved">var</span> <span class="variable">a2</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span> };
<span class="reserved">var</span> <span class="variable">a3</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">2</span> };

<span class="comment">// 1で始まって2で終わる(長さは任意)。</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">a1</span> <span class="reserved">is</span> [<span class="number">1</span>, .., <span class="number">2</span>]); <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">a2</span> <span class="reserved">is</span> [<span class="number">1</span>, .., <span class="number">2</span>]); <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">a3</span> <span class="reserved">is</span> [<span class="number">1</span>, .., <span class="number">2</span>]); <span class="comment">// true</span>

<span class="comment">// 末尾が 1, 2で終わる(長さは任意)。</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">a1</span> <span class="reserved">is</span> [.., <span class="number">1</span>, <span class="number">2</span>]); <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">a2</span> <span class="reserved">is</span> [.., <span class="number">1</span>, <span class="number">2</span>]); <span class="comment">// false</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">a3</span> <span class="reserved">is</span> [.., <span class="number">1</span>, <span class="number">2</span>]); <span class="comment">// true</span>
</code></pre>
<p>ちなみに、2か所以上に <code>..</code> を置いてしまうとコンパイル エラーになります。</p>
<pre class="source" title="2か所以上に .. を置くとコンパイル エラー">
<code><span class="reserved">var</span> <span class="variable">array</span> <span class="operator">=</span> <span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span> };

<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable">array</span> <span class="reserved">is</span> [.., <span class="error">..</span>]);
</code></pre>
<h4><a id="sub-pattern">リスト パターンの再帰</a></h4>
<p><a href="?list">リスト パターン</a>はカテゴライズするなら<a href="?p=2#recursive">再帰パターン</a>の一種です。
<code>[]</code> の中の各要素には任意のパターンを書くことができます。</p>
<pre class="source" title="リスト パターン中の再帰パターン">
<code><span class="reserved">using</span> System<span class="operator">.</span>Numerics;

<span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">match1</span>(<span class="reserved">int</span>[] <span class="variable local">array</span>)
    <span class="operator">=&gt;</span> <span class="variable local">array</span> <span class="reserved">is</span> [<span class="number">0</span>, <span class="reserved">_</span>, <span class="operator">&gt;</span> <span class="number">0</span>, <span class="operator">&lt;</span> <span class="number">0</span>, <span class="reserved">var</span> x, ..] <span class="operator">&amp;&amp;</span> (<span class="variable">x</span> <span class="operator">%</span> <span class="number">2</span>) <span class="operator">==</span> <span class="number">1</span>;
<span class="comment">// 前から順に、</span>
<span class="comment">// 0 だけにマッチ(定数パターン)</span>
<span class="comment">// 任意 (破棄パターン)</span>
<span class="comment">// 0 より大きい(関係演算パターン)</span>
<span class="comment">// 0 より小さい(関係演算パターン)</span>
<span class="comment">// 任意 (var パターン)</span>
<span class="comment">// 残り読み飛ばし (スライス パターン)</span>

<span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">match2</span>((<span class="reserved">int</span> x, <span class="reserved">int</span> y)[] <span class="variable local">points</span>)
    <span class="operator">=&gt;</span> <span class="variable local">points</span> <span class="reserved">is</span> [(<span class="number">1</span>, <span class="number">2</span>), (<span class="field">x</span>: <span class="number">3</span>, <span class="field">y</span>: <span class="number">4</span>), { <span class="field">x</span>: <span class="number">5</span>, <span class="field">y</span>: <span class="number">6</span> }];
<span class="comment">// 前から順に</span>
<span class="comment">// 位置パターン</span>
<span class="comment">// 位置パターン(名前付き)</span>
<span class="comment">// プロパティ パターン</span>
</code></pre>
<p>また、スライス パターンも、<code>..</code> の後ろに続けてパターンを書くことができます。</p>
<pre class="source" title=".. に再帰でパターンを付ける">
<code><span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">match1</span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">span</span>) <span class="operator">=&gt;</span> <span class="variable local">span</span> <span class="control">switch</span>
{
    [<span class="operator">&gt;</span> <span class="number">0</span>, .. <span class="reserved">var</span> rest] <span class="operator">=&gt;</span> <span class="method">match1</span>(<span class="variable">rest</span>), <span class="comment">// 先頭が正の数で、残りを再帰的に判定</span>
    [] <span class="operator">=&gt;</span> <span class="reserved">true</span>,
    <span class="reserved">_</span> <span class="operator">=&gt;</span> <span class="reserved">false</span>,
};

<span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">match2</span>(<span class="reserved">int</span>[] <span class="variable local">array</span>)
    <span class="operator">=&gt;</span> <span class="variable local">array</span> <span class="reserved">is</span> [<span class="number">1</span>, ..[<span class="number">2</span>, <span class="number">3</span>]]; <span class="comment">// あまり意味はなくて、[1, 2, 3] と同じ結果にしかならない</span>
</code></pre>
<p>よく使いそうな例でいうと、「先頭数バイトが特定のパターンの時に読み飛ばし」みたいなことができます。</p>
<pre class="source" title="UTF-8 の BOM 読み飛ばし">
<code><span class="reserved">var</span> <span class="variable">utf8</span> <span class="operator">=</span> <span class="type">File</span><span class="operator">.</span><span class="method">ReadAllBytes</span>(<span class="string">&quot;a.txt&quot;</span>);

<span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">b</span> <span class="control">in</span> <span class="method">removeBom</span>(<span class="variable">utf8</span>))
{
    <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">b</span>:<span class="string">X</span>}<span class="string">&quot;</span>);
}

<span class="reserved">static</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="method">removeBom</span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable local">utf8</span>)
    <span class="operator">=&gt;</span> <span class="variable local">utf8</span> <span class="reserved">is</span> [<span class="number">0xEF</span>, <span class="number">0xBB</span>, <span class="number">0xBF</span>, .. <span class="reserved">var</span> noBom] <span class="operator">?</span> <span class="variable">noBom</span> <span class="operator">:</span> <span class="variable local">utf8</span>;
</code></pre>
<h4><a id="list-pattern-lowering">リスト パターンの展開結果</a></h4>
<p>リスト パターンやスライス パターンは、
割かしべたに長さ (<code>Length</code> もしくは <code>Count</code> プロパティ)、インデックス (<code>a[i]</code>) やスライス (<code>a[..]</code>) に展開されます。
例えば以下のようなリスト パターンを書いた場合、</p>
<pre class="source" title="リスト パターンを使った回文判定の例">
<code><span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="method">palindrome</span>(<span class="reserved">new</span> <span class="reserved">int</span>[<span class="number">0</span>]));              <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="method">palindrome</span>(<span class="reserved">new</span>[] { <span class="number">1</span> }));             <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="method">palindrome</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span> }));          <span class="comment">// false</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="method">palindrome</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span> }));       <span class="comment">// false</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="method">palindrome</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">1</span> }));       <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="method">palindrome</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">1</span> })); <span class="comment">// true</span>
<span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="method">palindrome</span>(<span class="reserved">new</span>[] { <span class="number">1</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span> })); <span class="comment">// false</span>

<span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">palindrome</span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">list</span>) <span class="operator">=&gt;</span> <span class="variable local">list</span> <span class="control">switch</span>
{
    [] <span class="reserved">or</span> [<span class="reserved">_</span>] <span class="operator">=&gt;</span> <span class="reserved">true</span>,
    [<span class="reserved">var</span> first, .. <span class="reserved">var</span> rest, <span class="reserved">var</span> last] <span class="operator">=&gt;</span> <span class="variable">first</span> <span class="operator">==</span> <span class="variable">last</span> <span class="operator">&amp;&amp;</span> <span class="method">palindrome</span>(<span class="variable">rest</span>),
};
</code></pre>
<p>以下のようなコードとほぼ同じ意味になります。</p>
<pre class="source" title="palindrome の展開結果">
<code><span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">palindrome</span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">list</span>) <span class="operator">=&gt;</span> <span class="variable local">list</span><span class="operator">.</span><span class="property">Length</span> <span class="control">switch</span>
{
    <span class="number">0</span> <span class="reserved">or</span> <span class="number">1</span> <span class="operator">=&gt;</span> <span class="reserved">true</span>,
    <span class="operator">&gt;=</span> <span class="number">2</span> <span class="operator">=&gt;</span> <span class="variable local">list</span>[<span class="number">0</span>] <span class="operator">==</span> <span class="variable local">list</span>[<span class="operator">^</span><span class="number">1</span>] <span class="operator">&amp;&amp;</span> <span class="method">palindrome</span>(<span class="variable local">list</span>[<span class="number">1</span>..<span class="operator">^</span><span class="number">1</span>]),
};
</code></pre>
<p><code>a[^i]</code> や <code>a[i..j]</code> が使えることが、そのままリスト パターンを使える条件になります。
(詳しい条件に付いては「<a href="https://ufcpp.net/study/csharp/data/dataranges/">インデックス/範囲</a>」を参照。)</p>
<p>また、<code>list is [_, .. var rest, _]</code> みたいなものが <code>list[1..^1]</code> に展開される都合上、
<code>list[i..j]</code> がパフォーマンス的にいまいちなコードになっている場合、
リスト パターンも非効率になります。</p>
<pre class="source" title="スライス パターンは文字通りスライスを作る">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">m1</span>(<span class="reserved">int</span>[] <span class="variable local">array</span>)
{
    <span class="comment">// 配列に対するスライスは新しい配列を作っちゃう(= 遅い)。</span>
    <span class="reserved">var</span> <span class="variable">slice</span> <span class="operator">=</span> <span class="variable local">array</span>[<span class="number">1</span>..<span class="operator">^</span><span class="number">1</span>];

    <span class="comment">// その影響で、以下のコードも新しい配列がいちいち作られて遅い。</span>
    <span class="comment">// (string でも同じようなことが起きる)。</span>
    <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable local">array</span> <span class="reserved">is</span> [<span class="reserved">_</span>, ..<span class="reserved">var</span> rest, <span class="reserved">_</span>]);
}

<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">m2</span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">span</span>)
{
    <span class="comment">// Span の場合はそんな非効率な事は起きないので、</span>
    <span class="reserved">var</span> <span class="variable">slice</span> <span class="operator">=</span> <span class="variable local">span</span>[<span class="number">1</span>..<span class="operator">^</span><span class="number">1</span>];

    <span class="comment">// 以下のコードも遅くはならない。</span>
    <span class="comment">// (string に対しては ReadOnlySpan&lt;char&gt; にすると速い)。</span>
    <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="variable local">span</span> <span class="reserved">is</span> [<span class="reserved">_</span>, .. <span class="reserved">var</span> rest, <span class="reserved">_</span>]);
}
</code></pre>
<h3><a id="usage">再帰パターンの利用例</h3>
<p>「<a href="/study/csharp/datatype/typeswitch/?p=3#usage">型スイッチの用途</a>」と同じ題材で、再帰パターンの利用例も挙げておきます。</p>
<p>使った題材は、数式を扱うようなクラスです。
要するに、例えば、「<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>×</mo><mi>x</mi><mo>+</mo><mn>1</mn></math>」というような式を、以下のようなクラスで表します。</p>
<pre class="source" title="数式を表す Node クラス">
<code><span class="reserved">public</span> <span class="reserved">abstract</span> <span class="reserved">class</span> <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">readonly</span> <span class="type">Node</span> X = <span class="reserved">new</span> <span class="type">Var</span>();
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="type">Node</span>(<span class="reserved">int</span> <span class="variable">value</span>) =&gt; <span class="reserved">new</span> <span class="type">Const</span>(<span class="variable">value</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Node</span> <span class="reserved">operator</span> +(<span class="type">Node</span> <span class="variable">left</span>, <span class="type">Node</span> <span class="variable">right</span>) =&gt; <span class="reserved">new</span> <span class="type">Add</span>(<span class="variable">left</span>, <span class="variable">right</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Node</span> <span class="reserved">operator</span> *(<span class="type">Node</span> <span class="variable">left</span>, <span class="type">Node</span> <span class="variable">right</span>) =&gt; <span class="reserved">new</span> <span class="type">Mul</span>(<span class="variable">left</span>, <span class="variable">right</span>);
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Var</span> : <span class="type">Node</span> { <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() =&gt; <span class="string">&quot;x&quot;</span>; }
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Const</span> : <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> Value { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="method">Const</span>(<span class="reserved">int</span> <span class="variable">value</span>) { Value = <span class="variable">value</span>; }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">value</span>) =&gt; <span class="variable">value</span> = Value;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() =&gt; Value.<span class="method">ToString</span>();
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Add</span> : <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="type">Node</span> Left { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">Node</span> Right { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="method">Add</span>(<span class="type">Node</span> <span class="variable">left</span>, <span class="type">Node</span> <span class="variable">right</span>) =&gt; (Left, Right) = (<span class="variable">left</span>, <span class="variable">right</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="type">Node</span> <span class="variable">left</span>, <span class="reserved">out</span> <span class="type">Node</span> <span class="variable">right</span>) =&gt; (<span class="variable">left</span>, <span class="variable">right</span>) = (Left, Right);
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() =&gt; <span class="string">$&quot;(</span>{Left.<span class="method">ToString</span>()}<span class="string"> + </span>{Right.<span class="method">ToString</span>()}<span class="string">)&quot;</span>;
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Mul</span> : <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="type">Node</span> Left { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">Node</span> Right { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="method">Mul</span>(<span class="type">Node</span> <span class="variable">left</span>, <span class="type">Node</span> <span class="variable">right</span>) =&gt; (Left, Right) = (<span class="variable">left</span>, <span class="variable">right</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="type">Node</span> <span class="variable">left</span>, <span class="reserved">out</span> <span class="type">Node</span> <span class="variable">right</span>) =&gt; (<span class="variable">left</span>, <span class="variable">right</span>) = (Left, Right);
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>() =&gt; <span class="string">$&quot;</span>{Left.<span class="method">ToString</span>()}<span class="string"> * </span>{Right.<span class="method">ToString</span>()}<span class="string">&quot;</span>;
}
</code></pre>
<p>こいつに対して「式の簡約化」をやってみます。
要は、
「<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>+</mo><mn>0</mn></math>を<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>に、
<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>×</mo><mn>1</mn></math>を<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>に、
<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>×</mo><mn>0</mn></math>を<math xmlns="http://www.w3.org/1998/Math/MathML"><mn>0</mn></math>に直す」みたいなやつ。</p>
<p>こういう処理は、<code>switch</code>式と位置パターンを使って以下のように書けます。
(コード全体: <a href="https://github.com/ufcpp/UfcppSample/blob/master/Chapters/Data/Patterns/Expressions/Program.cs">Expressions/Program.cs</a>)</p>
<pre class="source" title="switch 式と位置パターンを使って式の簡約化">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Node</span> <span class="method">Simplify</span>(<span class="reserved">this</span> <span class="type">Node</span> <span class="variable">n</span>)
    =&gt; <span class="variable">n</span> <span class="reserved">switch</span>
{
    <span class="type">Add</span> (<span class="reserved">var</span> l, <span class="reserved">var</span> r) =&gt; (<span class="variable">l</span>.<span class="method">Simplify</span>(), <span class="variable">r</span>.<span class="method">Simplify</span>()) <span class="reserved">switch</span>
    {
        <span class="comment">// 0 を足しても変わらない</span>
        (<span class="type">Const</span>(0), <span class="reserved">var</span> r1) =&gt; <span class="variable">r1</span>,
        (<span class="reserved">var</span> l1, <span class="type">Const</span>(0)) =&gt; <span class="variable">l1</span>,
        <span class="comment">// 他</span>
        (<span class="reserved">var</span> l1, <span class="reserved">var</span> r1) =&gt; <span class="reserved">new</span> <span class="type">Add</span>(<span class="variable">l1</span>, <span class="variable">r1</span>)
    },
    <span class="type">Mul</span> (<span class="reserved">var</span> l, <span class="reserved">var</span> r) =&gt; (<span class="variable">l</span>.<span class="method">Simplify</span>(), <span class="variable">r</span>.<span class="method">Simplify</span>()) <span class="reserved">switch</span>
    {
        <span class="comment">// 0 を掛けたら 0</span>
        (<span class="type">Const</span>(0) c, <span class="reserved">_</span>) =&gt; <span class="variable">c</span>,
        (<span class="reserved">_</span>, <span class="type">Const</span>(0) c) =&gt; <span class="variable">c</span>,
        <span class="comment">// 1 を掛けても変わらない</span>
        (<span class="type">Const</span>(1), <span class="reserved">var</span> r1) =&gt; <span class="variable">r1</span>,
        (<span class="reserved">var</span> l1, <span class="type">Const</span>(1)) =&gt; <span class="variable">l1</span>,
        <span class="comment">// 他</span>
        (<span class="reserved">var</span> l1, <span class="reserved">var</span> r1) =&gt; <span class="reserved">new</span> <span class="type">Mul</span>(<span class="variable">l1</span>, <span class="variable">r1</span>)
    },
    <span class="reserved">_</span> =&gt; <span class="variable">n</span>
};
</code></pre>
<p>C# 7.3 までだと、この処理は以下のように書くことになります。</p>
<pre class="source" title="C# 7.3 以前での書き方">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Node</span> <span class="method">ClassicSimplify</span>(<span class="reserved">this</span> <span class="type">Node</span> <span class="variable">n</span>)
{
    <span class="control">if</span> (<span class="variable">n</span> <span class="reserved">is</span> <span class="type">Add</span> <span class="variable">a</span>)
    {
        <span class="reserved">var</span> (<span class="variable">l</span>, <span class="variable">r</span>) = <span class="variable">a</span>;
        <span class="reserved">var</span> <span class="variable">l1</span> = <span class="variable">l</span>.<span class="method">Simplify</span>();
        <span class="reserved">var</span> <span class="variable">r1</span> = <span class="variable">r</span>.<span class="method">Simplify</span>();
 
        { <span class="control">if</span> (<span class="variable">l1</span> <span class="reserved">is</span> <span class="type">Const</span> <span class="variable">c</span> &amp;&amp; <span class="variable">c</span>.Value == 0) <span class="control">return</span> <span class="variable">r1</span>; }
        { <span class="control">if</span> (<span class="variable">r1</span> <span class="reserved">is</span> <span class="type">Const</span> <span class="variable">c</span> &amp;&amp; <span class="variable">c</span>.Value == 0) <span class="control">return</span> <span class="variable">l1</span>; }
        <span class="control">return</span> <span class="reserved">new</span> <span class="type">Add</span>(<span class="variable">l1</span>, <span class="variable">r1</span>);
    }
    <span class="control">if</span> (<span class="variable">n</span> <span class="reserved">is</span> <span class="type">Mul</span> <span class="variable">m</span>)
    {
        <span class="reserved">var</span> (<span class="variable">l</span>, <span class="variable">r</span>) = <span class="variable">m</span>;
        <span class="reserved">var</span> <span class="variable">l1</span> = <span class="variable">l</span>.<span class="method">Simplify</span>();
        <span class="reserved">var</span> <span class="variable">r1</span> = <span class="variable">r</span>.<span class="method">Simplify</span>();
 
        {
            <span class="control">if</span> (<span class="variable">l1</span> <span class="reserved">is</span> <span class="type">Const</span> <span class="variable">c</span>)
            {
                <span class="control">if</span> (<span class="variable">c</span>.Value == 0) <span class="control">return</span> <span class="variable">c</span>;
                <span class="control">if</span> (<span class="variable">c</span>.Value == 1) <span class="control">return</span> <span class="variable">r1</span>;
            }
        }
        {
            <span class="control">if</span> (<span class="variable">r1</span> <span class="reserved">is</span> <span class="type">Const</span> <span class="variable">c</span>)
            {
                <span class="control">if</span> (<span class="variable">c</span>.Value == 0) <span class="control">return</span> <span class="variable">c</span>;
                <span class="control">if</span> (<span class="variable">c</span>.Value == 1) <span class="control">return</span> <span class="variable">l1</span>;
            }
        }
        <span class="control">return</span> <span class="reserved">new</span> <span class="type">Mul</span>(<span class="variable">l1</span>, <span class="variable">r1</span>);
    }
    <span class="control">return</span> <span class="variable">n</span>;
}
</code></pre>
<!-- pageBreak -->
<h2><a id="pattern-combintor">パターンの組み合わせ</h2>
<h5 class="version version9">Ver. 9.0</h5>
<p>C# 9.0 で <code>and</code> や <code>or</code> などのキーワードを使ってパターンの組み合わせ(pattern combinators)ができるようになりました。</p>
<ul>
<li><code>and</code>: 論理積パターン (conjunctive patterns)。両辺に書いたパターンの両方にマッチすることを求める</li>
<li><code>or</code>: 論理和パターン (disjunctive patterns)。両辺に書いたパターンの少なくとも一方にマッチすることを求める</li>
<li><code>not</code>: 否定パターン (negated patterns)。後ろに書いたパターンの否定を取る</li>
<li><code>()</code>: 括弧付きパターン (parenthesized patterns)。<code>and</code>, <code>or</code> などの結合優先度を指定するためにパターンを <code>()</code> でくくる</li>
</ul>
<h3><a id="and-pattern">and パターン</h3>
<p>2つのパターンを <code>and</code> キーワードでつなぐことで、両方のパターンにマッチしたときだけマッチした扱いになります。
(論理積パターン(conjunctive patterns)と言ったりもします。)</p>
<p>例えば、複数のインターフェイスをすべて実装しているかを判定するとかに使えます。</p>
<pre class="source" title="and パターンで複数のインターフェイスを実装しているか判定">
<code><span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    <span class="comment">// 2つのインターフェイスを両方実装している場合にマッチ。</span>
    <span class="comment">// この時、パターン中で宣言した a, b にはちゃんと両方「初期化済み」判定を受ける。</span>
    <span class="type">IA</span> <span class="variable">a</span> <span class="reserved">and</span> <span class="type">IB</span> <span class="variable">b</span> =&gt; <span class="variable">a</span>.A * <span class="variable">b</span>.B,
    <span class="reserved">_</span> =&gt; 0,
};
 
<span class="reserved">interface</span> <span class="type">IA</span> { <span class="reserved">int</span> A { <span class="reserved">get</span>; } }
<span class="reserved">interface</span> <span class="type">IB</span> { <span class="reserved">int</span> B { <span class="reserved">get</span>; } }
</code></pre>
<p>その他、後述する関係演算パターンと組み合わせて、「0～10まで」みたいな数値の範囲を表すことができます。</p>
<pre class="source" title="数値の範囲指定パターン">
<code><span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">byte</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    &gt;= 0 <span class="reserved">and</span> &lt; 10 =&gt; 0,
    &gt;= 10 <span class="reserved">and</span> &lt; 100 =&gt; 1,
    &gt;= 100 =&gt; 2,
};
</code></pre>
<h3><a id="or-pattern">or パターン</h3>
<p>2つのパターンを <code>or</code> キーワードでつなぐことで、少なくともいずれか片方のパターンにマッチしたときにマッチした扱いになります。
(論理和パターン(disjunctive patterns)と言ったりもします。)</p>
<p>単純に複数の値にマッチさせたり、複数の型にマッチさせることができます。</p>
<pre class="source" title="複数の値にマッチ">
<code><span class="reserved">bool</span> <span class="method">IsSmallPrime</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> 2 <span class="reserved">or</span> 3 <span class="reserved">or</span> 5 <span class="reserved">or</span> 7;
 
<span class="reserved">bool</span> <span class="method">IsTrue</span>(<span class="reserved">bool</span>? <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    <span class="reserved">true</span> =&gt; <span class="reserved">true</span>,
    <span class="comment">// _ (true 以外)と差はないものの、あり得る値を網羅していることがチェックできるという点で</span>
    <span class="comment">// true, false, null の3つの値を並べる意味はなくはない。</span>
    <span class="reserved">false</span> <span class="reserved">or</span> <span class="reserved">null</span> =&gt; <span class="reserved">false</span>,
};
</code></pre>
<p>また、複数の型にマッチさせたりもできます。</p>
<pre class="source" title="複数の型にマッチ">
<code><span class="reserved">bool</span> <span class="method">IsByte</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">byte</span> <span class="reserved">or</span> <span class="reserved">sbyte</span>;
</code></pre>
<p><code>and</code> と同様、後述する関係演算パターンとの組み合わせでも使えます。</p>
<pre class="source" title="関係演算と or パターンの組み合わせ">
<code><span class="reserved">int</span> <span class="method">Triangular</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    &lt; -1 <span class="reserved">or</span> &gt; 1 =&gt; 0,
    <span class="reserved">_</span> =&gt; 1 - <span class="type">Math</span>.<span class="method">Abs</span>(<span class="variable">x</span>),
};
</code></pre>
<h4><a id="conditional-keyward-and-or">文脈キーワードの and, or</h4>
<p>C# のキーワード追加では恒例行事ですが、
既存コードをなるべく壊さないように、後付けな <code>and</code>、<code>or</code> などは<a href="/study/csharp/ap_reserved.html#context">文脈キーワード</a>になっています。</p>
<p>例えば、あまり意味のあるコードではないものの以下のようなコードは有効な C# コードになります。</p>
<pre class="source" title="and, or は文脈キーワード">
<code><span class="comment">// 水色の部分は型名の or, and。青色の部分はキーワードの or, and。</span>
<span class="reserved">bool</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="type">or</span> <span class="reserved">or</span> <span class="type">and</span> <span class="reserved">and</span> <span class="type">and</span>;
 
<span class="reserved">class</span> <span class="type">and</span> { }
<span class="reserved">class</span> <span class="type">or</span> { }
</code></pre>
<h3><a id="not-pattern">not パターン</h3>
<p>パターンの前に <code>not</code> キーワードを置くことで、元のパターンの成否を反転させることができます。
(否定パターン(negated patterns)と言ったりもします。)</p>
<p>おそらく一番使い道があるのは <code>not null</code> だと思います。</p>
<pre class="source" title="not null">
<code><span class="reserved">using</span> System;
 
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
 
<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span>? <span class="variable">s</span>)
{
    <span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span>.Length);
    }
}
</code></pre>
<p><code>string</code> 相手だと <code>x != null</code> と大差ないですが、<a href="/blog/2020/12/isnull/">場合によってはパフォーマンスがよくなることもあります</a>。
また、<code>!</code> の視認性があまりよくないので <code>!=</code> よりも <code>is not</code> の方を好む人もいるようです。</p>
<p>あと、いわゆる early return に使えます。
以下のように、特定条件を満たさないときに早々に <code>return</code> ステートメントで関数を抜けてしまうときに <code>not</code> パターンが使えます。</p>
<pre class="source" title="not パターンで early return">
<code><span class="reserved">using</span> System;
 
<span class="reserved">void</span> <span class="method">PositivePattern</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">string</span> <span class="variable">s</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span>.Length);
    }
}

<span class="comment">// ↑のメソッドを early return で書き直したもの。</span>
<span class="reserved">void</span> <span class="method">EarlyReturn</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="comment">// if の中に限り、not + 型パターンで変数宣言可能。</span>
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">string</span> <span class="variable">s</span>) <span class="control">return</span>;
 
    <span class="comment">// この場合、if 中(not string の時) には s が使えず、</span>
    <span class="comment">// その後ろ(string の時)でだけ s が使える。</span>
 
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span>.Length);
}
</code></pre>
<h3><a id="parenthesized-patterns">括弧付きパターン</h3>
<p><code>not</code>, <code>and</code>, <code>or</code> の結合順位は <code>!</code>, <code>&amp;&amp;</code>, <code>||</code> と同じで、<code>not</code> → <code>and</code> → <code>or</code> の順です。</p>
<p>例えば以下のような書き方をすると、<code>and</code> の結合が優先されます。</p>
<pre class="source" title="and が優先">
<code><span class="reserved">bool</span> <span class="method">IsAsciiLetter</span>(<span class="reserved">char</span> <span class="variable">c</span>) =&gt; <span class="variable">c</span> <span class="reserved">is</span> &gt;= <span class="string">&#39;a&#39;</span> <span class="reserved">and</span> &lt;= <span class="string">&#39;z&#39;</span> <span class="reserved">or</span> &gt;= <span class="string">&#39;A&#39;</span> <span class="reserved">and</span> &lt;= <span class="string">&#39;Z&#39;</span>;
</code></pre>
<p><code>&amp;&amp;</code> と <code>||</code> でもよくある話ですが、優先度がわかりにくくて読むときにつらかったりします。
また、<code>or</code> の方を優先したいことも当然あります。</p>
<p>そこで、パターンを <code>()</code> で囲んで結合優先度を明示することができるようになりました。
(括弧付きパターン(parenthesized patterns)と言ったりもします。)
先ほどの <code>IsAsciiLetter</code> の例は以下のようにも書けます。</p>
<pre class="source" title="() を付けて優先度を明示">
<code><span class="comment">// () を付けて優先度を明示。</span>
<span class="reserved">bool</span> <span class="method">IsAsciiLetter</span>(<span class="reserved">char</span> <span class="variable">c</span>) =&gt; <span class="variable">c</span> <span class="reserved">is</span> (&gt;= <span class="string">&#39;a&#39;</span> <span class="reserved">and</span> &lt;= <span class="string">&#39;z&#39;</span>) <span class="reserved">or</span> (&gt;= <span class="string">&#39;A&#39;</span> <span class="reserved">and</span> &lt;= <span class="string">&#39;Z&#39;</span>);
</code></pre>
<p>前述の「複数のインターフェイスをすべて実装しているかを判定」と「<code>not</code> パターンを使った early return」の組み合わせもできます。</p>
<pre class="source" title="not (and)">
<code><span class="reserved">using</span> System;
 
<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">not</span> (<span class="type">IA</span> <span class="variable">a</span> <span class="reserved">and</span> <span class="type">IB</span> <span class="variable">b</span>)) <span class="control">return</span>;
 
    <span class="comment">// a, b ともに使える。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">a</span>.A * <span class="variable">b</span>.B);
}
 
<span class="reserved">interface</span> <span class="type">IA</span> { <span class="reserved">int</span> A { <span class="reserved">get</span>; } }
<span class="reserved">interface</span> <span class="type">IB</span> { <span class="reserved">int</span> B { <span class="reserved">get</span>; } }
</code></pre>
<h2><a id="relational-patterns">関係演算パターン</h2>
<h5 class="version version9">Ver. 9.0</h5>
<p><code>&lt;</code>, <code>&lt;=</code>, <code>&gt;</code>, <code>&gt;=</code> の4つの関係演算子を使って数値の大小をパターンの中に書けます。
(関係演算パターン(relational patterns)と言ったりします。)</p>
<pre class="source" title="">
<code><span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">byte</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    &lt; 10 =&gt; 1, <span class="comment">// 0～9</span>
    &gt;= 10 <span class="reserved">and</span> &lt;= 99 =&gt; 2, <span class="comment">// 10～99</span>
    &gt; 99 =&gt; 3, <span class="comment">// 100～255</span>
};
</code></pre>
<p>初期の案では、C# 8.0 で<a href="/study/csharp/cheatsheet/ap_ver8/#range">範囲アクセス用に <code>..</code> 演算子を導入</a>したのに対して、「範囲パターン」も用意したいというものでした。
ただ、<code>x..y</code> みたいな範囲パターンだと、両端(この場合 <code>x</code>と<code>y</code>)を含むかどうかがわかりにくくて困るだろうということで不採用になっていました。
( <code>..</code> 演算子は<a href="/study/csharp/data/dataranges/#index-usage">インデックス用途</a>に絞ったことで、先頭<code>x</code>は含む、末尾<code>y</code>は含まないというルールにできましたが、「範囲パターン」の場合はあまり用途を絞れないので同じルールだと使いにくいという問題があります。)</p>
<p>他のプログラミング言語だと、範囲を表すために <code>&lt;..</code>, <code>=..</code>, <code>..&lt;</code>, <code>..=</code> など <code>..</code> の前後に <code>&lt;</code> や <code>=</code> を付けることで両端の含む・含まない問題を解決していたりします。
しかし、C# ではもういっそ、<code>&lt;</code>, <code>&lt;=</code>, <code>&gt;</code>, <code>&gt;=</code> と <code>and</code> パターンの組み合わせで範囲を表そうということになりました。</p>
<!-- pageBreak -->
<h2><a id="compile-time-validation">コンパイル時検査</h2>
<p>パターン マッチングでは、値の網羅性を満たしているかどうかと、書いたパターンが重複していないかをコンパイル時に検査してくれる仕組みがあります。</p>
<h3><a id="exhaustive">網羅性チェック</h3>
<p>いくつかの型は決まった値しかとりません。例えば <code>bool</code> なら <code>true</code> か <code>false</code> の2値ですし、
<code>bool?</code> でも <code>true</code>, <code>false</code>, <code>null</code> の3値だけです。
<code>byte</code> も高々256個の値しか持ちません。
<a href="/study/csharp/datatype/typeswitch/?p=5#exhaustive">型スイッチのページにも書いていますが</a>、パターン マッチングではこれらの値をすべて網羅しているかどうか(exhaustiveness: 網羅性)の検査をしてくれます。</p>
<pre class="source" title="bool, bool? の網羅性検査">
<code><span class="comment">// 無警告</span>
<span class="reserved">int</span> <span class="method">A</span>(<span class="reserved">bool</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    <span class="reserved">true</span> =&gt; 1,
    <span class="reserved">false</span> =&gt; 0,
};
 
<span class="comment">// 警告あり(CS8655: 条件に null が足りていない)</span>
<span class="reserved">int</span> <span class="method">B</span>(<span class="reserved">bool</span>? <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="warning"><span class="control">switch</span></span>
{
    <span class="reserved">true</span> =&gt; 1,
    <span class="reserved">false</span> =&gt; 0,
};
 
<span class="comment">// 無警告</span>
<span class="reserved">int</span> <span class="method">C</span>(<span class="reserved">bool</span>? <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    <span class="reserved">true</span> =&gt; 1,
    <span class="reserved">false</span> <span class="reserved">or</span> <span class="reserved">null</span> =&gt; 0,
};
</code></pre>
<p>また、数値型に対しては、<a href="/study/csharp/datatype/patterns/?p=3#relational-patterns">関係演算パターン</a>を使って「100未満」と「100以上」というように相補的に値を網羅しているかを検査できます。
例えば以下のコードには条件漏れがあって警告を起こします。</p>
<pre class="source" title="実は条件漏れがあるコード">
<code><span class="comment">// 警告を起こす</span>
<span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">byte</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    &lt; 10 =&gt; 1,
    &gt;= 10 <span class="reserved">and</span> &lt; 100 =&gt; 2,
    <span class="comment">// &lt; 100 と &gt; 100 (どちらも 100 は含まない)しかないので、実は 100 が漏れてる</span>
    &gt; 100 =&gt; 3,
};
</code></pre>
<p>値パターンや <code>or</code> パターンとの組み合わせでも網羅性の検査がかかります。</p>
<pre class="source" title="値パターンや or パターンとの組み合わせでの網羅性検査">
<code><span class="comment">// 整数の場合は値パターンとかその or パターン、関係演算パターンの組み合わせでも網羅性検査がかかる</span>
<span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">uint</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    0 <span class="reserved">or</span> 2 <span class="reserved">or</span> 4 <span class="reserved">or</span> 6 <span class="reserved">or</span> 8 =&gt; 0,
    1 <span class="reserved">or</span> 3 <span class="reserved">or</span> 5 <span class="reserved">or</span> 7 <span class="reserved">or</span> 9 =&gt; 1,
    &gt;= 10 =&gt; -1, <span class="comment">// この行がなかったり、条件が &gt; 10 とかだったりすると警告</span>
};
</code></pre>
<p>一般の型に対しても、「null か非 null か」みたいな条件が相補的で、これに対しても網羅性の検査がかかります。</p>
<pre class="source" title="null か非 null かの網羅性">
<code><span class="comment">// null か非 null かで網羅性検査がかかっていて、どれか1行でも欠けていると警告</span>
<span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">int</span>? <span class="variable">x</span>, <span class="reserved">int</span>? <span class="variable">y</span>) =&gt; (<span class="variable">x</span>, <span class="variable">y</span>) <span class="control">switch</span>
{
    (<span class="reserved">null</span>, <span class="reserved">null</span>) =&gt; 0,
    ({ }, <span class="reserved">null</span>) =&gt; -1,
    (<span class="reserved">null</span>, { }) =&gt; 1,
    ({ } x1, { } y1) =&gt; <span class="variable">x1</span>.<span class="method">CompareTo</span>(<span class="variable">y1</span>),
};
</code></pre>
<h3><a id="case-duplicate">条件の重複チェック</h3>
<p><code>switch</code> ステートメント/<code>switch</code> 式中に絶対に到達できない条件があるとき、
ある程度はコンパイル時に検知してコンパイル エラーにしてもらえます。</p>
<p>パターンを使った <code>switch</code> の条件は<a href="/study/csharp/datatype/typeswitch/?p=2#sequential">上から逐次判定</a>なので、要するに、上の方に下にある条件の上位互換な条件があるとコンパイル エラーになります。</p>
<p>一番わかりやすいのは<a href="/study/csharp/datatype/patterns/#discard">破棄パターン</a>で、これは「何にでも一致するパターン」なので、その下に何かを書くとエラーになります。</p>
<pre class="source" title="破棄パターンの下に別条件を書いても絶対に到達できない">
<code><span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>) =&gt; <span class="variable">obj</span> <span class="control">switch</span>
{
    <span class="reserved">_</span> =&gt; 0,
    <span class="error"><span class="reserved">string</span> <span class="reserved">_</span></span> =&gt; 1,
};
</code></pre>
<p>当然ですが、全く同じ条件が2つ以上ある場合にも、1つ目以外には絶対に到達しないのでエラーになります。</p>
<pre class="source" title="同じ条件が並ぶとエラー">
<code><span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>) =&gt; <span class="variable">obj</span> <span class="control">switch</span>
{
    <span class="reserved">string</span> <span class="variable">s</span> =&gt; <span class="variable">s</span>.Length,
    <span class="error"><span class="reserved">string</span> <span class="reserved">_</span></span> =&gt; 1,
};
</code></pre>
<p>ちなみに、<a href="/study/csharp/datatype/typeswitch/?p=2#switch"><code>when</code>句</a>だと重複チェックが漏れることがあります。
一方、同じような条件でも、<a href="/study/csharp/datatype/patterns/?p=2#recursive">再帰パターン</a>を使うとチェックが働きやすいです。</p>
<pre class="source" title="再帰パターンの方が重複チェックが正確">
<code><span class="reserved">int</span> <span class="method">M1</span>(<span class="reserved">object</span> <span class="variable">obj</span>) =&gt; <span class="variable">obj</span> <span class="control">switch</span>
{
    <span class="comment">// when 句を使うと「同じ条件」判定ができなくなる。コンパイルできてしまう。</span>
    <span class="reserved">string</span> <span class="variable">s</span> <span class="control">when</span> <span class="variable">s</span>.Length == 0 =&gt; 0,
    <span class="reserved">string</span> <span class="variable">s</span> <span class="control">when</span> <span class="variable">s</span>.Length == 0 =&gt; 1,
    <span class="reserved">_</span> =&gt; -1,
};
 
<span class="reserved">int</span> <span class="method">M2</span>(<span class="reserved">object</span> <span class="variable">obj</span>) =&gt; <span class="variable">obj</span> <span class="control">switch</span>
{
    <span class="comment">// 同じことを再帰パターンでやるとちゃんと重複チェックが掛かる。2つ目でコンパイル エラーに。</span>
    <span class="reserved">string</span> { Length: 0 } =&gt; 0,
    <span class="error"><span class="reserved">string</span> { Length: 0 }</span> =&gt; 1,
    <span class="reserved">_</span> =&gt; -1,
};
</code></pre>
<p>また、前節の<a href="#exhaustive">網羅性</a>とも関連して、
全ての値を網羅済みのところの後ろに条件を足しても、その行には絶対に来ないのでエラーにできます。
例えば以下のコードはコンパイル エラーになります。</p>
<pre class="source" title="網羅済みのところの後ろに追加の条件を足すとエラー">
<code><span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">a</span>, <span class="reserved">bool</span> <span class="variable">b</span>) =&gt; (<span class="variable">a</span>, <span class="variable">b</span>) <span class="control">switch</span>
{
    (<span class="reserved">false</span>, <span class="reserved">false</span>) =&gt; 0,
    (<span class="reserved">true</span>, <span class="reserved">false</span>) =&gt; 1,
    (<span class="reserved">false</span>, <span class="reserved">true</span>) =&gt; 2,
    (<span class="reserved">true</span>, <span class="reserved">true</span>) =&gt; 3,
    <span class="comment">// bool の場合上記4つ以外は絶対にないことがわかるので、この行でコンパイル エラーになる。</span>
    <span class="error"><span class="reserved">_</span></span> =&gt; 4,
};
</code></pre> ]]></description>
				<pubDate>Mon, 20 Sep 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] コンパイル結果に影響を及ぼす属性</title>
				<link>http://www.ufcpp.net/study/csharp/start/miscreservedattribute/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<p>「<a href="/study/csharp/sp_attribute.html">属性</a>」の説明を「<a href="/study/csharp/#dynamic">動的な処理</a>」に並べているように、
多くの場合(特に属性を自作する場合)、
属性は<a href="/study/csharp/sp_reflection.html#reflection">リフレクション</a>を使って実行時に型情報から読みだして使うものです。
(動的な処理自体、うちのサイト内では結構後半での説明なので、属性自体についての説明も後々になります。)</p>
<p>ところが、いくつかの属性は C# コンパイラー自体が解釈して、
コンパイル結果に影響を及ぼします。</p>
<h2><a id="reserved-attribute">予約属性</a></h2>
<p>この手の、(動的・実行時ではなく) 静的・コンパイル時に影響を及ぼす属性として、以下のようなものがあります。</p>
<ul>
<li><code>AttributeUsage</code> (<code>System</code>名前空間) : 属性の用途を指定します</li>
<li><code>Obsolete</code> (<code>System</code>名前空間) : 時代遅れでもう使ってほしくない(別のクラスやメソッドに移行してほしい)ものに付けて、警告を発します</li>
<li><code>Conditional</code> (<code>System.Diagnostics</code> 名前空間) : 特定の条件下でのみ実行されるメソッドを定義できるようにします</li>
<li>呼び出し元情報(CallerInfo)属性: メソッドの呼び出し元に関する情報を得るために使います</li>
</ul>
<p><a href="#new-syntax">後述するように</a>、裏でこっそりとコンパイル結果に影響を及ぼす属性は他にももっとたくさんあるんですが、
明示的な属性指定でコンパイル結果が変わるものは以上です。
これらの属性の事を <strong id="key-reserved-attribute" class="keyword">予約属性</strong> (reserved attribute)と呼びます。</p>
<p><code>AttributeUsage</code>, <code>Obsolete</code>, <code>Conditional</code> は C# 1.0 の頃からあるもので、当時はこの3つだけが予約属性でした。
その後、C# 5.0 で<a href="https://ufcpp.net/study/csharp/ap_ver5.html#CallerInfo">呼び出し元情報属性</a>の <code>CallerFilePath</code>, <code>CallerLineNumber</code>, <code>CallerMemberName</code> 属性(いずれも <code>System.Runtime.CompilerServices</code> 名前空間)が追加されました。
また、C# 10.0 で、呼び出し元情報属性に <code>CallerArgumentExpression</code> が追加されました。</p>
<h3><a id="AttributeUsage">AttributeUsage</a></h3>
<p><code>AttributeUsage</code> 属性(<code>System</code>名前空間)では、
<a href="/study/csharp/sp_attribute.html#userdefine">属性を自作</a>する際に、属性の使い方(名前通り、attribute usage)を指定します。</p>
<p>以下のように、指定した以外の属性の使い方をするとコンパイル エラーを起こします。</p>
<pre class="source" title="AttributeUsage の利用例">
<code>[<span class="type">AttributeUsage</span>(<span class="type">AttributeTargets</span>.Class)]
<span class="reserved">class</span> <span class="type">ForClass</span> : <span class="type">Attribute</span> { }

[<span class="type">ForClass</span>] <span class="comment">// これは OK。</span>
<span class="reserved">class</span> <span class="type">A</span>
{
    [<span class="error"><span class="type">ForClass</span></span>] <span class="comment">// これは「ターゲットが合わない」というエラーになる。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>() { }
}
</code></pre>
<h3><a id="Obsolete">Obsolete</a></h3>
<p><code>Obsolete</code> 属性(<code>System</code>名前空間)は、もう廃止(obsolete)したいクラスやメソッドに付けて、そのクラスやメソッドの利用者側コードに警告やエラーを出します。
通常、廃止理由や移行先に関する情報を書いておきます。</p>
<pre class="source" title="Obsolete 属性の利用例">
<code><span class="warning"><span class="type">HighPerformance</span>.<span class="method">AlgorithmA</span>()</span>; <span class="comment">// 警告が出る</span>
<span class="error"><span class="type">Cryptograph</span>.<span class="method">AlgorithmA</span>()</span>;     <span class="comment">// エラーになる</span>

<span class="reserved">class</span> <span class="type">HighPerformance</span>
{
    [<span class="type">Obsolete</span>(<span class="string">"遅いので AlgorithmB に移行してほしい"</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">AlgorithmA</span>() { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">AlgorithmB</span>() { }
}

<span class="reserved">class</span> <span class="type">Cryptograph</span>
{
    [<span class="type">Obsolete</span>(<span class="string">"セキュリティ強度が低いので AlgorithmB に移行してほしい"</span>, error: <span class="reserved">true</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">AlgorithmA</span>() { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">AlgorithmB</span>() { }
}
</code></pre>
<h3><a id="Conditional">Conditional</a></h3>
<p><code>Conditional</code> 属性 (<code>System.Diagnostics</code> 名前空間)を付けると、特定の条件下でのみ実行されるメソッド(conditional method: 条件付きメソッド)、特定の条件下でのみ認識される属性(conditional attribute: 条件付き属性)を定義できるようにします。</p>
<p>(<a href="https://ufcpp.net/study/csharp/ap_ver2.html#conditional">条件付き属性</a>は C# 2.0 からの機能です。)</p>
<p>条件付きメソッドは、
<a href="/study/csharp/sp_preprocess.html#conditional"><code>#if</code> ディレクティブなどを使った条件付きコンパイル</a>を使ったコードと一緒で、
<a href="/study/csharp/sp_preprocess.html#symbol"><code>#define</code> ディレクティブ</a>などでシンボル定義があるときだけ実行されるメソッドになります。</p>
<p>一番多い用途は「デバッグ時にのみ実行」で、例えば標準ライブラリ中の <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.debug.assert"><code>Debug.Assert</code> メソッド</a>には <code>Conditional</code> 属性が付いています。</p>
<pre class="source" title="標準ライブラリの Debug.Assert メソッド(宣言部分のみ)">
<code><span class="reserved">using</span> System.Diagnostics;
<span class="reserved">using</span> System.Diagnostics.CodeAnalysis;

<span class="reserved">namespace</span> System.Diagnostics
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Debug</span>
    {
        [<span class="type">Conditional</span>(<span class="string">"DEBUG"</span>)]
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class引数method">Assert</span>([<span class="type">DoesNotReturnIf</span>(<span class="reserved">false</span>)] <span class="reserved">bool</span> condition);
    }
}
</code></pre>
<p>これを呼びだすコードはデバッグビルド時にのみ実行されます。</p>
<pre class="source" title="Debug.Assert の利用例">
<code><span class="reserved">using</span> System.Diagnostics;

<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> x)
{
    <span class="comment">// デバッグ実行時にだけ x &gt; 0 判定が残る。</span>
    <span class="comment">// 「リリースまでにはこの条件に当てはまらない呼び出し元は絶対に残さない」、</span>
    <span class="comment">// 「だったらリリース時にこの条件判定が残るのはパフォーマンス的にもったいない」</span>
    <span class="comment">// みたいなときに使う。</span>
    <span class="type">Debug</span>.<span class="method">Assert</span>(x &gt; 0);
}
</code></pre>
<h3><a id="CallerInfo">呼び出し元情報(caller info)</a></h3>
<h5 class="version version5">Ver. 5</h5>
<h5 class="version version10">Ver. 10</h5>
<p>以下の4つの属性を使って、メソッドの呼び出し元に関する情報を得ることができます
(いずれも <code>System.Runtime.CompilerServices</code> 名前空間)。
通称、CallerInfo (呼び出し元の情報)属性と言います。</p>
<ul>
<li><code>CallerFilePath</code>: 呼び出し元のファイル名</li>
<li><code>CallerLineNumber</code>: 呼び出し元の行番号</li>
<li><code>CallerMemberName</code>: 呼び出し元のメンバー名（メソッド名、プロパティ名、イベント名等々）</li>
<li><code>CallerArgumentExpression</code>: 呼び出し元で、特定の引数に渡した式</li>
</ul>
<p>このうち、前3つは C# 5.0 から、最後の <code>CallerArgumentExpression</code> は C# 10.0 から使える属性です。
(それ以前のコンパイラーは単にこの属性を無視します。)</p>
<p>これらは、以下のように、<a href="/study/csharp/st_function.html#default-parameter">オプション引数</a>になっている引数に属性を付ける形で使います。</p>
<pre class="source" title="CallerInfo 属性の利用例">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(
    <span class="reserved">int</span> x,
    [<span class="type">CallerLineNumber</span>] <span class="reserved">int</span> line = 0,
    [<span class="type">CallerFilePath</span>] <span class="reserved">string</span>? file = <span class="reserved">null</span>,
    [<span class="type">CallerMemberName</span>] <span class="reserved">string</span>? member = <span class="reserved">null</span>,
    [<span class="type">CallerArgumentExpression</span>(<span class="string">"x"</span>)] <span class="reserved">string</span>? arg = <span class="reserved">null</span>)
{
    <span class="type">Console</span>.WriteLine($@"{file} の {line} 行目
{member} から呼ばれていて
{arg} という式を引数に渡している
(実際の値は {x})
");
}
</code></pre>
<p>これを、例えば以下のようなコードから呼び出したとします。</p>
<pre class="source" title="CallerInfo 属性を使ったメソッドを呼び出す例">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="method">M</span>(2 * 3 * 5);
    }
}
</code></pre>
<p>すると、省略したオプション引数の部分に、行番号、ファイルのフルパス、呼び出し元のメンバー名(この場合 <code>Main</code> メソッド)、引数に渡した式などの整数/文字列が挿入されます。
この例の場合、(ファイル名は環境によって変わりますが)以下のような出力が得られます。</p>
<pre class="console" title="CallerInfo 属性を使ったメソッドを呼び出す例">
<code>C:\Users\ufcpp\source\repos\ConsoleApp1\ConsoleApp1\Program.cs の 7 行目
Main から呼ばれていて
2 * 3 * 5 という式を引数に渡している
(実際の値は 30)
</code></pre>
<p>主な用途はデバッグ、ログ用です。</p>
<p>他に面白い使い方としては、「null 判定で、何の変数が null だったかを知らせるために使う」と言うようなこともできます。
.NET 6 (C# 10.0) で導入された <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.argumentnullexception.throwifnull"><code>ThrowIfNull</code> メソッド</a>がまさにこの機能を使っています。
この <code>ThrowIfNull</code> は以下のような宣言になっています。</p>
<pre class="source" title="ThrowIfNull (宣言部分のみ)">
<code><span class="reserved">using</span> System.Diagnostics.CodeAnalysis;
<span class="reserved">using</span> System.Runtime.CompilerServices;

<span class="reserved">namespace</span> System
{
    <span class="reserved">public</span> <span class="reserved">class</span> <span class="type">ArgumentNullException</span>
    {
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> ThrowIfNull(
            [<span class="type">NotNull</span>] <span class="reserved">object</span>? argument,
            <em>[<span class="type">CallerArgumentExpression</span>(<span class="string">"argument"</span>)]</em> <span class="reserved">string</span>? paramName = <span class="reserved">null</span>);
    }
}
</code></pre>
<p>このメソッドは以下のような使い方をします。</p>
<pre class="source" title="ThrowIfNull を使ったメソッドの利用例">
<code>M(<span class="reserved">null</span>);

<span class="reserved">void</span> M(<span class="reserved">string</span>? myArgument)
{
    <span class="type">ArgumentNullException</span>.<em>ThrowIfNull(myArgument)</em>;
}
</code></pre>
<p>この場合、「null だったら例外」なメソッドにわざと null を渡しているので例外が発生します。
投げられる例外にはちゃんと「何が null だったか」の情報が渡っていて、
以下のようなメッセージが表示されるはずです。</p>
<pre class="console" title="ThrowIfNull を使ったメソッドの利用例">
<code>Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter <em>'myArgument'</em>)
</code></pre>
<p>ちなみに、これらの数値/文字列はコンパイル時<a href="/study/csharp/sp_const.html#constant">定数</a>になります。
直接数値/文字列を書く場合と比べて追加のコストは掛かりません。</p>
<p>また、これらの属性は拡張メソッドとかでもちゃんと動きます。</p>
<pre class="source" title="拡張メソッドで CallerArgumentExpression 属性を使う例">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

(<span class="reserved">from</span> x <span class="reserved">in</span> <span class="reserved">new</span>[] { 1, 2, 3 } <span class="reserved">select</span> x * x).Sum().M();

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Extensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">this</span> <span class="reserved">int</span> x, [<span class="type">CallerArgumentExpression</span>(<span class="string">"x"</span>)] <span class="reserved">string</span>? ex = <span class="reserved">null</span>)
    {
        <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{ex}<span class="string"> = </span>{x}<span class="string">"</span>);
    }
}
</code></pre>
<pre class="console" title="拡張メソッドで CallerArgumentExpression 属性を使う例">
<code>(from x in new[] { 1, 2, 3 } select x * x).Sum() = 14
</code></pre>
<h2><a id="new-syntax">属性を使った新機能</a></h2>
<p>C# の新機能のうち結構な割合のものが、</p>
<ul>
<li>既存の構文で書けるコードに属性を付けたものが生成される</li>
<li>その属性が付いている場合、コンパイラーが特殊対応する</li>
</ul>
<p>というような実装方法になっています。</p>
<p>比較的新しいものでいうと、例えば C# 8.0 で導入された <a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver8/#nullable-reference-type">null 許容参照型</a>は <code>Nullable</code> 属性、<code>NullableContext</code> 属性を使ったコードに展開されます。</p>
<p>例えば nullable enable な場所で以下のようなコードを書いた場合、</p>
<pre class="source" title="null 許容参照型の例">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> M1(<span class="reserved">string</span><em>?</em> x) { }
    <span class="reserved">public</span> <span class="reserved">void</span> M2(<span class="reserved">string</span><em>?</em> x, <span class="reserved">string</span> y, <span class="reserved">string</span> z) { }
}
</code></pre>
<p>旧来の(nullable disable な場所での)コードでいうところの以下のようなコードが得られます。</p>
<pre class="source" title="null 許容参照型の展開結果の例">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <em>[<span class="type">NullableContext</span>(2)]</em>
    <span class="reserved">public</span> <span class="reserved">void</span> M1(<span class="reserved">string</span> x)
    {
    }

    <em>[<span class="type">NullableContext</span>(1)]</em>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M2(<em>[<span class="type">Nullable</span>(2)]</em> <span class="reserved">string</span> x, <span class="reserved">string</span> y, <span class="reserved">string</span> z)
    {
    }
}
</code></pre>
<p>逆に古くからあるものだと拡張メソッドがそうで、以下の2つのコードが同じ意味になります。</p>
<pre class="source" title="拡張メソッドの例">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<em><span class="reserved">this</span></em> <span class="reserved">string</span> x) { }
}
</code></pre>
<pre class="source" title="拡張メソッドの展開結果の例">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">C</span>
{
    <em>[<span class="type">Extension</span>]</em>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">string</span> x) { }
}
</code></pre>
<p>ただし、対応するバージョン以降
(今あげた例でいうと、null 許容参照型は C# 8.0、拡張メソッドは C# 3.0)では、
これらの属性を手書きで使うことはできません。
「直接使うな、拡張メソッド構文を使え」と言うようなコンパイル エラーになります。</p>
<h2><a id="can-be-internal">internal 属性</h2>
<p>昔は、この手の属性は public である必要がありました。
C# 3.0 の頃はまさにそうで、<code>Extension</code> 属性は public です。</p>
<p>ところが最近は「internal でもいい」と言うことになっています。
例えば以下のような状況を想定しています。
(public であることを義務付けてしまうと最後の「被り」が解消できなくて困る。)</p>
<ul>
<li><code>CallerArgumentExpressionAttribute</code> という名前の属性さえあれば、古いバージョンの .NET ランタイム上でも使える</li>
<li><code>CallerArgumentExpressionAttribute</code> が標準ライブラリ入りするのは .NET 6 (C# 10.0 と同世代)から</li>
<li>.NET 5 (C# 9.0 と同世代)でも C# 10.0 にしてこの属性を使いたいので自前で同じ名前の属性を用意</li>
<li>その .NET 5 なコードを、.NET 6 な別のライブラリやアプリから参照したい</li>
<li>自前定義の属性と標準ライブラリ中の属性が被って困る</li>
</ul>
<h2><a id="compiler-generated">コンパイラー生成属性</h2>
<p>さらに言うと、最近は標準ライブラリ中に定義された属性を参照するのではなく、
コンパイラーが属性自体をコンパイル時生成していることが多いです。</p>
<p>例えば[前述の null 許容参照型]の <code>Nullable</code>, <code>NullableContext</code> 属性はコンパイラー生成です。
標準ライブラリにこれらの属性が定義されているわけではなく、
コンパイル結果に以下のような属性が追加されて、それが使われます。</p>
<pre class="source" title="コンパイラー生成の null 許容参照型関連属性">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;

<span class="reserved">namespace</span> Microsoft.CodeAnalysis
{
    [<span class="type">CompilerGenerated</span>]
    [<span class="type">Embedded</span>]
    <span class="reserved">internal</span> <span class="reserved">sealed</span> <span class="reserved">class</span> <span class="type">EmbeddedAttribute</span> : <span class="type">Attribute</span> { }
}

<span class="reserved">namespace</span> System.Runtime.CompilerServices
{
    [<span class="type">CompilerGenerated</span>]
    [Microsoft.CodeAnalysis.<span class="type">Embedded</span>]
    [<span class="type">AttributeUsage</span>(<span class="type">AttributeTargets</span>.Class | <span class="type">AttributeTargets</span>.Property | <span class="type">AttributeTargets</span>.Field | <span class="type">AttributeTargets</span>.Event | <span class="type">AttributeTargets</span>.Parameter | <span class="type">AttributeTargets</span>.ReturnValue | <span class="type">AttributeTargets</span>.GenericParameter, AllowMultiple = <span class="reserved">false</span>, Inherited = <span class="reserved">false</span>)]
    <span class="reserved">internal</span> <span class="reserved">sealed</span> <span class="reserved">class</span> <span class="type">NullableAttribute</span> : <span class="type">Attribute</span>
    {
        <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">byte</span>[] NullableFlags;
        <span class="reserved">public</span> <span class="type">NullableAttribute</span>(<span class="reserved">byte</span> P_0) =&gt; NullableFlags = <span class="reserved">new</span> <span class="reserved">byte</span>[1] { P_0 };
        <span class="reserved">public</span> <span class="type">NullableAttribute</span>(<span class="reserved">byte</span>[] P_0) =&gt; NullableFlags = P_0;
    }
    [<span class="type">CompilerGenerated</span>]
    [Microsoft.CodeAnalysis.<span class="type">Embedded</span>]
    [<span class="type">AttributeUsage</span>(<span class="type">AttributeTargets</span>.Class | <span class="type">AttributeTargets</span>.Struct | <span class="type">AttributeTargets</span>.Method | <span class="type">AttributeTargets</span>.Interface | <span class="type">AttributeTargets</span>.Delegate, AllowMultiple = <span class="reserved">false</span>, Inherited = <span class="reserved">false</span>)]
    <span class="reserved">internal</span> <span class="reserved">sealed</span> <span class="reserved">class</span> <span class="type">NullableContextAttribute</span> : <span class="type">Attribute</span>
    {
        <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">byte</span> Flag;
        <span class="reserved">public</span> <span class="type">NullableContextAttribute</span>(<span class="reserved">byte</span> P_0) =&gt; Flag = P_0;
    }
}
</code></pre>
<p>他にも例えば、C# 7.3 の <a href="/study/csharp/sp_unsafe.html#unmanaged-constraints"><code>unmanaged</code> 制約</a>も <code>IsUnmanaged</code> 属性がコンパイラー生成されています。</p>
<pre class="source" title="IsUnmanaged 属性">
<code><span class="reserved">namespace</span> System.Runtime.CompilerServices
{
    [<span class="type">CompilerGenerated</span>]
    [Microsoft.CodeAnalysis.<span class="type">Embedded</span>]
    <span class="reserved">internal</span> <span class="reserved">sealed</span> <span class="reserved">class</span> <span class="type">IsUnmanagedAttribute</span> : <span class="type">Attribute</span> { }
}
</code></pre> ]]></description>
				<pubDate>Sun, 12 Sep 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 9.0 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver9/</link>
				<description><![CDATA[ <div class="version version9">Ver. 9.0</div>
<table>
<tr>
<th>リリース時期</th>
<td>2020/11</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>.NET 5.0</li>
</td>
</tr>
<tr>
<th>要約・目玉機能</ht>
<td>
<ul>
<li>レコード型</li>
</ul>
</td>
</tr>
</table>
<h2><a id="record">レコード型</h2>
<p>C# 9.0 で、レコード型(records)という新しい種類の型が追加されました。
record (記録)という名前通り、データの読み書きに使うことを意図した型です。
例えば以下のような書き方で、「<code>Name</code> という文字列と <code>Birthday</code> という日付」を読み書きできます。</p>
<pre class="source" title="record の例">
<code><span class="reserved">using</span> System;
 
<span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">birthday</span>);
</code></pre>
<p>詳しくは「<a href="/study/csharp/datatype/record/">レコード型</a>」で説明します。</p>
<h3><a id="init-only">init-only プロパティ</h3>
<p>以下のように <code>init</code> という新しいアクセサーを使って、「オブジェクト初期化子までは書き換え可能で、それ以降は書き換えできないプロパティ」を作れるようになりました。</p>
<pre class="source" title="オブジェクト初期化子でだけ書き換え可能">
<code><span class="reserved">var</span> <span class="variable">p</span> = <span class="reserved">new</span> <span class="type">Point</span> { X = 1, Y = 2 };
<span class="error"><span class="variable">p</span>.X</span> = 3; <span class="comment">// ダメ。</span>
 
<span class="reserved">class</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; <span class="reserved"><em>init</em></span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; <span class="reserved"><em>init</em></span>; }
}
</code></pre>
<p><code>readonly</code> の制限が厳しすぎるので、問題ない範囲でちょっとだけ制限を緩めたもです。
(歴史的経緯で <code>init</code> という新キーワードが使われていますが、もし C# をフルスクラッチで作り直せるなら <code>readonly</code> が最初から <code>init</code> 相当の仕様になっていたと思います。)</p>
<p>詳しくは「<a href="/study/csharp/oo_property.html#init-only">init-only プロパティ</a>」で説明します。</p>
<h2><a id="top-level-statements">トップ レベル ステートメント</h2>
<p>トップ レベル(top-leve: クラスや名前空間よりも外側、ファイル直下)に<a href="/study/csharp/st_variable.html#statement">ステートメント</a>を直接書けるようになりました。</p>
<p>例えばよくある「Hello World」であれば、単に以下のように書けるようになります。</p>
<pre class="source" title="トップ レベルに直接「Hello World」">
<code><span class="reserved">using</span> System;
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Hello World!&quot;</span>);
</code></pre>
<p>詳しくは「<a href="/study/csharp/misc/miscentrypoint/#top-level-statements">トップ レベル ステートメント</a>」で説明します。</p>
<h2><a id="pattern-v3">パターンの追加</h2>
<p><a href="ap_ver7">C# 7.0</a>から脈々と改善されてきた<a href="/study/csharp/datatype/patterns/">パターン マッチング</a>ですが、
C# 9.0 でもいくつかのパターンが追加されています。</p>
<pre class="source" title="C# 9.0 でのパターン追加">
<code><span class="comment">// not, and, or や、 &lt;, &lt;=, &gt;, &gt;= などのパターンが増えた。</span>
<span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">uint</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    0 <span class="reserved">or</span> 2 <span class="reserved">or</span> 4 <span class="reserved">or</span> 6 <span class="reserved">or</span> 8 =&gt; 0,
    1 <span class="reserved">or</span> 3 <span class="reserved">or</span> 5 <span class="reserved">or</span> 7 <span class="reserved">or</span> 9 =&gt; 1,
    &gt;= 10 =&gt; -1,
};
</code></pre>
<p>3世代かけてようやく当初予定(C# に追加すること自体は最初から決めていた機能)が全て入りました。
当初から予定に入ってたのは、既存のいくつかのプログラミング言語が同様の文法を持っていて、
<a href="/study/csharp/datatype/patterns/?p=4#exhaustive">網羅性</a>や<a href="/study/csharp/datatype/patterns/?p=4#case-duplicate">重複</a>の検査を含めて実装手段が既知で、検討コストが低いからです。
それでも、需要が高いものから少しずつ実装した結果、3世代に分かれました。
3世代目なことを指して「パターン v3」(patterns v3)という俗称があったりもします。</p>
<p>詳しくは「<a href="/study/csharp/datatype/patterns/">パターン マッチング</a>」で説明します。
C# 9.0 で追加されているのは以下の3つです。</p>
<ul>
<li><a href="/study/csharp/datatype/patterns/#simplified-type-pattern">型パターンの簡単化</a></li>
<li><a href="/study/csharp/datatype/patterns/?p=3#pattern-combintor">パターンの組み合わせ</a></li>
<li><a href="/study/csharp/datatype/patterns/?p=3#relational-patterns">関係演算パターン</a></li>
</ul>
<h2><a id="target-typed-inference">ターゲット型推論の強化</h2>
<h3><a id="target-typed-new">ターゲットからの new 型推論</h3>
<p>ターゲット型からの推論が効く場合に、<code>new T()</code> の <code>T</code> の部分を省略できるようになりました。
(target-typed new とか呼ばれたりします。)</p>
<p>特に、<a href="/study/csharp/sp3_inference.html#type-inference"><code>var</code></a> が使えず、
型名が長い特に便利です。</p>
<pre class="source" title="フィールド初期化子で特に便利">
<code><span class="reserved">using</span> System.Collections.Generic;
 
<span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="comment">// フィールドに対しては var が使えない。
    // 代わりに new 型推論を使うと便利なことがある(特に、型名が長い時)。</span>
    <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="type">List</span>&lt;(<span class="reserved">int</span> x, <span class="reserved">int</span> y)&gt;&gt; _cache = <span class="reserved">new</span>();
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/oo_construct.html#target-typed-new">ターゲットからの new 型推論</a>」で説明します。</p>
<h3><a id="target-typed-conditional">条件演算子のターゲット型推論</h3>
<p>条件演算子の第2・第3項がターゲット型からの型推論するようになりました。</p>
<pre class="source" title="">
<code><span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">b</span>)
{
    <span class="comment">// int? を明示するとコンパイルできる(var だとダメ)。</span>
    <span class="reserved">int</span>? <span class="variable">i</span> = <span class="variable">b</span> ? 1 : <span class="reserved">null</span>;
 
    <span class="comment">// Base を明示するとコンパイルできる(var だとダメ)</span>
    <span class="type">Base</span> <span class="variable">c</span> = <span class="variable">b</span> ? <span class="reserved">new</span> <span class="type">A</span>() : <span class="reserved">new</span> <span class="type">B</span>();
}
 
<span class="reserved">class</span> <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">A</span> : <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">Base</span> { }
</code></pre>
<p>詳しくは「<a href="/study/csharp/st_branch.html#terget-typed-conditional">条件演算子のターゲット型推論</a>」で説明します。
「<a href="/study/csharp/start/MiscTypeResolution/">型の決定</a>」も参考にしてください。</p>
<h2><a id="class-covariant-returns">クラスの共変戻り値</h2>
<p>仮想メソッドの戻り値に共変性が認められるようになりました。
(機能名の俗称としては、「クラスの共変戻り値」と言ったりします。)</p>
<p>例えば以下のようなコードを書けるようになります。</p>
<pre class="source" title="仮想メソッド戻り値の共変性">
<code><span class="reserved">class</span> <span class="type">Base</span>
{
    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="type">Base</span> <span class="method">Clone</span>() =&gt; <span class="reserved">new</span> <span class="type">Base</span>();
}
 
<span class="reserved">class</span> <span class="type">Derived</span> : <span class="type">Base</span>
{
    <span class="comment">// これの戻り値が Base じゃなくてもよくなった。</span>
    <span class="comment">// Derived は常に Base に安全に変換可能なので、 Base Clone() の override として Derived Clone() を使える。</span>
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="type">Derived</span> <span class="method">Clone</span>() =&gt; <span class="reserved">new</span> <span class="type">Derived</span>();
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/oo_polymorphism.html#covariance">多態性/戻り値の共変性</a>」で説明します。</p>
<h2><a id="unsafe">unsafe/ネイティブ相互運用向け機能</h2>
<p><a href="/study/csharp/cheatsheet/ap_ver7_2/">C# 7.2</a>の辺りから、
言語の方向性として生産性や安全性を優先する C# でも、
パフォーマンス改善を目的とするような言語機能が結構増えてきました。</p>
<p>また、 クロスプラットフォーム化が進んだことで、ネイティブ相互運用関連の機能も増えています。</p>
<p>この手の機能は一般的な開発者が直接触れることは少ないですが、
.NET ランタイム自体や、大規模に使われているライブラリのパフォーマンス改善につながり、
間接的にすべての C# 開発者が恩恵を受けるものになります。</p>
<h3><a id="skip-locals-init">ローカル変数の0初期化抑止</h3>
<p><code>/unsafe</code> オプション指定時限定ですが、ローカル変数の0初期化を抑止できるようになりました。</p>
<pre class="source" title="SkipLocalsInit 属性で0初期化抑止">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.CompilerServices;
<span class="reserved">using</span> System.Text.Unicode;
 
<span class="method">m</span>(<span class="string">&quot;aあ</span><span style="color:#b776fb;">😀</span><span class="string">&quot;</span>);
 
<span class="comment">// この属性を付けると stackalloc の要素の0初期化がなくなる。</span>
[<span class="type">SkipLocalsInit</span>]
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">string</span> <span class="variable">s</span>)
{
    <span class="comment">// UTF-16 の文字数に大して、UTF-8 のバイト数は最大でも3倍以内。</span>
    <span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">buffer</span> = <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[<span class="variable">s</span>.Length * 3];
    <span class="type">Utf8</span>.<span class="method">FromUtf16</span>(<span class="variable">s</span>, <span class="variable">buffer</span>, <span class="reserved">out</span> <span class="reserved">_</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">bytesWritten</span>);
 
    <span class="comment">// FromUtf16 の仕様上、bytesWritten バイト目までは必ず上書きされる。</span>
    <span class="comment">// 上書きされた部分だけを使う分には0初期化は「余計なお世話」。</span>
    <span class="reserved">var</span> <span class="variable">written</span> = <span class="variable">buffer</span>[..<span class="variable">bytesWritten</span>];
 
    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">b</span> <span class="control">in</span> <span class="variable">written</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">b</span>);
    }
}
</code></pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/sp_unsafe.html#skip-locals-init">ローカル変数の0初期化抑止</a>」で説明します。</p>
<h3><a id="function-pointer">関数ポインター</h3>
<p>C# で関数ポインターを書けるようになりました。</p>
<p>.NET の内部的にはこれまでも関数ポインターがあったんですが、 それを C# から効率的に呼ぶ手段がありませんでした。 これに対して、C# 9 では delegate* という記法で関数ポインターを扱えるようになりました。</p>
<pre class="source" title="関数ポインター構文の例">
<span class="reserved">using</span> System<span class="operator">.</span>Runtime<span class="operator">.</span>InteropServices;

<span class="comment">// 関数ポインターを nint で取得。</span>
<span class="reserved">nint</span> <span class="variable">kernel32</span> <span class="operator">=</span> <span class="type"><span class="static">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">Load</span></span>(<span class="string">&quot;kernel32.dll&quot;</span>);
<span class="reserved">nint</span> <span class="variable">p</span> <span class="operator">=</span> <span class="type"><span class="static">NativeLibrary</span></span><span class="operator">.</span><span class="static"><span class="method">GetExport</span></span>(<span class="variable">kernel32</span>, <span class="string">&quot;Beep&quot;</span>);

<span class="reserved">unsafe</span>
{
    <span class="comment">// 「関数ポインター型」にキャストして使う。</span>
    <span class="comment">// 構文的には delegate* から初めて、 &lt;&gt; の中に引数を戻り値の型を並べる。</span>
    <span class="comment">// (戻り値の型が最後。Func&lt;&gt; 風。)</span>
    <span class="reserved">var</span> <span class="variable">fp</span> <span class="operator">=</span> (<span class="reserved">delegate</span><span class="operator">*</span>&lt;<span class="reserved">uint</span>, <span class="reserved">uint</span>, <span class="reserved">int</span>&gt;)<span class="variable">p</span>;
    <span class="variable">fp</span>(<span class="number">440</span>, <span class="number">1000</span>);
}
</pre>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/interop/functionpointer/">関数ポインター</a>」で説明します。</p>
<h2><a id="nint">native int</h2>
<p><code>nint</code> と <code>nuint</code> というキーワードで、「CPU 依存の一番高速に扱える整数」が使えるようになりました。
<code>nint</code> が符号付、<code>nuint</code> が符号なしです。</p>
<pre class="source" title="CPU 依存幅整数">
<code><span class="reserved">nint</span> <span class="variable">x</span> = 0x1_0000;
<span class="variable">x</span> = <span class="variable">x</span> * <span class="variable">x</span>;

<span class="comment">// 32ビット CPU だと 0、64ビット CPU だと 100000000 になるはず。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="variable">x</span>:<span class="string">X</span>}<span class="string">&quot;</span>);

<span class="reserved">unsafe</span>
{
    <span class="comment">// 32ビット CPU だと 4、64ビット CPU だと 8 になるはず。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="reserved">sizeof</span>(<span class="reserved">nint</span>));
}
</code></pre>
<p>ちなみに、内部的には <code>IntPtr</code>、<code>UIntPtr</code> (いずれも <code>System</code> 名前空間)にコンパイルされています。
そのため、以下のようなコードはコンパイル エラーになります(引数の型が同じ同名のメソッドが2つあるため)。</p>
<pre class="source" title="IntPtr と nint でのオーバーロードはできない">
<code><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">void</span> <span class="method">M</span>(<span class="type">IntPtr</span> <span class="variable">x</span>) { }
    <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">nint</span> <span class="variable">x</span>) { }
}
</code></pre>
<p>ただ、単純に 「<code>IntPtr</code>、<code>UIntPtr</code> に別名が付いた」というわけではなく、<code>+</code> などの演算子の挙動が違います。
(※ C# 10 までの話。 <a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver11/#numeric-intptr">C# 11</a> 以降は「<code>nint</code>、<code>nuint</code> は <code>IntPtr</code>、<code>UIntPtr</code> の別名 」という扱いになりました。)</p>
<p><code>IntPtr</code> の場合は <code>operator +(IntPtr pointer, int offset)</code> しか持っていませんが、
<code>nint</code> の場合は普通に整数としての四則演算が全て行えます。 
ちなみに、コンパイラーが <code>IntPtr</code> と <code>nint</code> を区別するため、<code>nint</code> だった場合は <code>NativeInteger</code> 属性(<code>System.Runtime.CompilerServices</code> 名前空間)が付きます。</p>
<p>今更こんな機能が入った背景には、パフォーマンス改善やネイティブ相互運用の強化があります。
例えば、以下のような場面で <code>nint</code> を使っています。</p>
<ul>
<li><a href="https://github.com/dotnet/runtime/blob/7984b32774916c98ab7c85c244c9e40581e4cdf5/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs#L11-L17">ネイティブ コード側が CPU 依存幅の整数になっている場合の相互運用</a></li>
<li><a href="https://github.com/dotnet/runtime/blob/4017327955f1d8ddc43980eb1848c52fbb131dfc/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs#L30">配列のインデックス アクセスは <code>nint</code> を使った方が速い</a> (C++ でいう <code>size_t</code> な処理)</li>
</ul>
<h2><a id="other">その他</h2>
<h3><a id="nrt">null 許容参照型の改善</h3>
<p>C# 8.0 で入った <a href="/study/csharp/resource/nullablereferencetype/">null 許容参照型</a>に対してちょっと改善が入っています。
主に以下の2点です。</p>
<ul>
<li><a href="/study/csharp/resource/nullablereferencetype/?p=3#unconstrained-generics">制約なしジェネリック型引数に <code>?</code> を付けれるようになった</a></li>
<li><a href="/study/csharp/resource/nullablereferencetype/?p=4#annotation-attributes">アノテーション属性</a>に <code>MemberNotNull</code> と <code>MemberNotNullWhen</code> が増えた</li>
</ul>
<h3><a id="lambda-discard">ラムダ式の引数を破棄</h3>
<p>ラムダ式の引数で、<code>_</code> を使った値の破棄ができるようになりました。</p>
<pre class="source" title="ラムダ式の引数で _ を破棄扱い">
<code><span class="reserved">static</span> <span class="reserved">void</span> Subscribe(<span class="type">INotifyPropertyChanged</span> source)
{
    <span class="comment">// _ を破棄扱いして、2個以上並べられる</span>
    source.PropertyChanged += (<span class="reserved">_</span>, <span class="reserved">_</span>) =&gt; { };
}
</code></pre>
<p>詳細は「<a href="/study/csharp/datatype/declarationexpressions/#lambda-discard">値の破棄 - ラムダ式の引数</a>」で説明します。</p>
<h3><a id="static-anonymous-function">静的匿名関数</h3>
<p>匿名関数に対しても <code>static</code> 修飾子を付けれるようになりました。
「外部の変数を捕獲しない」という意味になります。</p>
<pre class="source" title="静的匿名関数">
<code><span class="reserved">using</span> System;
 
<span class="reserved">int</span> <span class="variable">a</span> = 0;
 
<span class="comment">// 以下の行は自身の引数しか使っていないので static にしても怒られない。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">ok</span> = <span class="reserved"><em>static</em></span> <span class="variable">x</span> =&gt; <span class="variable">x</span> * <span class="variable">x</span>;
 
<span class="comment">// 以下の行は外側のローカル変数 a を使ってしまったのでコンパイル エラー。</span>
<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">ng</span> = <span class="reserved"><em>static</em></span> <span class="variable">x</span> =&gt; <span class="variable"><span class="error">a</span></span> * <span class="variable">x</span>;
</code></pre>
<p>詳しくは「<a href="/study/csharp/functional/fun_localfunctions/#static-local-function">静的匿名関数</a>」で説明します。</p>
<h3><a id="local-function-attribute">ローカル関数への属性適用</h3>
<p><a href="/study/csharp/functional/fun_localfunctions/#local-function">ローカル関数</a>に属性を付けられるようになりました。</p>
<pre class="source" title="ローカル関数に属性を付ける">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Diagnostics.CodeAnalysis;
 
<span class="method">m</span>(<span class="string">&quot;&quot;</span>, <span class="string">&quot;&quot;</span>);
 
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">string</span>? <span class="variable">a</span>, <span class="reserved">string</span>? <span class="variable">b</span>)
{
    <span class="comment">// C# 9.0 からローカル関数に属性を付けれる。</span>
    <span class="comment">// C# 8.0 の null 許容参照型がらみで特に有用。</span>
    [<span class="reserved">return</span>: <span class="type">NotNullIfNotNull</span>(<span class="string">&quot;s&quot;</span>)]
    <span class="reserved">string</span>? <span class="method">toLower</span>(<span class="reserved">string</span>? <span class="variable">s</span>) =&gt; <span class="variable">s</span>?.<span class="method">ToLower</span>();
 
    <span class="control">if</span> (<span class="variable">a</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span> &amp;&amp; <span class="variable">b</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span>)
    {
        <span class="comment">// a, b の null 許容性が、NotNullIfNotNull 属性のおかげで al, bl に伝搬。</span>
        <span class="reserved">string</span> <span class="variable">al</span> = <span class="method">toLower</span>(<span class="variable">a</span>);
        <span class="reserved">string</span> <span class="variable">bl</span> = <span class="method">toLower</span>(<span class="variable">b</span>);
 
        <span class="comment">// a, b が非 null なので、al, bl は非 null で確定済み。改めてのチェック不要。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">al</span>.<span class="method">GetHashCode</span>());
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">bl</span>.<span class="method">GetHashCode</span>());
    }
}
</code></pre>
<h3><a id="extension-getenumerator">拡張メソッドでの GetEnumerator 実装</h3>
<p><a href="/study/csharp/misc/miscpatternbased/#index">パターン ベース</a>な <a href="/study/csharp/sp_foreach.html#extension-getenumerator"><code>foreach</code></a>、<a href="/study/csharp/async/asyncstream#await-foreach"><code>await foreach</code></a>で、拡張メソッドによる実装ができるようになりました。</p>
<h2><a id="source-generator">ソースコード生成</h2>
<p>正確には C# という言語の機能ではなく、「C# 9.0 と同時期に実装された」というだけですが、
C# 9.0 世代の C# コンパイラーにはソースコード生成(source generator)プラグインの作成機能が追加されました。
詳細は「<a href="https://ufcpp.net/study/csharp/misc/analyzer-generator/">コード解析とコード生成</a>」で説明しています。</p>
<p>これと同時に、ソースコード生成を前提とした文法もいくつか実装されました。</p>
<h3><a id="extended_partial_method">部分メソッドの拡張</h3>
<p><a href="/study/csharp/misc/analyzer-generator/">ソースコード生成</a>では、手書きでは不完全な C# コードを書いて、
それをソースコード生成で埋めてもらうという状況があり得ます。
C# 9.0 ではそのための文法として、<a href="/study/csharp/oo_class.html#partial_method"><code>partial</code> キーワード</a>を再利用することにしました。</p>
<pre class="source" title="ソースコード生成で埋めてもらう前提の不完全なメソッドの例">
<code><span class="comment">// (1) 手書き前提のコード</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>()
    {
        System.<span class="type">Console</span>.<span class="method">WriteLine</span>(
            <span class="string">&quot;PreGeneratedMethod が呼ばれた直後&quot;</span>
            + <span class="method">WantSourceGenerated</span>());
    }
 
    <span class="comment">// C# コードが先にあって、これを元にソースコード生成してほしいメソッド。</span>
    <span class="reserved">private</span> <span class="reserved">partial</span> <span class="reserved">string</span> <span class="method">WantSourceGenerated</span>();
}
 
<span class="comment">// (2) C# からのソースコード生成が前提のコード</span>
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">PartialClass</span>
{
    <span class="reserved">private</span> <span class="reserved">partial</span> <span class="reserved">string</span> <span class="method">WantSourceGenerated</span>() =&gt; <span class="string">&quot;手書きはしづらしくて、ソースコード生成なら楽な文字列&quot;</span>;
}
</code></pre>
<p>C# 2.0 の頃からある部分メソッドとの差は<a href="https://ufcpp.net/study/csharp/oo_conceal.html#level">アクセシビリティ</a>修飾子の有無です。
<code>private</code> などを付けるかどうかで「コード生成が先」か「手書きが先」かの用途が逆になります。</p>
<p>詳しくは「<a href="/study/csharp/oo_class.html#extended_partial_method">部分メソッドの拡張</a>」で説明します。</p>
<h3><a id="module-initializer">モジュール初期化子</h3>
<p>プログラムの実行時、最初に1回だけ呼び出したい処理が必要になることがあります。
「<a href="https://ufcpp.net/study/csharp/oo_static.html#ctor">静的コンストラクター</a>」で説明しているように、この静的コンストラクターという機能を使っても「最初に1回だけ呼ばれる」ということができますが、C# 9.0 ではモジュール初期化子という書き方もできるようになりました。</p>
<p>以下のように、<code>ModuleInitilizer</code> 属性(<code>System.Runtime.CompilerServices</code> 名前空間)を付けた<a href="https://ufcpp.net/study/csharp/oo_static.html#stmethod">静的メソッド</a>を書くと、それが必ず1回呼び出されるようになります。</p>
<pre class="source" title="ModuleInitialize 属性">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.CompilerServices;
 
<span class="reserved">class</span> <span class="type">Sample</span>
{
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init</span>()
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;必ず1回だけ呼ばれる&quot;</span>);
    }
}
</code></pre>
<p>これをモジュール初期化子(module initializer)と呼びます。</p>
<p>ソースコード生成と組み合わせて、これまでなら<a href="https://ufcpp.net/study/csharp/sp_reflection.html">リフレクション</a>に頼らざるを得なかったような処理を、コンパイル時コード生成に置き換えたりできます。
(他にも使い道はありますが、モジュール初期化子導入の最大のモチベーションはこれです。)</p>
<p>詳しくは「<a href="https://ufcpp.net/study/csharp/oop/ModuleInitializer">モジュール初期化子</a>」で説明します。</p>
 ]]></description>
				<pubDate>Sun, 02 May 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>レコード型</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/record/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<p>C# 9.0 で、レコード型(records)という新しい種類の型が追加されました。
(また、C# 10.0 では構造体版レコード型(record structs)が追加されました。)</p>
<p>record (記録)という名前通り、データの読み書きに使うことを意図した型です。
例えば以下のような書き方で、「<code>Name</code> という文字列と <code>Birthday</code> という日付」を読み書きできます。</p>
<pre class="source" title="record の例">
<code><span class="reserved">using</span> System;
 
<span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>);
</code></pre>
<h2><a id="data-centric">データが主役のプログラミング</a></h2>
<p>プログラミングをしていると、データが主役・データが中心になる場面がちらほらあります。
「データが主役」(data centric)というのは、例えば以下のように、「<code>Name</code> という文字列と、<code>Birthday</code> という日付を持っている」というような「何の型がどういうデータを記録しているか」という情報が強い意味を持つような場面です。</p>
<pre class="source" title="「Name, Birthday フィールドを持っている」と言うこと自体が強い意味を持つ例">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Person</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> Name;
    <span class="reserved">public</span> <span class="type">DateTime</span> Birthday;
}
</code></pre>
<p><a href="/study/csharp/oo_about.html">オブジェクト指向</a>ではこれと真逆の考え方をしたりします。
「<a href="/study/csharp/oo_conceal.html">実装の隠ぺい</a>」などで書いていますが、
オブジェクト指向では「内部的にどういうデータを持っているか」はあまり重要ではなく、
「外から見てどうふるまうか」の方が主役(behavior centric)になります。
例えば上記の例に当てはめるなら、<code>Birthday</code> (誕生日)はなんだったら <code>int</code> (単なる整数。例えば独自の基準日からの経過日数で表すなど)でデータを記録していてもよくて、「外から見て <code>DateTime</code> 型で <code>Birthday</code> を取れれば中身は何でもいい」みたいに考えます。</p>
<p>ところが、データを保存・復元したり、ネットワーク越しに送受信したり、GUI で表示・編集する場合、結局「どういうデータをどういう形式で持っているか」という内部的な情報がそのまま必要になったりします。
例えば上記の <code>Person</code> 型であれば、以下のような JSON 形式で保存して、これを読み書きしたりすることが結構あると思います。</p>
<pre class="source" title="Person 型を JSON で保存">
<code>{
  "name": "天馬飛雄",
  "birthday": "2003/04/07"
}
</code></pre>
<h3><a id="data-boilerplate">ボイラープレートなコード</a></h3>
<p>上記の例に挙げた <code>Person</code> 型の作りは、話を単純化するために簡素化して書いたものですが、
これを「C# のお作法的に好ましい書き方」で書こうとすると実は結構なコード量を書く必要があります。
例えば以下のようなコードになります。</p>
<pre class="source" title="Person をお作法通りに書く場合">
<code><span class="reserved">class</span> <span class="type">Person</span> : <span class="type">IEquatable</span>&lt;<span class="type">Person</span>&gt;
{
    <span class="reserved">public</span> <span class="reserved">string</span> Name { <span class="reserved">get</span>; <span class="reserved">init</span>; }
    <span class="reserved">public</span> <span class="type">DateTime</span> Birthday { <span class="reserved">get</span>; <span class="reserved">init</span>; }
 
    <span class="reserved">public</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">name</span>, <span class="type">DateTime</span> <span class="variable">birthday</span>)
    {
        Name = name;
        Birthday = birthday;
    }
 
    <span class="reserved">public</span> <span class="reserved">bool</span> <span class="method">Equals</span>(<span class="type">Person</span>? <span class="variable">other</span>)
        =&gt; other <span class="reserved">is</span> { } person &amp;&amp;
            Name == person.Name &amp;&amp;
            Birthday == person.Birthday;
 
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">bool</span> <span class="method">Equals</span>(<span class="reserved">object</span>? <span class="variable">obj</span>)
        =&gt; obj <span class="reserved">is</span> <span class="type">Person</span> <span class="variable">person</span> &amp;&amp;
            Name == person.Name &amp;&amp;
            Birthday == person.Birthday;
 
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">int</span> <span class="method">GetHashCode</span>()
        =&gt; HashCode.Combine(Name, Birthday);
 
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>()
        =&gt; <span class="string">$&quot;Person {{ Name = </span>{Name}<span class="string">, Birthday = </span>{Birthday}<span class="string"> }}&quot;</span>;
}
</code></pre>
<p>このコードで書いているのは以下のようなものです。</p>
<ul>
<li>
immutable (1度作ったデータは書き換え不可能にする)にした方がいい
<ul>
<li>C# (8.0 以前)で immutable なデータ型を作ろうと思うと<a href="/study/csharp/oo_construct.html">コンストラクター</a>が必要になる</li>
<li>そうなると、コンストラクターの引数と、プロパティへの代入で同じ名前を何度も書く必要がある</li>
</ul>
</li>
<li>
<a href="/study/csharp/oo_reference.html#reftype">参照型</a>であっても値的にふるまう(value semantics を持つ)ようにしたい
<ul>
<li>2つのインスタンスが「全て同じプロパティ値を持つなら等しい」という判定にする</li>
<li>等値判定(<code>Equals</code> メソッドや <code>GetHashCode</code> メソッド)を書く必要がある</li>
</ul>
</li>
<li>必須ではないものの、<code>ToString</code> で中身のデータが見れると便利</li>
</ul>
<p>これは、どんな「データ中心の型」でもほぼ同じものを書く必要があり、かなり定型コードです。
あまりにも同じものを繰り返し書かないといけないので「ボイラープレート」(boilerplate: 焼き型製品。タイ焼きとかみたいな同じ形状のものを大量生産するやつ)と呼ばれたりします。</p>
<p>当然、毎度毎度同じようなコードを繰り返し書かないといけないのはしんどいです。
「お作法的に好ましいものを書こうとするとボイラープレートがしんどい」という状態はあまり好ましくなく、
簡潔に書ける専用の文法が求められていました。</p>
<h2><a id="record">レコード型</a></h2>
<p>このボイラープレート問題を解決するために、データ中心の型向けの新しい構文として導入されたのが<strong id="key-record" class="keyword">レコード型</strong>です。
最も短い書き方をすると、例えば以下のようになります。</p>
<pre class="source" title="record の例">
<code><span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>);
</code></pre>
<p>クラスとの差は以下の2点です。</p>
<ul>
<li><code>class</code> キーワードの代わりに <code>record</code> キーワードを使う</li>
<li>
型名の後ろに直接コンストラクター引数を書ける(プライマリ コンストラクター)
<ul>
<li>この場合、コンストラクター引数と同名のプロパティが自動的に作られる</li>
</ul>
</li>
</ul>
<p>ちなみに、「プライマリ コンストラクター」(後述)は使わずに、以下のように書くこともできます。</p>
<pre class="source" title="プライマリ コンストラクターは使わず、単に class を record に変えた書き方の例">
<code><span class="reserved">record</span> <span class="type">Person</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> Name { <span class="reserved">get</span>; <span class="reserved">init</span>; }
    <span class="reserved">public</span> <span class="type">DateTime</span> Birthday { <span class="reserved">get</span>; <span class="reserved">init</span>; }
}
</code></pre>
<p>どちらの書き方でも、<code>record</code> キーワードを使って定義した型に対しては、
以下のようなものが自動生成されます。</p>
<ul>
<li>
<code>Equals</code> や <code>GetHashCode</code> や <code>==</code> などの等値判定メソッド
<ul>
<li><code>IEquatable&lt;T&gt;</code> インターフェイスの実装も含む</li>
</ul>
</li>
<li><code>ToString</code> メソッド</li>
<li>後述する <code>with</code> 式で使うクローン メソッド</li>
<li>後述する派生クラス判別のための <code>EqualityContract</code> プロパティ</li>
</ul>
<p>要するに、前述した「お作用的に好ましい」とされるコードを一通りコンパイラーが用意してくれます。</p>
<h3><a id="record-to-class">レコード型とクラス</a></h3>
<p>ちなみに、コンパイラーが色々と自動生成してくれる以外は通常のクラスと同じというか、
内部的には実際にただのクラスとしてコンパイルされます。
(※ C# 9.0 の <code>record</code> の場合。C# 10.0 で導入された <code>record struct</code> は構造体としてコンパイルされます。)</p>
<p>コンパイラー生成のコードをそのまま書くと以下のような感じになります。
(一部、実際には手書きの C# コードでは書けないメソッド名で生成されていたりしますし、
C# コンパイラーのバージョンによって微妙に異なるコードになったりはしますが、
意味的にはほぼこのままのコードになります。)</p>
<pre class="source" title="レコード型からコンパイラー生成されるクラスの例">
<code><span class="reserved">class</span> <span class="type">Person</span> : IEquatable&lt;Person&gt;
{
    <span class="reserved">protected</span> <span class="reserved">virtual</span> Type EqualityContract =&gt; <span class="reserved">typeof</span>(<span class="type">Person</span>);
 
    <span class="reserved">public</span> <span class="reserved">string</span> Name { <span class="reserved">get</span>; <span class="reserved">init</span>; }
    <span class="reserved">public</span> <span class="type">DateTime</span> Birthday { <span class="reserved">get</span>; <span class="reserved">init</span>; }

    <span class="reserved">public</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>)
    {
        <span class="reserved">this</span>.Name = Name;
        <span class="reserved">this</span>.Birthday = Birthday;
    }
    
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">string</span> <span class="variable">Name</span>, <span class="reserved">out</span> <span class="type">DateTime</span> <span class="variable">Birthday</span>)
    {
        Name = <span class="reserved">this</span>.Name;
        Birthday = <span class="reserved">this</span>.Birthday;
    }

    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> <span class="method">ToString</span>()
    {
        StringBuilder <span class="variable">stringBuilder</span> = <span class="reserved">new</span> StringBuilder();
        stringBuilder.Append(<span class="string">&quot;Person&quot;</span>);
        stringBuilder.Append(<span class="string">&quot; { &quot;</span>);
        <span class="control">if</span> (PrintMembers(stringBuilder))
        {
            stringBuilder.Append(<span class="string">&quot; &quot;</span>);
        }
        stringBuilder.Append(<span class="string">&quot;}&quot;</span>);
        <span class="control">return</span> stringBuilder.ToString();
    }
 
    <span class="reserved">protected</span> <span class="reserved">virtual</span> <span class="reserved">bool</span> <span class="method">PrintMembers</span>(StringBuilder <span class="variable">builder</span>)
    {
        builder.Append(<span class="string">&quot;Name&quot;</span>);
        builder.Append(<span class="string">&quot; = &quot;</span>);
        builder.Append((<span class="reserved">object</span>)Name);
        builder.Append(<span class="string">&quot;, &quot;</span>);
        builder.Append(<span class="string">&quot;Birthday&quot;</span>);
        builder.Append(<span class="string">&quot; = &quot;</span>);
        builder.Append(Birthday.ToString());
        <span class="control">return</span> <span class="reserved">true</span>;
    }
 
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="reserved">operator</span> !=(<span class="type">Person</span> <span class="variable">r1</span>, <span class="type">Person</span> <span class="variable">r2</span>) =&gt; !(r1 == r2);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="reserved">operator</span> ==(<span class="type">Person</span> <span class="variable">r1</span>, <span class="type">Person</span> <span class="variable">r2</span>) =&gt; (<span class="reserved">object</span>)r1 == r2 || (r1 <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span> &amp;&amp; r1.Equals(r2));
 
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">int</span> <span class="method">GetHashCode</span>()
        =&gt; (<span class="type">EqualityComparer</span>&lt;Type&gt;.Default.GetHashCode(EqualityContract) * -1521134295
        + <span class="type">EqualityComparer</span>&lt;<span class="reserved">string</span>&gt;.Default.GetHashCode(Name)) * -1521134295
        + <span class="type">EqualityComparer</span>&lt;<span class="type">DateTime</span>&gt;.Default.GetHashCode(Birthday);
 
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">bool</span> <span class="method">Equals</span>(<span class="reserved">object</span> <span class="variable">obj</span>) =&gt; Equals(obj <span class="reserved">as</span> <span class="type">Person</span>);
 
    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="reserved">bool</span> <span class="method">Equals</span>(<span class="type">Person</span> <span class="variable">other</span>)
        =&gt; (<span class="reserved">object</span>)other != <span class="reserved">null</span>
        &amp;&amp; EqualityContract == other.EqualityContract
        &amp;&amp; <span class="type">EqualityComparer</span>&lt;<span class="reserved">string</span>&gt;.Default.Equals(Name, other.Name)
        &amp;&amp; <span class="type">EqualityComparer</span>&lt;<span class="type">DateTime</span>&gt;.Default.Equals(Birthday, other.Birthday);
 
    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="type">Person</span> <span class="method">Clone</span>() =&gt; <span class="reserved">new</span> Person(<span class="reserved">this</span>);
 
    <span class="reserved">protected</span> <span class="type">Person</span>(<span class="type">Person</span> <span class="variable">original</span>)
    {
        Name = original.Name;
        Birthday = original.Birthday;
    }
}
</code></pre>
<h3><a id="equality">等値判定</a></h3>
<p>前節で示した通り、レコード型を書くと自動的に <code>==</code> や <code>Equals</code> などの等値判定用のメソッド・演算子が追加されます。</p>
<p>ここで1点注意なんですが、レコード型から作られる <code>==</code> や <code>Equals</code> は <code>EqualityComparer&lt;T&gt;.Default</code> を経由して、最終的にはプロパティごとに <code>Equals</code> メソッドを呼ぶことになります。
通常、<code>==</code> と <code>Equals</code> の結果が違うなんてことは求められないので、
そんな実装になっていることはめったにはありませんが…
悪名高いものとして、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.double.nan"><code>NaN</code></a> (<a href="https://ja.wikipedia.org/wiki/NaN">Not a Number</a>)は <code>==</code> と <code>Equals</code> の結果が違ったりするので、
「<code>double</code> で直接比較」と「レコード型で1段包んで比較」の結果が変わったりします。</p>
<pre class="source" title="== も内部的には Equals を呼ぶ仕様">
<code><span class="reserved">using</span> System;
 
<span class="reserved">double</span> <span class="variable">nan</span> = <span class="reserved">double</span>.NaN;
 
Console.WriteLine(nan == nan); <span class="comment">// 常に false を返す。</span>
Console.WriteLine(nan.Equals(nan)); <span class="comment">// こっちは true だったりする。</span>
 
<span class="reserved">var</span> <span class="variable">recordNan</span> = <span class="reserved">new</span> Double(nan);
 
Console.WriteLine(recordNan == recordNan); <span class="comment">// true</span>
Console.WriteLine(recordNan.Equals(recordNan)); <span class="comment">// true</span>
 
<span class="reserved">record</span> <span class="type">Double</span>(<span class="reserved">double</span> <span class="variable">Value</span>);
</code></pre>
<p>ちなみに、等値判定を <code>EqualityComparer&lt;T&gt;.Default</code> 越しにやっている都合で、レコード型のプロパティやフィールドに型引数にできない型(例えば<a href="https://ufcpp.net/study/csharp/sp_unsafe.html#pointer">ポインター</a>や<a href="https://ufcpp.net/study/csharp/resource/refstruct/">ref 構造体</a>など)は使えません。<code>unsafe record R(int* P);</code> はコンパイル エラーになります。</p>
<h3><a id="record-struct">record class と record struct</a></h3>
<h5 class="version version10">Ver. 10</h5>
<p>C# 9.0 (レコード型の最初のバージョン)では、レコード型は常に<a href="/study/csharp/oo_reference.html#reftype">参照型</a>(クラスと同系統の型)になります。
これに対して C# 10.0 では<a href="/study/csharp/oo_reference.html#valtype">値型</a>も選べるようにしました。
そのため、以下のように、<code>record class</code> と <code>record struct</code> というキーワードで書き分けができるようになりました。</p>
<pre class="source" title="C# 10.0 の record class と record struct">
<code><span class="reserved">record</span> <span class="reserved">class</span> <span class="type">Reference</span>(<span class="reserved">int</span> <span class="variable">X</span>, <span class="reserved">int</span> <span class="variable">Y</span>); <span class="comment">// record だけ書いた場合こちらと同じ意味</span>
<span class="reserved">record</span> <span class="reserved">struct</span> <span class="type">Value</span>(<span class="reserved">int</span> <span class="variable">X</span>, <span class="reserved">int</span> <span class="variable">Y</span>);
</code></pre>
<p>ちなみに、C# 9.0 の頃からある <code>record</code> だけを使う書き方と、C# 10.0 で追加された <code>record class</code> という書き方は全く同じ意味になります。
(レコード型の思想としては、一番よく使う書き方を極力短く書けるようにしたいというものがあって、
「クラスの方がよく使うから、<code>record</code> という短い書き方は <code>record class</code> の意味で使う」という判断があるようです。)</p>
<h4><a id="record-struct-specific">record struct の特徴</h4>
<p><code>record class</code> と <code>record struct</code> の差は、ほぼ<a href="https://ufcpp.net/study/csharp/oo_reference.html">クラス(参照型)と構造体(値型)の差</a>そのままなんですが、
ちょっとだけ細かい差があります。
(といっても、それも参照型と値型の用途の違いからくるものです。)</p>
<p>まず、構造体の場合は<a href="https://ufcpp.net/study/csharp/oo_inherit.html">継承</a>がありません。
なので、継承に関係して必要になる <a href="https://ufcpp.net/study/csharp/datatype/record/#inheritance"><code>EqualityContract</code> プロパティ</a>は生成されません。</p>
<p>また、構造体の場合、mutable (最初に作ったタイミング以外でも好きなタイミングでメンバーを書き換え可能)であっても <code>record class</code> ほど問題は起こしません。
なので、<code>record struct</code> (だけ書く)だと、mutable なプロパティが生成されます。</p>
<pre class="source" title="record class と record struct からの生成物">
<code><span class="comment">// class の場合、X, Y から生成されるプロパティは</comment>
<span class="comment">// public int X { get; <em>init;</em> }</comment>
<span class="comment">// public int Y { get; <em>init;</em> }</comment>
<span class="reserved">record</span> <span class="reserved">class</span> <span class="type">RecordClass</span>(<span class="reserved">int</span> X, <span class="reserved">int</span> Y);

<span class="comment">// struct の場合は、</comment>
<span class="comment">// public int X { get; <em>set;</em> }</comment>
<span class="comment">// public int Y { get; <em>set;</em> }</comment>
<span class="reserved">record</span> <span class="reserved">struct</span> <span class="type">RecordStruct</span>(<span class="reserved">int</span> X, <span class="reserved">int</span> Y);
</code></pre>
<p>構造体には <a href="https://ufcpp.net/study/csharp/resource/readonlyness/#readonly-struct"><code>readonly</code> 修飾</a>を付けることができるので、immutable (書き換え不能)な <code>record struct</code> を作りたければ <code>readonly record struct</code> と書きます。
この場合は <code>record class</code> と同じようなプロパティが生成されます。</p>
<pre class="source" title="readonly record struct からの生成物">
<code><span class="comment">// readonly struct の場合は、</comment>
<span class="comment">// public int X { get; <em>init;</em> }</comment>
<span class="comment">// public int Y { get; <em>init;</em> }</comment>
<span class="reserved">readonly record</span> <span class="reserved">struct</span> <span class="type">ReadOnlyRecordStruct</span>(<span class="reserved">int</span> X, <span class="reserved">int</span> Y);
</code></pre>
<h3><a id="anonymous-type">レコード型と匿名型</a></h3>
<p>導入順序的な問題で、C# 的に言うとレコード型は「名前のある<a href="/study/csharp/sp3_inference.html#anonymous">匿名型</a>」みたいな感じ(トゲナシトゲトゲっぽいやつ)だったりはします。
(匿名型が C# 3.0 で導入された機能なのに対して、レコード型は C# 9.0 です。)</p>
<p>C# は既存機能と新機能の整合性を極力取るように頑張って機能追加をしていて、
レコード型追加の際には匿名型や<a href="/study/csharp/datatype/tuples#key-tuple">タプル</a>との整合性を結構気にして設計しています。</p>
<p>例えば以下のようなコードがあったとします。
これは「とりあえず型名は付けずに匿名(タプル)でコードを書いてみた」みたいな状態です。</p>
<pre class="source" title="まずタプルでコードを書いてみた状態">
<code><span class="reserved">using</span> System;
 
<span class="reserved">var</span> <span class="variable">p</span> = (X: 1, Y: 2); <span class="comment">// これはタプル</span>
var (<span class="variable">x</span>, <span class="variable">y</span>) = p;
Console.WriteLine(<span class="string">$&quot;</span>{x}<span class="string"> * </span>{y}<span class="string"> = </span>{x * y}<span class="string">&quot;</span>);
</code></pre>
<p>ここで、<code>X, Y</code> のペアに <code>Point</code> という名前を付けたいとして、そのためにレコード型を使ったとします。</p>
<pre class="source" title="">
<code><span class="reserved">record</span> <span class="type">Point</span>(<span class="reserved">int</span> <span class="variable">X</span>, <span class="reserved">int</span> <span class="variable">Y</span>);
</code></pre>
<p>先ほどのコードには、<code>new Point</code> を足すだけで「匿名の型から名前付きの型に移行」ができます。</p>
<pre class="source" title="new Point を足すだけで名前付きの型に移行">
<code><span class="reserved">using</span> System;
 
<span class="reserved">var</span> <span class="variable">p</span> = <span class="reserved">new</span> <span class="type">Point</span>(X: 1, Y: 2); <span class="comment">// これで名前付きになった</span>
var (<span class="variable">x</span>, <span class="variable">y</span>) = p;
Console.WriteLine(<span class="string">$&quot;</span>{x}<span class="string"> * </span>{y}<span class="string"> = </span>{x * y}<span class="string">&quot;</span>);
</code></pre>
<h3><a id="vs-normal-struct">レコード型と構造体</a></h3>
<p>プロパティごとの比較で等値判定したり、プロパティごとの代入でクローン(後述の <a href="#with"><code>with</code> 式</a>を使う)を作ったりを取ったりする操作は、構造体であれば元々できる操作です。
ある意味、C# 9.0 で導入されたレコード型は「構造体(値型)的な扱いができるクラス(参照型)を作れるようにする」と言うものです。
(こういう操作ができることを「値セマンティクス(value semantics)を持つ」という用語で呼んだりします。)</p>
<p>一方で、C# 10.0 では <code>record struct</code> が追加されました。
「構造体的な扱いができるクラスの構造体版」みたいなものができてしまったわけですが…</p>
<p>当初、「通常の構造体にレコード型と同程度の機能性を持たせるように仕様を変えようか」という案も上がっていました。
しかし、その案だと、
既存コードへの影響が大きすぎたり、
コンパイラーによる自動生成物が増えることが好ましくない場面もあったりで、
デメリットもそれなりにあります。
なので結局、通常の構造体(<code>struct</code>)とは別に「構造体版レコード」(<code>record struct</code>)が追加されました。</p>
<p>大まかな違いとしては、次節のプライマリ コンストラクターを持てる点と、<code>IEquatable&lt;T&gt;</code> インターフェイス実装がコンパイラー生成される点です。</p>
<ul>
<li>
プライマリ コンストラクターを持てる
<ul>
<li>その引数からプロパティや <a href="https://ufcpp.net/study/csharp/datatype/deconstruction/#arbitrary-types"><code>Deconstruct</code> メソッド</a>がコンパイラー生成される</li>
</ul>
</li>
<li>
<code>IEquatable&lt;T&gt;</code> インターフェイス実装がコンパイラー生成される
<ul>
<li>通常の構造体よりも <code>Equals</code> のパフォーマンスがいい</li>
<li>ただし、コンパイル結果のプログラム サイズがちょっと大きくなる</li>
<li>インターフェイスを実装する都合上、<a href="https://ufcpp.net/study/csharp/resource/refstruct/">ref 構造体</a> と両立しない (<code>ref record struct</code> とは書けない)</li>
</ul>
</li>
</ul>
<h2><a id="primary-constructor">プライマリ コンストラクター</a></h2>
<p>先ほど、レコード型の最も短い書き方として以下のような例を挙げました。</p>
<pre class="source" title="record の例">
<code><span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>);
</code></pre>
<p>この、型名の直後に <code>()</code> でコンストラクター引数を並べる書き方を<strong id="key-primary-constructor" class="keyword">プライマリ コンストラクター</strong>と言います。</p>
<p>名前にコンストラクターと入っている通り、この構文からコンストラクターがコンパイラー生成されます。
それだけではなく、引数名と同名の <a href="/study/csharp/oo_property.html#init-only">init-only プロパティ</a>が生成されます。
<a href="#record-to-class">前述</a>の「レコード型から生成されるクラスの例」で挙げたコードのうち、
以下のものは「プライマリ コンストラクターからの生成物」になります。</p>
<pre class="source" title="レコード型からコンパイラー生成されるクラスの例">
<code><span class="reserved">class</span> <span class="type">Person</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> Name { <span class="reserved">get</span>; <span class="reserved">init</span>; }
    <span class="reserved">public</span> <span class="type">DateTime</span> Birthday { <span class="reserved">get</span>; <span class="reserved">init</span>; }

    <span class="reserved">public</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>)
    {
        <span class="reserved">this</span>.Name = Name;
        <span class="reserved">this</span>.Birthday = Birthday;
    }
    
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">string</span> <span class="variable">Name</span>, <span class="reserved">out</span> <span class="type">DateTime</span> <span class="variable">Birthday</span>)
    {
        Name = <span class="reserved">this</span>.Name;
        Birthday = <span class="reserved">this</span>.Birthday;
    }
}
</code></pre>
<p>残りの <code>Equals</code> や <code>PrintMember</code> などについては、プライマリ コンストラクターの有無にかかわらず、
レコード型であれば常にコンパイラー生成されます。
(public な get アクセサーを持ったすべてのプロパティが「生成元」になります。)</p>
<p>ちなみに、プライマリ コンストラクターの引数は、以下のように、
他のメンバーの初期化子や、メソッドの中身で参照することもできます。</p>
<pre class="source" title="プライマリ コンストラクターの引数を初期化子などから参照する例">
<code><span class="reserved">record</span> <span class="type">X</span>(<span class="reserved">int</span> <span class="variable">Value</span>)
{
    <span class="reserved">public</span> <span class="reserved">int</span> Squared { <span class="reserved">get</span>; } = Value * Value;
    <span class="reserved">public</span> <span class="reserved">int</span> Cubed { <span class="reserved">get</span>; } = Value * Value * Value;
    <span class="reserved">public</span> <span class="reserved">double</span> <span class="method">GetSqrt</span>() =&gt; Math.Sqrt(Value);
}
</code></pre>
<p>また「プライマリ」(primary: 一番の、最優先の)の名前の通り、
このコンストラクターは特別というか、「手書きで他のコンストラクターを書き足す場合、必ずプライマリ コンストラクターが呼ばれるようにしなければならない」という強い制約が掛かります。
例えば以下のコードはコンパイル エラーを起こします。</p>
<pre class="source" title="プライマリ コンストラクターを呼んでいなくてエラーになる例">
<code><span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>)
{
    <span class="comment">// プライマリ コンストラクターを呼んでいないのでコンパイル エラーになる。</span>
    <span class="reserved">public</span> <span class="type">Person</span>() { }
}
</code></pre>
<p>以下のように <code>this</code> 初期化子を足せばコンパイルできるようになります。</p>
<pre class="source" title="this 初期化子でプライマリ コンストラクターを呼ぶ例">
<code><span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>)
{
    <span class="comment">// これならエラーにはならない。</span>
    <span class="comment">// (&quot;&quot; や default をとりあえず入れてしまう行為の良し悪しは置いておいて…)</span>
    <span class="reserved">public</span> <span class="type">Person</span>() : <span class="reserved">this</span>(<span class="string">&quot;&quot;</span>, <span class="reserved">default</span>(<span class="type">DateTime</span>)) { }
}
</code></pre>
<p>ちなみに、プライマリ コンストラクターの引数に <a href="https://ufcpp.net/study/csharp/sp_ref.html#in"><code>in</code></a> と <a href="https://ufcpp.net/study/csharp/sp_params.html"><code>params</code></a> を付けることはできます(その引数からプロパティの生成もされます)が、<a href="https://ufcpp.net/study/csharp/sp_ref.html#sec-byref"><code>ref</code></a> と <a href="https://ufcpp.net/study/csharp/sp_ref.html#out"><code>out</code></a> は付けれません。</p>
<pre class="source" title="プライマリ コンストラクター引数に対する in/params">
<code><span class="comment">// in と params は受け付ける。</span>
<span class="reserved">public</span> <span class="reserved">record</span> <span class="type">Record</span>(<span class="reserved">in</span> <span class="reserved">int</span> X, <span class="reserved">params</span> <span class="reserved">int</span>[] Y);

<span class="comment">// ちなみに、 ref と out はダメ。</span>
<span class="reserved">public</span> <span class="reserved">record</span> <span class="type">Record2</span>(<span class="reserved"><span class="error">ref</span></span> <span class="reserved">int</span> X, <span class="reserved"><span class="error">out</span></span> <span class="reserved">int</span> Y);
</code></pre>
<h3><a id="primary-constructor-attribute">プライマリ コンストラクター引数への属性付与</a></h3>
<p>プライマリ コンストラクターからはプロパティがコンパイラー生成されます。
また、<a href="/study/csharp/oo_property.html#auto">プロパティからもさらにフィールドが生成</a>されています。
ということで、プライマリ コンストラクターの引数には3重の意味(引数、プロパティ、フィールド)が含まれていたりします。</p>
<p>必要となる場面はそれほど多くはないと思いますが、
コンパイラー生成されるプロパティやフィールドに対しても、
以下のような書き方で属性を付けることができます。</p>
<pre class="source" title="プライマリ コンストラクターから生成されるプロパティ、フィールドに属性を付ける例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Reflection;
 
<span class="reserved">var</span> <span class="variable">t</span> = <span class="reserved">typeof</span>(X);
 
<span class="comment">// parameter</span>
Console.WriteLine(t.GetConstructor(<span class="reserved">new</span>[] { <span class="reserved">typeof</span>(<span class="reserved">int</span>) }).GetParameters()[0].GetCustomAttribute&lt;A&gt;().Name);
 
<span class="comment">// property</span>
Console.WriteLine(t.GetProperty(<span class="string">&quot;Value&quot;</span>).GetCustomAttribute&lt;A&gt;().Name);
 
<span class="comment">// field</span>
Console.WriteLine(t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)[0].GetCustomAttribute&lt;A&gt;().Name);
 
<span class="reserved">record</span> <span class="type">X</span>(
    [A(<span class="string">&quot;parameter&quot;</span>)]
    [<span class="reserved"><em>property</em></span>: A(<span class="string">&quot;property&quot;</span>)]
    [<span class="reserved"><em>field</em></span>: A(<span class="string">&quot;field&quot;</span>)]
    <span class="reserved">int</span> <span class="variable">Value</span>);
 
<span class="reserved">class</span> <span class="type">A</span> : Attribute
{
    <span class="reserved">public</span> <span class="reserved">string</span> Name { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">A</span>(<span class="reserved">string</span> <span class="variable">name</span>) =&gt; Name = name;
}
</code></pre>
<h2><a id="manual-override">生成物の上書き</a></h2>
<p>レコード型の目標の1つは「お作法として最も好ましいものを最も短い書き方で書ける」というものです。</p>
<p>一方で、わかった上でお作法から外れたい場合や、ちょっとしたカスタマイズをしたい場合もあります。
そこで、C# のレコード型では、コンパイラー生成されるであろう物と同名のプロパティやメソッドを手書きすると、
手書きした方のコードが優先される仕様になっています。</p>
<p>例えば、文字列の比較で大文字・小文字を無視したい場合、<code>Equals</code> メソッドなどを以下のように書き加えることでできます。
(例と言うことで <code>Equals</code> のみを書きますが、実際は <code>GetHashCode</code> などの書き足しも必要です。)</p>
<pre class="source" title="Equals をカスタマイズする例">
<code><span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>)
{
    <span class="reserved">bool</span> <span class="type">IEquatable</span>&lt;<span class="type">Person</span>&gt;.<span class="method">Equals</span>(<span class="type">Person</span>? <span class="variable">other</span>)
        =&gt; <span class="variable">other</span> <span class="reserved">is</span> <span class="reserved">not</span> <span class="reserved">null</span>
        &amp;&amp; Name.Equals(<span class="variable">other</span>.Name, <em><span class="type">StringComparison</span>.OrdinalIgnoreCase</em>)
        &amp;&amp; Birthday == <span class="variable">other</span>.Birthday;
}
</code></pre>
<p>他の例として、本来あまり好ましくはないんですが、プロパティを書き換え可能にしてしまいたい場合、
以下のようにプロパティを手書きで足してしまうことでできます。</p>
<pre class="source" title="生成されるプロパティのカスタマイズする例">
<code><span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>)
{
    <span class="reserved">public</span> <span class="reserved">string</span> Name { <span class="reserved">get</span>; <span class="reserved"><em>set</em></span>; } = Name;
    <span class="reserved">public</span> <span class="type">DateTime</span> Birthday { <span class="reserved">get</span>; <span class="reserved"><em>set</em></span>; } = Birthday;
}
</code></pre>
<p>ちなみに、この場合、「<code>Name</code> 引数を <code>Name</code> プロパティに自動代入する」みたいな処理は掛からないので注意が必要です。
上記の例で <code>Name { get; } = Name;</code> としているように、明示的な初期化が必要になります。</p>
<h3><a id="manual-override-field">フィールドでの生成物の上書き</a></h3>
<h5 class="version version10">Ver. 10</h5>
<p>C# 9.0 時点では、プライマリ コンストラクター引数からの生成物の上書きはプロパティでしかできませんでした。</p>
<p>これが C# 10.0 ではフィールドでも上書きできるようになりました。
例えば以下のコードは C# 10.0 から有効なコードになります。
(C# 9.0 時代は「(生成物の)プロパティ <code>X</code> と(手書きの)フィールド <code>X</code> が名前衝突してる」というエラーになっていました。)</p>
<pre class="source" title="フィールドでプライマリ コンストラクター引数から生成されるはずだったプロパティを上書きする例">
<code><span class="reserved">record</span> <span class="type">R</span>(<span class="reserved">int</span> X)
{
    <span class="reserved">public</span> <span class="reserved">int</span> X = X;
}
</code></pre>
<p><code>record struct</code> を導入するにあたって、
「クラスと違って、構造体では public フィールドを使うことがそれなりに需要としてある」
という背景からこの仕様が入りました。
プロパティ生成を抑止して、フィールドに変えたいときにこの機能を使います。</p>
<p>とはいえ、別に <code>record class</code> で使えてしまって困る機能でもないので、クラスか構造体かは問わずこの機能を使えます。</p>
<h2><a id="inheritance">レコード型の継承</a></h2>
<p>レコード型はクラスと同じく<a href="/study/csharp/oo_inherit.html">継承</a>ができます。
例えば以下のように書けます。</p>
<pre class="source" title="レコード型の継承">
<code><span class="reserved">record</span> <span class="type">Base</span>;
<span class="reserved">record</span> <span class="type">A</span>(<span class="reserved">int</span> <span class="variable">N</span>) : Base;
<span class="reserved">record</span> <span class="type">B</span>(<span class="reserved">string</span> <span class="variable">S</span>) : Base;
</code></pre>
<p>ちなみに、基底クラスがプライマリ コンストラクターを持っている場合、
派生クラスからそのプライマリ コンストラクターの呼び出しが必要です。
以下のように、基底クラス名の後ろに <code>()</code> を付けることで呼び出せます。</p>
<pre class="source" title="基底クラスのプライマリ コンストラクター呼び出しの例">
<code><span class="reserved">record</span> <span class="type">Base</span>(<span class="reserved">int</span> <span class="variable">X</span>);
 
<span class="comment">// Base(int X) を呼んでいないのでエラーになる。</span>
<span class="reserved">record</span> <span class="error"><span class="type">Error1</span></span>(<span class="reserved">int</span> <span class="variable">X</span>) : Base;
 
<span class="comment">// コンパイルできる例1: 引数を伝搬。</span>
<span class="reserved">record</span> <span class="type">Ok1</span>(<span class="reserved">int</span> <span class="variable">X</span>) : Base(X);
 
<span class="comment">// コンパイルできる例2: 引数に何らかの既定値を与える。</span>
<span class="reserved">record</span> <span class="type">Ok2</span>() : Base(1);
 
<span class="comment">// コンパイルできる例3: 引数を伝搬しつつ、プロパティ Y を追加。</span>
<span class="comment">// (この場合、X は Base.X が優先されて、Ok3.X はコンパイラー生成されない。)</span>
<span class="reserved">record</span> <span class="type">Ok3</span>(<span class="reserved">int</span> <span class="variable">X</span>, <span class="reserved">int</span> <span class="variable">Y</span>) : Base(X);
 
<span class="comment">// Ok2 と似たようなものだけど、これはコンパイルできない。</span>
<span class="comment">// コンパイラーの実装都合で () が必要。</span>
<span class="reserved">record</span> <span class="error"><span class="type">Error2</span></span> : Base(1);
</code></pre>
<p>また、将来的なことを言うと、以下のような話もあります。</p>
<ul>
<li>
C# 9.0 時点ではレコード型の派生はレコード型同士でしかできない
<ul>
<li>将来的にはクラスからレコード型、レコード型からクラスの派生も認めるかもしれない</li>
</ul>
</li>
<li>
<code>record struct</code> が入るとすると、派生できるのは <code>record class</code> のみ
<ul>
<li>(単に <code>record</code> と書くと <code>record class</code> の意味なので派生できる)</li>
</ul>
</li>
</ul>
<p>ちなみに、「<a href="#record-to-class">レコード型とクラス</a>」で書いたコンパイラー生成物に <code>EqualityContract</code> というプロパティがありますが、
これは派生クラスを弁別するためにあります。</p>
<p>例えば以下のコードの出力結果は false です。</p>
<pre class="source" title="(既定動作では)レコード型の == は型判定を含んでいる">
<code><span class="reserved">using</span> System;
 
<span class="comment">// 同じ値を持っていても型が違うと「不一致」扱い。</span>
Console.WriteLine(<span class="reserved">new</span> Base(1) == <span class="reserved">new</span> Derived(1)); <span class="comment">// false</span>
 
<span class="reserved">record</span> <span class="type">Base</span>(<span class="reserved">int</span> <span class="variable">X</span>);
<span class="reserved">record</span> <span class="type">Derived</span>(<span class="reserved">int</span> <span class="variable">X</span>) : Base(X);
</code></pre>
<p>コンパイラー生成物の <code>Equals</code> 等が <code>EqualityContract == other.EqualityContract</code> みたいなコードを含んでいるのはこのためです。
ちなみに、ちゃんと <code>new Base(x).Equals(new Derived(y))</code> と <code>new Derived(y).Equals(new Base(x))</code> の結果が一致するように作られています。
(これが成り立つようにするのは意外と手間で、レコード型からのコンパイラー生成物は結構なコード量になっていますし、手書きメンバー追加でのカスタマイズは結構大変です。)</p>
<p>逆に、型は無視してプロパティの一致だけで等価判定してほしい場合、以下のように <code>EqualityContract</code> を手書き追加すればできます。</p>
<pre class="source" title="EqualityContract の手書きで挙動をカスタマイズする例">
<code><span class="reserved">using</span> System;
 
<span class="comment">// EqualityContract で typeof(Base) を返すことで「一致」扱いに変わる。</span>
Console.WriteLine(<span class="reserved">new</span> Base(1) == <span class="reserved">new</span> Derived(1)); <span class="comment">// true</span>
 
<span class="reserved">record</span> <span class="type">Base</span>(<span class="reserved">int</span> <span class="variable">X</span>);
<span class="reserved">record</span> <span class="type">Derived</span>(<span class="reserved">int</span> <span class="variable">X</span>) : Base(X)
{
    <span class="reserved">protected</span> <span class="reserved">override</span> Type EqualityContract =&gt; <span class="reserved">typeof</span>(Base);
}
</code></pre>
<h2><a id="with">with 式</a></h2>
<p>「お作法として好ましいのは immutable (書き換え不可)」と言いましたし、
レコード型もそのお作法に則って(手書きでカスタマイズしない限り) immutable な型を生成します。</p>
<p>immutable なデータに対しても、「データの一部分だけを書き換えたい」という要件はよくあるんですが、
この場合「元のデータを書き換えず、クローンして一部分書き換えたデータを新規作成」という手順を踏みます。
C# 8.0 以前の書き方でいうと、以下のようなコードを書くことになります。
(が、1つ問題があって、実際には C# 8.0 で完全にこれと同じことは実現できません。)</p>
<pre class="source" title="クローンしてから部分書き換え">
<code><span class="reserved">using</span> System;
 
<span class="reserved">var</span> <span class="variable">p1</span> = <span class="reserved">new</span> <span class="type">Person</span>(<span class="string">&quot;天馬飛雄&quot;</span>, <span class="reserved">new</span>(2003, 4, 7));
 
<span class="reserved">var</span> <span class="variable">p2</span> = p1.Clone();
<span class="error">p2.Name</span> = <span class="string">&quot;鉄腕アトム&quot;</span>;
 
<span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable">Name</span>, <span class="type">DateTime</span> <span class="variable">Birthday</span>);
</code></pre>
<p>このコードなんですが、(immutable というお作法上)「<code>Name</code> は書き換え不能」で作られているはずです。
その書き換え不能プロパティを書き換えないといけないので、C# 8.0 でこれと同様のコードは書けません。
これが <a href="/study/csharp/oo_property.html#init-only">init-only プロパティ</a>という機能の導入の動機で、C# コンパイラーが「クローン直後」だけを特別扱いして書き換えを認めています。</p>
<p>C# 9.0 ではどうしたかと言うと、<code>with</code> 式という構文を追加しました。
これが内部的に上記の「まずクローンして、クローン直後のインスタンスの一部分を書き換える」という処理に展開されます。</p>
<pre class="source" title="with 式で immutable データの一部分を書き換え">
<code><span class="reserved">var</span> <span class="variable">p1</span> = <span class="reserved">new</span> <span class="type">Person</span>(<span class="string">&quot;天馬飛雄&quot;</span>, <span class="reserved">new</span>(2003, 4, 7));
<span class="reserved">var</span> <span class="variable">p2</span> = p1 <span class="reserved">with</span> { Name = <span class="string">&quot;鉄腕アトム&quot;</span> };
</code></pre>
<p>とりあえず以下のように覚えてください。</p>
<ul>
<li>immutable なデータに対して一部分だけの書き換えをしたいときには <code>with</code> 式を使う</li>
<li>内部的にやっていることはクローンしてからの部分書き換え</li>
</ul>
<p>ちなみに、<code>with { }</code> だけ書く(「一部書き換え」はしない)のでもクローンになります。</p>
<pre class="source" title="with { } でクローン">
<code><span class="reserved">using</span> System;
 
<span class="reserved">var</span> <span class="variable">p1</span> = <span class="reserved">new</span> Point(1, 2);
<span class="reserved">var</span> <span class="variable">p2</span> = p1 <span class="reserved">with</span> { }; <span class="comment">// p1 のクローンが作られる</span>
 
Console.WriteLine(p1 == p2); <span class="comment">// 持ってる値的には等しいので true。</span>
Console.WriteLine(ReferenceEquals(p1, p2)); <span class="comment">// クローン(別インスタンス)ができてるのでこちらは false。</span>
 
<span class="reserved">record</span> <span class="type">Point</span>(<span class="reserved">int</span> <span class="variable">X</span>, <span class="reserved">int</span> <span class="variable">Y</span>);
</code></pre>
<p>また、C# 9.0 時点ではクローン用のメソッドを <code>with</code> 式以外から呼ぶ手段はありません。
(<code>&lt;Clone&gt;$</code> みたいな通常の C# コードでは書けないような変な名前でクローン メソッドが生成されています。
逆に、この自動生成のクローンと紛らわしくならないようにするため、
レコード型に自前で <code>Clone</code> という名前のメソッドを定義することは認められていません。)
将来的には認める可能性もあるものの、現状は「クローン方法のカスタマイズ」もできません
(<code>Equals</code> 等と違って、<code>&lt;Clone&gt;$</code> メソッドを「手書きで上書き」はできません)。</p>
<p>また、このクローン用メソッドを手書きできない都合上、C# 9.0 時点では <code>with</code> 式はレコード型専用の構文になります。
(ただし、C# 10.0 で <code>struct</code> に対しては <code>with</code> 式を使えるようになる予定です。
構造体は元からクローン相当の機能を持っているので、それを使う予定です。)</p>
<h3><a id="anonymous-type">匿名型と構造体に対する with 式</a></h3>
<h5 class="version version10">Ver. 10</h5>
<p>C# 9.0 時点では、<code>with</code> 式はレコード型に対してしか使えません。
ただ、<code>with</code> 式に求められる要件は「クローンメソッドを持っていて、<code>set</code> もしくは <code>init</code> 持ちのプロパティがある」という点だけです。
前述の通り、「クローン方法のカスタマイズ」を提供することで任意の型に対して <code>with</code> 式を使えるようにするという提案も出ていますが、その一方で、C# 9.0 時点でも <code>with</code> 式が使える条件を満たせるけどもスケジュールの都合で C# 10.0 での実装になったものもあります。</p>
<p>ということで C# 10.0 では、匿名型と、任意の構造体に対して <code>with</code> 式を使えるようになりました。
以下のコードは C# 9.0 ではコンパイルできませんが、C# 10.0  ではコンパイルできるます。</p>
<p><a href="https://ufcpp.net/study/csharp/sp3_inference.html#anonymous">匿名型</a>:</p>
<pre class="source" title="匿名型に対する with 式">
<code><span class="reserved">var</span> <span class="variable">p1</span> = <span class="reserved">new</span> { X = 1, Y = 2 };
<span class="reserved">var</span> <span class="variable">p2</span> = p1 <span class="reserved">with</span> { X = 3 };
</code></pre>
<p>任意の<a href="https://ufcpp.net/study/csharp/resource/rm_struct/">構造体</a>:</p>
<pre class="source" title="構造体に対する with 式">
<code><span class="reserved">var</span> <span class="variable">p1</span> = <span class="reserved">new</span> Point { X = 1, Y = 2 };
<span class="reserved">var</span> <span class="variable">p2</span> = p1 <span class="reserved">with</span> { X = 3 };
 
<span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; <span class="reserved">init</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; <span class="reserved">init</span>; }
}
</code></pre> ]]></description>
				<pubDate>Sun, 02 May 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>モジュール初期化子</title>
				<link>http://www.ufcpp.net/study/csharp/oop/moduleinitializer/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</a></h2>
<h5 class="version version9">Ver. 9</h5>
<p>プログラムの実行時、最初に1回だけ呼び出したい処理が必要になることがあります。
「<a href="https://ufcpp.net/study/csharp/oo_static.html#ctor">静的コンストラクター</a>」で説明しているように、この静的コンストラクターという機能を使っても「最初に1回だけ呼ばれる」ということができますが、C# 9.0 ではモジュール初期化子という書き方もできるようになりました。</p>
<h2><a id="module-initializer">モジュール初期化子</a></h2>
<p>「<a href="https://ufcpp.net/study/csharp/oo_static.html#ctor">静的コンストラクター</a>」を使うとプログラム中で1回だけ呼び出される処理を書くことができます。
静的コンストラクターが呼び出されるタイミングは、そのクラスのなんらかのメンバーに初めてアクセスしたときです。</p>
<p>C# 9.0 では、もう1種類、「最初に1回だけ呼ばれる」という性質の処理の書き方ができるようになりました。
以下のように、<code>ModuleInitilizer</code> 属性(<code>System.Runtime.CompilerServices</code> 名前空間)を付けた<a href="https://ufcpp.net/study/csharp/oo_static.html#stmethod">静的メソッド</a>を書くと、それが必ず1回呼び出されるようになります。</p>
<pre class="source" title="ModuleInitialize 属性">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.CompilerServices;
 
<span class="reserved">class</span> <span class="type">Sample</span>
{
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init</span>()
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;必ず1回だけ呼ばれる&quot;</span>);
    }
}
</code></pre>
<p>これを<strong id="key-module-initializer" class="keyword">モジュール初期化子</strong>(module initializer)と呼びます。</p>
<p>静的コンストラクターとの差は以下の通りです。</p>
<ul>
<li>
1つのクラスに複数のモジュール初期化子を書ける
<ul>
<li><a href="https://ufcpp.net/study/csharp/oo_class.html#partial"><code>partial</code></a> を使って複数のファイルに分かれていても全部呼ばれる</li>
</ul>
</li>
<li>そのクラスを含んでいるモジュールを読み込んだ時点で呼ばれる</li>
</ul>
<p>静的コンストラクターの呼び出しには「そのクラスのなんらかのメンバーにアクセス」という条件が付くので、確実に呼び出される保証が実はなかったりします。
モジュール初期化子の呼び出しも「モジュールを読み込む」(モジュールに含まれているなんらかの型に触れる)という条件は付くんですが、静的コンストラクターと比べればだいぶ確実に呼ばれます。
(一切何の型も使わないモジュールを参照すること自体がほとんどないので、実質的には「確実」と行ってしまっても構わないと思います。)</p>
<h3><a id="module-initializer-impl">モジュール初期化子の実装方法</a></h3>
<p>「モジュール読み込み時に必ず呼ばれる」というもの自体は .NET Framework 1.0 の頃から実はありました(単に C# から使う手段がなかっただけ)。
当初から、「<code>&lt;Module&gt;</code> という特殊な名前のクラスの静的コンストラクターは、モジュール読み込み時に必ず1回呼ばれる」という仕様があります。
<code>&lt;&gt;</code> を含む名前なので通常の C# コードで書くことはできませんし、C# 8.0 まではこの型の静的コンストラクターを書き出す手段もありませんでした。</p>
<p>C# 9.0 のモジュール初期化子がやっていることはこの「<code>&lt;Module&gt;</code> クラスの静的コンストラクターの生成」です。
例えば以下のようなコードを書いたとすると、</p>
<pre class="source" title="モジュール初期化子(&lt;Module&gt; クラスの生成元)">
<code><span class="reserved">using</span> System.Runtime.CompilerServices;
 
<span class="reserved">class</span> <span class="type">C1</span>
{
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init1</span>() { }
 
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init2</span>() { }
}
 
<span class="reserved">class</span> <span class="type">C2</span>
{
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init1</span>() { }
 
}
</code></pre>
<p>以下のようなコードに相当するものがコンパイラーによって追加されます。</p>
<pre class="source" title="モジュール初期化子から生成される &lt;Module&gt; クラス">
<code><span class="reserved">class</span> <span class="type">&lt;Module&gt;</span>
{
    <span class="reserved">static</span> <span class="type">&lt;Module&gt;</span>()
    {
        <span class="type">C1</span>.<span class="method">Init1</span>();
        <span class="type">C1</span>.<span class="method">Init2</span>();
        <span class="type">C2</span>.<span class="method">Init1</span>();
    }
}
</code></pre>
<p>1つの静的コンストラクターの中に単なるメソッド呼び出しが並べられているだけの状態になります。
したがって、以下のような性質があります。</p>
<ul>
<li>
トータルでの呼び出しコストは静的コンストラクターをたくさん並べるよりも軽い
<ul>
<li>(静的コンストラクターは「<a href="https://ufcpp.net/study/csharp/sp_thread.html">マルチスレッド</a>実行時でも1回限り呼ぶ」という処理が必要で、通常のメソッド呼び出しよりも少し負担が大きい。モジュール初期化子はその負担が1回だけで済む)</li>
</ul>
</li>
<li>(意図せずコードを残してしまうと)本当は不要であっても必ず呼ばれる</li>
<li>呼び出しの負荷がモジュール読み込み時に集中する</li>
</ul>
<h3><a id="module-initialize-usage">モジュール初期化子の用途</a></h3>
<p>.NET 6.0 では iOS や <a href="https://ja.wikipedia.org/wiki/WebAssembly">WebAssembly</a> 上での実行のサポートが入ります。
(iOS や WebAssembly 上で C# が動くという状況はもっと前からあったんですが、
Windows で動いていた .NET とは別系統で保守されていました。
それが、 .NET 6.0 で統合されて1つの「.NET」になりました。)</p>
<p>用途が増えると、これまでの用途では動いていたものが新しい用途では動かせない・動いても効率が悪いということがあります。
実際、iOS や WebAssembly 環境では<a href="https://ufcpp.net/study/csharp/sp_reflection.html">リフレクション</a>を使いづらいです。</p>
<p>例えば以下のように、文字列で型名を指定して、その型のインスタンスを生成するということを考えてみます。
(こういうコードをそのまま書くことはないですが、JSON などにシリアライズ・デシリアライズしたりするときにこれに類する処理が内部的に行われたりします。)</p>
<pre class="source" title="文字列で型名を指定してインスタンス生成">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Reflection;
 
<span class="comment">// リフレクションを使えば文字列からその名前の型のインスタンスを作れる。</span>
<span class="comment">// ただ、パフォーマンスはあんまりよくない。</span>
<span class="reserved">object</span>? <span class="method">CreateInstance</span>(<span class="reserved">string</span> <span class="variable">typeName</span>)
{
    <span class="control">if</span> (<span class="type">Assembly</span>.<span class="method">GetExecutingAssembly</span>().<span class="method">GetType</span>(<span class="variable">typeName</span>) <span class="reserved">is</span> { } t) <span class="control">return</span> <span class="type">Activator</span>.<span class="method">CreateInstance</span>(<span class="variable">t</span>);
    <span class="control">else</span> <span class="control">return</span> <span class="reserved">null</span>;
}
 
<span class="comment">// ただ、 &quot;A&quot;, &quot;B&quot; という文字列が型名を指しているかどうかはコンパイラーが関知することではなく、</span>
<span class="comment">// 「クラス A, B は誰も使っていない」誤判定を受けることがある。</span>
<span class="comment">// AOT (事前ネイティブコード化)実行環境だと A, B が消し去られて、上記 GetType に失敗しうる。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">CreateInstance</span>(<span class="string">&quot;A&quot;</span>));
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">CreateInstance</span>(<span class="string">&quot;B&quot;</span>));
 
<span class="reserved">class</span> <span class="type">A</span>
{
}
 
<span class="reserved">class</span> <span class="type">B</span>
{
}
</code></pre>
<p>このコードは直接的にクラス <code>A</code>、<code>B</code> を使っているコードがどこにもありません。
かなり頑張ってコードを追えば、<code>&quot;A&quot;</code> という文字列が <code>A</code> というクラスを指していて、
それをリフレクション(<code>Activator.CreateInstance</code>)越しに使っていることがわからなくはないんですが、コンパイラーが機械的に判定すると「<code>A</code> も <code>B</code> も使われていない」という判定を受けます。</p>
<p>一方で、C# 9.0 の世代では <a href="https://ufcpp.net/study/csharp/misc/analyzer-generator/">source generator</a> (ソースコード生成)の仕組みが導入されました。
source generator 導入の動機の1つに「これまでリフレクションでやっていたような処理をコンパイル時にやりたい」というものがあります。
先ほどの <code>Activator.CreateInstance</code> を使っていた処理も、source generator を使って、「最初に1回どこかで初期化処理をする」みたいなものに置き換えることが考えられます。
例えば、以下のように、<code>CreateInstance</code> 的な処理を自前管理することを考えます。</p>
<pre class="source" title="リフレクションをなくすために、自前で CreateInstance 的なものを管理">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
 
<span class="comment">// どこか必ず1回呼ばれる保証のあるものを使って、事前に string → Func&lt;object&gt; な辞書を作っておくという発想。</span>
<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">TypeRepository</span>
{
    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">readonly</span> <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="type">Func</span>&lt;<span class="reserved">object</span>&gt;&gt; _factories = <span class="reserved">new</span>();
 
    <span class="comment">// 型名からインスタンスを作る。Register がどこかで呼ばれる前提。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">object</span>? <span class="method">CreateInstance</span>(<span class="reserved">string</span> <span class="variable">typeName</span>) =&gt; _factories.<span class="method">TryGetValue</span>(<span class="variable">typeName</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">f</span>) ? <span class="variable">f</span>() : <span class="reserved">null</span>;
 
    <span class="comment">// 型名 → インスタンス生成デリゲートを登録。</span>
    <span class="comment">// 静的コンストラクターで呼んでもらう想定だと破綻気味だったけど、モジュール初期化子なら割と成立する。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Register</span>(<span class="reserved">string</span> <span class="variable">typeName</span>, <span class="type">Func</span>&lt;<span class="reserved">object</span>&gt; <span class="variable">factory</span>) =&gt; _factories.<span class="method">Add</span>(<span class="variable">typeName</span>, <span class="variable">factory</span>);
}

</code></pre>
<p>ここで静的コンストラクターだと「呼ばれる保証がない」という点が問題になります。
例えば以下のコードのように変な挙動をしたりします。</p>
<pre class="source" title="静的コンストラクターだと呼ばれないことがあるので困る例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
 
<span class="comment">// 後述するように、静的コンストラクターはこの用途だと呼ばれない。</span>
<span class="comment">// なので、Register が呼ばれてなくて、CreateInstance が null を返す。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="type">TypeRepository</span>.<span class="method">CreateInstance</span>(<span class="string">&quot;A&quot;</span>)); <span class="comment">// null</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="type">TypeRepository</span>.<span class="method">CreateInstance</span>(<span class="string">&quot;B&quot;</span>)); <span class="comment">// null</span>
 
<span class="comment">// これが例えば、どこでもいいから1度 A のメンバーを空呼びすると上記コードがちゃんと new A(), new B() を返すようになる。</span>
<span class="comment">// 静的コンストラクターが呼ばれるタイミングは「その型のメンバーを最初に使った直後」</span>
<span class="reserved">_</span> = <span class="reserved">new</span> <span class="type">A</span>(); <span class="comment">// このタイミングで A の静的コンストラクターが呼ばれる</span>
<span class="reserved">_</span> = <span class="reserved">new</span> <span class="type">B</span>(); <span class="comment">// このタイミングで B の静的コンストラクターが呼ばれる</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="type">TypeRepository</span>.<span class="method">CreateInstance</span>(<span class="string">&quot;A&quot;</span>)); <span class="comment">// A</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="type">TypeRepository</span>.<span class="method">CreateInstance</span>(<span class="string">&quot;B&quot;</span>)); <span class="comment">// B</span>
 
<span class="comment">// 手書きはあまりしたくないものの、Source Generator がある今、</span>
<span class="comment">// 必要な型に対して以下のようなコード生成をするのは十分現実的。</span>
<span class="comment">// ただ、静的コンストラクターは呼ばれるタイミングに問題があって…</span>
<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">static</span> <span class="type">A</span>() =&gt; <span class="type">TypeRepository</span>.<span class="method">Register</span>(<span class="reserved">nameof</span>(<span class="type">A</span>), () =&gt; <span class="reserved">new</span> <span class="type">A</span>());
}
 
<span class="reserved">class</span> <span class="type">B</span>
{
    <span class="reserved">static</span> <span class="type">B</span>() =&gt; <span class="type">TypeRepository</span>.<span class="method">Register</span>(<span class="reserved">nameof</span>(<span class="type">B</span>), () =&gt; <span class="reserved">new</span> <span class="type">B</span>());
}
</code></pre>
<p>モジュール初期化子なら確実に呼ばれる保証が強いのでこの問題を解決できます。
以下のコードであれば意図した挙動になります。</p>
<pre class="source" title="モジュール初期化子なら呼び出される保証が強いので楽という例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.CompilerServices;
 
<span class="comment">// モジュール初期化子の場合、その型を含むモジュール(dll とか exe とか)がロードされた直後に必ず呼ばれる。</span>
<span class="comment">// 静的コンストラクターの「型に触れた瞬間」よりは確実に呼ばれる保証あり。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="type">TypeRepository</span>.<span class="method">CreateInstance</span>(<span class="string">&quot;A&quot;</span>)); <span class="comment">// A</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="type">TypeRepository</span>.<span class="method">CreateInstance</span>(<span class="string">&quot;B&quot;</span>)); <span class="comment">// B</span>
 
<span class="comment">// 静的コンストラクターだと呼ばれるタイミングが不定で問題があったけど、モジュール初期化子なら大丈夫。</span>
<span class="reserved">class</span> <span class="type">A</span>
{
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init</span>() =&gt; <span class="type">TypeRepository</span>.<span class="method">Register</span>(<span class="reserved">nameof</span>(<span class="type">A</span>), () =&gt; <span class="reserved">new</span> <span class="type">A</span>());
}
 
<span class="reserved">class</span> <span class="type">B</span>
{
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init</span>() =&gt; <span class="type">TypeRepository</span>.<span class="method">Register</span>(<span class="reserved">nameof</span>(<span class="type">B</span>), () =&gt; <span class="reserved">new</span> <span class="type">B</span>());
}
</code></pre>
<h2><a id ="generics">ジェネリックな型</h2>
<p>逆に静的コンストラクターでないと書けないものもあります。
ジェネリックな型に対してはモジュール初期化子を定義できません。</p>
<pre class="source" title="ジェネリックな型に対するモジュール初期化はコンパイル エラーになる">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Generic</span>&lt;<span class="type">T</span>&gt;
{
    <span class="comment">// これはコンパイル エラー。</span>
    <span class="comment">// 静的コンストラクターなら、 Generic&lt;int&gt; みたいな具象化した型ごとに呼ばれるけど、</span>
    <span class="comment">// モジュール初期化のタイミングでは何の型で具象化されるかわからなくて呼びようがない。</span>
    [<span class="error"><span class="type">ModuleInitializer</span></span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init1</span>() { }
}
</code></pre>
<p><a href="#module-initialize-usage">前節</a>で書いたような用途でモジュール初期化をジェネリック型に対して使いたい場合、
以下のように、非ジェネリックな型を1つ用意して、その中で想定しうるすべての型を列挙するなどの対処が必要になります。</p>
<pre class="source" title="非ジェネリックな型のモジュール初期化に初期化処理を集約する必要あり">
<code><span class="comment">// 前節のようなことをジェネリックな型に対してしようとすると…</span>
<span class="reserved">class</span> <span class="type">Generic</span>&lt;<span class="type">T</span>&gt;
{
}
 
<span class="comment">// 非ジェネリックなものを1個用意して、</span>
<span class="reserved">class</span> <span class="type">Generic</span>
{
    [<span class="type">ModuleInitializer</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Init</span>()
    {
        <span class="type">TypeRepository</span>.<span class="method">Register</span>(<span class="reserved">typeof</span>(<span class="type">Generic</span>&lt;&gt;) + <span class="string">&quot;&lt;int&gt;&quot;</span>, () =&gt; <span class="reserved">new</span> <span class="type">Generic</span>&lt;<span class="reserved">int</span>&gt;());
        <span class="type">TypeRepository</span>.<span class="method">Register</span>(<span class="reserved">typeof</span>(<span class="type">Generic</span>&lt;&gt;) + <span class="string">&quot;&lt;string&gt;&quot;</span>, () =&gt; <span class="reserved">new</span> <span class="type">Generic</span>&lt;<span class="reserved">string</span>&gt;());
        <span class="comment">// 以下、使うことがわかっている限りの具象型を並べる必要がある。</span>
    }
}
</code></pre> ]]></description>
				<pubDate>Sun, 21 Feb 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>コード解析とコード生成</title>
				<link>http://www.ufcpp.net/study/csharp/misc/analyzer-generator/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>C# コンパイラーなどを含むいわゆる「開発ツール」にとって重要なことは開発者の生産性を高めることです。
開発ツールが発展してきた現在、コンパイラーの仕事は多岐にわたります。
例えば、以下のようなことをしたいという要求があったりします。</p>
<ul>
<li>コード解析 (analyzer): 人的ミスを生みそうなコードははじく。場合によってはその修正方法も提示する(fixer)</li>
<li>コード生成 (generator): ボイラープレートになりがちなコードを手短に書けるようにする</li>
</ul>
<p>C# コンパイラー自身が様々なコード解析を提供していますし、
ボイラープレートを避けるために追加された文法もたくさんあります。
一方で、コード解析やコード生成には C# の正規の文法としては入れにくいものもあり、
第3者の作ったプラグインとして機能提供される場合も多いです。
現在の C# コンパイラーは公式にそういうプラグインを組み込むための仕組みを持っています。</p>
<p>文脈的にわかる場合には単に analyzer、generator と呼ばれます。
generator に関しては「ソースコードを生成する」ということを明示して source generator と呼ぶことが多いです。
文脈的にわかりにくい場合には、<a href="https://github.com/dotnet/roslyn">C# コンパイラーのコードネーム</a>を足して、roslyn analyzer、roslyn source generator と呼んだりします。</p>
<p>積みタスク: <a href="https://github.com/ufcpp/UfcppSample/issues/320">issues/320</a></p>
<h2><a id="analyzer">コード解析(analyzer)とコード生成(generator)</h2>
<p>C# コンパイラーは現在(というかそれぞれ C# 6.0 世代と C# 9.0 世代で)、コード解析とコード生成のプラグインを書けるようになりました。
コード解析(analyzer)については C# 6.0 のときにも1ページ利用例を書きました: 「<a href="https://ufcpp.net/study/csharp/package/pkgcodeawarelibrary/">Code-Awareなライブラリ</a>」。</p>
<p>C# チームや .NET チームが公式に提供する機能としても、今はコンパイラーの内部に実装するよりも、プラグインとして実装するものが増えています。
例えば、以下のコードを書いたとします。</p>
<pre class="source" title="C# の文法としては問題ないものの、修正したくなるコード">
<code><span class="reserved">class</span> <span class="type">C</span>
{
    <span class="reserved">int</span> x;
}
</code></pre>
<p>C# の文法上は特に問題のない書き方なんですが、推奨されているコーディング規約としては、<a href="https://ufcpp.net/study/csharp/oo_conceal.html#level">アクセシビリティ</a>を明示(<code>private</code> 修飾子を付けた方がいい)と言うことになっています。
こういう、「文法としては間違っていないけども、規約的には推奨されていない」みたいなものに対する情報はプラグインとして提供されていたりします。</p>
<p>上記のコードを Visual Studio で書いていると、以下のように、非推奨である旨が表示されて、修正案を提示してもらえます。</p>
<p><img src="/media/1182/addaccessibilitymodifiers.png" alt="private 修飾子を付けた方がいいという情報を出してくれる" /></p>
<p>これはコード解析プラグインとして実装されています。</p>
<p>コード生成(generator)はまだ実装されて間もない(C# 9.0 世代での追加)ので実例は少ないですが、今後は公式提供される generator が増えていくと思われます。</p>
<h2><a id="syntax-vs-plugin">文法化 VS プラグイン</h2>
<p><a href="https://ufcpp.net/blog/2016/12/tipsgeneratedil/">昔ブログに書いたことはあるんですが</a>、C# は構文糖衣が多い言語です。
構文糖衣(syntax sugar)というのは、「煩雑でもよければ等価なコードを別の文法で書けるものの、簡潔に書くために導入された文法」みたいなものです。</p>
<p>例えば、<a href="https://ufcpp.net/study/csharp/sp3_linq.html#query">クエリ式</a>がわかりやすい例ですが、以下のコードの <code>a</code>、<code>b</code>、<code>c</code> の3行は全く同じ意味のコードになります。</p>
<pre class="source" title="クエリ式の展開結果">
<code><span class="reserved">using</span> System.Linq;
 
<span class="reserved">var</span> <span class="variable">data</span> = <span class="reserved">new</span>[] { 1, 2, 3, 4 };
 
<span class="reserved">var</span> <span class="variable">a</span> =
    <span class="reserved">from</span> x <span class="reserved">in</span> <span class="variable">data</span>
    <span class="reserved">where</span> x &gt; 2
    <span class="reserved">select</span> x * x;
 
<span class="reserved">var</span> <span class="variable">b</span> = <span class="variable">data</span>
    .<span class="method">Where</span>(<span class="variable">x</span> =&gt; <span class="variable">x</span> &gt; 2)
    .<span class="method">Select</span>(<span class="variable">x</span> =&gt; <span class="variable">x</span> * <span class="variable">x</span>);
 
<span class="reserved">var</span> <span class="variable">c</span> = <span class="type">Enumerable</span>.<span class="method">Select</span>(
    <span class="type">Enumerable</span>.<span class="method">Where</span>(<span class="variable">data</span>, <span class="variable">x</span> =&gt; <span class="variable">x</span> &gt; 2),
    <span class="variable">x</span> =&gt; <span class="variable">x</span> * <span class="variable">x</span>);
</code></pre>
<p><code>a</code>の行と<code>b</code>の行のどちらが読みやすいかは好みの問題になったりしますが、<code>c</code>の行は少し読みにくいと思います。
<a href="https://ufcpp.net/study/csharp/sp3_linq.html#query">クエリ式</a>や<a href="https://ufcpp.net/study/csharp/sp3_extension.html?key=exmethod#exmethod">拡張メソッド</a>はこういう、原理的には他の書き方もできるけど、書きやすさのために使う構文糖衣です。</p>
<p>この手の構文糖衣はある意味、C# コードから別の C# コードを生成しているようなもので、
冒頭で説明したコード生成(generator)の公式提供版と言えます。</p>
<p>この辺りの機能は、ある程度の汎用的であると認定されたからこそ C# の文法として正式に採用されましたが、一方で、用途が狭く、言語機能としては採用しにくいようなコード生成もあります。
要望としてよくあるものとしては <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.componentmodel.inotifypropertychanged?WT.mc_id=DT-MVP-4028921"><code>PropertyChanged</code></a> の実装が煩雑で面倒なので専用の文法が欲しいと言われたりします。</p>
<p>例えば、以下のようなコードを書きたい場面があるわけですが、</p>
<pre class="source" title="PropertyChanged の実装">
<code><span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.ComponentModel;
<span class="reserved">using</span> System.Runtime.CompilerServices;
 
<span class="reserved">class</span> <span class="type">C</span> : <span class="type">INotifyPropertyChanged</span>
{
    <span class="reserved">public</span> <span class="reserved">event</span> <span class="type">PropertyChangedEventHandler</span>? PropertyChanged;
    <span class="reserved">protected</span> <span class="reserved">void</span> <span class="method">OnPropertyChanged</span>(<span class="type">PropertyChangedEventArgs</span> <span class="variable">args</span>)
        =&gt; PropertyChanged?.<span class="method">Invoke</span>(<span class="reserved">this</span>, <span class="variable">args</span>);
    <span class="reserved">protected</span> <span class="reserved">void</span> <span class="method">SetValue</span>&lt;<span class="type">T</span>&gt;(<span class="reserved">ref</span> <span class="type">T</span> <span class="variable">store</span>, <span class="type">T</span> <span class="variable">value</span>, [<span class="type">CallerMemberName</span>] <span class="reserved">string</span>? <span class="variable">propertyName</span> = <span class="reserved">null</span>)
    {
        <span class="control">if</span> (!<span class="type">EqualityComparer</span>&lt;<span class="type">T</span>&gt;.Default.<span class="method">Equals</span>(<span class="variable">store</span>, <span class="variable">value</span>))
        {
            <span class="variable">store</span> = <span class="variable">value</span>;
            <span class="method">OnPropertyChanged</span>(<span class="reserved">new</span>(<span class="variable">propertyName</span>));
        }
    }
 
    <span class="reserved">private</span> <span class="reserved">int</span> _x;
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span> =&gt; _x; <span class="reserved">set</span> =&gt; <span class="method">SetValue</span>(<span class="reserved">ref</span> _x, <span class="reserved">value</span>); }
}
 </code></pre>
<p>このコードのうち、実質的に意味を持っているのは「<code>X</code> プロパティを持っていて、それに <code>PropertyChanged</code> を実装したい」というだけです。
だったら、以下のような簡素なコードから複雑なコードを「コード生成」したいという話になります。</p>
<pre class="source" title="上記コードのうち意味のある部分(このコードを元にコード生成してほしい)">
<code><span class="reserved">class</span> <span class="type">C</span>
{
    [<span class="type">AutoNotify</span>] <span class="comment">// 一例。こういう属性が欲しいという話。</span>
    <span class="reserved">private</span> <span class="reserved">int</span> _x;
}
</code></pre>
<p>本当に限られた場面でですが、その場面に行き当たった人にとっては非常に欲しくなる機能です。</p>
<p>こういう場合に使うのがコード生成(generator)です。
上記の <code>PropertyChanged</code> に関して、
C# チームとしては、C# の言語機能を追加するつもりはないそうですが、
generator のサンプルを提供しています。</p>
<ul>
<li><a href="https://github.com/dotnet/roslyn-sdk/blob/master/samples/CSharp/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.cs">AutoNotifyGenerator</a></li>
</ul>
<p>この generator を使うと、上記の <code>AutoNotify</code> 属性付きのフィールドから以下のようなソースコードを生成します。</p>
<pre class="source" title="上記のコードからの自動生成物">
<code><span class="reserved">public</span> <span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">C</span> : System.ComponentModel.<span class="type">INotifyPropertyChanged</span>
{
    <span class="reserved">public</span> <span class="reserved">event</span> System.ComponentModel.<span class="type">PropertyChangedEventHandler</span> PropertyChanged;
    <span class="reserved">public</span> <span class="reserved">int</span> X
    {
        <span class="reserved">get</span>
        {
            <span class="control">return</span> <span class="reserved">this</span>._x;
        }
 
        <span class="reserved">set</span>
        {
            <span class="reserved">this</span>._x = <span class="reserved">value</span>;
            <span class="reserved">this</span>.PropertyChanged?.<span class="method">Invoke</span>(<span class="reserved">this</span>, <span class="reserved">new</span> System.ComponentModel.<span class="type">PropertyChangedEventArgs</span>(<span class="reserved">nameof</span>(X)));
        }
    }
}
</code></pre>
<h2><a id="tool-vs-plugin">外部ツール VS プラグイン</h2>
<p>こういうソースコードの生成は、以前でも、外部ツールを書けば(ソースコードを C# コンパイラーでコンパイルする前に、自前のツールを通してソースコードを書き換えるとかすることは)可能でした。
コンパイラーの関知しない場所での書き換えだと以下のような問題があります。</p>
<ul>
<li>どこで何のツールによって生成されたソースコードなのかを調べるのが難しくなることがある</li>
<li>生成結果が正しいかどうか、リアルタイムに追うことができない</li>
</ul>
<p>特に後者は C# にとって重要です。
<a href="https://visualstudio.microsoft.com/">Visual Studio</a> や <a href="https://code.visualstudio.com/">Visual Studio Code</a> などの開発環境を使っていると、
C# では、書いたところからリアルタイムにコンパイルが掛かって、エラーや警告をリアルタイムに知ることができます。</p>
<p>例えば以下のようなコードを書いたとします。</p>
<pre class="source" title="警告が出るソースコードの例">
<code><span class="reserved">using</span> System;
<span class="reserved">var</span> <span class="variable">x</span> = 1;
<span class="reserved">var</span> <span class="warning"><span class="variable">y</span></span> = 2;
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span>);
</code></pre>
<p>変数 <code>y</code> が未使用(何の役にも立っていない)のでミスの可能性が高いコードです。
そこで、C# コンパイラーはこの役に立たないコードに対して警告を出してくれるんですが、
Visual Studio 上では書いた瞬間から警告が出ますし、
<code>y</code> を使用するコードを足せば即座に警告が消えます。
また、未使用変数を消してくれる自動修正(code fix)機能も提供してくれています。</p>
<p><img src="/media/1181/realtimecompilation.png" alt="リアルタイムにエラーや警告が見れる例" /></p>
<p>こういうリアルタイムなコンパイルをするためにも、外部ツールではなく、コンパイラーのプラグイン機能が必要になります。</p>
<p>コード生成(generator)による生成物も、以下の動画のように、Visual Studio 上では手書きの C# コードと遜色ない扱いを受けることができます。</p>
<div>
<iframe width="560" height="315" src="https://www.youtube.com/embed/vIYGnhi3DOk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
<p>以下の機能が使えます。</p>
<ul>
<li>生成物を Solution Explorer で確認</li>
<li>F12 で生成物にジャンプ</li>
<li>F9 でブレイクポイントを設置</li>
<li>F11 でステップイン実行</li>
</ul>
<h2><a id="usage">コード解析・コード生成の利用</h2>
<p>C# 6.0 世代でコード解析(analyzer)を、C# 9.0 世代でコード生成(generator)を書けるようになったといっても、ほとんどの C# 開発者にとってこれらは「自分で書く物」ではなく、「人が書いたものを利用するだけ」になると思います。</p>
<p>C#/.NET チームによる公式提供のものは .NET SDK や Visual Studio に最初から組み込まれていて、意識せずに使うことになります。
(<a href="#analyzer">前節</a>で紹介したアクセシビリティの追加などがその代表例です。)</p>
<p>一方で、プラグインなので、公式提供されなさそうな狭い用途のものも、第3者が作って公開していたりします。
利用するだけであれば、これらコード解析・コード生成プラグインは <a href="https://www.nuget.org/">NuGet</a> パッケージ参照するだけです。</p>
<p>例として、筆者の自作のコード解析・コード生成を参照してみます。</p>
<p>サンプルコード: <a href="https://github.com/ufcpp/UfcppSample/tree/master/Demo/2021/AnalyzerPackageReference">AnalyzerPackageReference</a></p>
<p>コード解析の例として<a href="https://github.com/ufcpp/NonCopyableAnalyzer">NonCopyableAnalyzer</a>を、コード生成の例として<a href="https://github.com/ufcpp/StringLiteralGenerator">StringLiteralGenerator</a>を使います。</p>
<p>簡単に説明しておくと、まず、NonCopyableAnalyzerは<a href="https://ufcpp.net/study/csharp/resource/rm_struct/">構造体</a>のコピーを禁止するコード解析です。
構造体はコピーが発生してしまうとまずい場面があるんですが、
通常は「コピーされてまずいなら構造体を使うな」という方針にすることが多いです。
ただ、パフォーマンス的にどうしても構造体にした上でコピーを禁止したいという場面がまれにあって、そういう場合に使います。</p>
<pre class="source" title="構造体のコピーを禁止">
<code><span class="comment">// NonCopyableAnalyzer の機能:</span>
<span class="type">S</span> <span class="variable">s1</span> = <span class="reserved">new</span>();
<span class="type">S</span> <span class="variable">s2</span> = <span class="error"><span class="variable">s1</span></span>; <span class="comment">// 構造体の代入(コピー)を禁止する</span>
 
[<span class="type">NonCopyable</span>]
<span class="reserved">struct</span> <span class="type">S</span> { }
</code></pre>
<p>StringLiteralGenerator は C# の通常の<a href="https://ufcpp.net/study/csharp/st_embeddedtype.html#stringl">文字列リテラル</a>から UTF-8 のバイト列を生成するものです。
例えば以下のようなコードを書いて、</p>
<pre class="source" title="UTF-8 バイト列の生成元の例">
<code><span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Literal</span>
{
    [<span class="type">Utf8</span>(<span class="string">&quot;aあ</span><span style="color:#b776fb;">😀</span><span class="string">&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> <span class="type">ReadOnlySpan</span>&lt;<span class="reserved">byte</span>&gt; <span class="method">M</span>();
}
</code></pre>
<p>以下のようなコードを自動生成します。</p>
<pre class="source" title="UTF-8 バイト列の生成結果の例">
<code><span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">Literal</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">partial</span> System.ReadOnlySpan&lt;<span class="reserved">byte</span>&gt; <span class="method">M</span>() =&gt; <span class="reserved">new</span> <span class="reserved">byte</span>[] {97, 227, 129, 130, 240, 159, 152, 128, };
}
</code></pre>
<p>どちらも読みやすさや書きやすさよりもパフォーマンスを最優先したい場合に限って使えるもので、あまり汎用に使えるものではありません。
汎用的でないからこそプラグインに向いているものです。</p>
<p><a href="https://github.com/ufcpp/UfcppSample/blob/master/Demo/2021/AnalyzerPackageReference/AnalyzerPackageReference/AnalyzerPackageReference.csproj#L8-L11">以下のようなパッケージ参照</a>をすることでこれらのプラグインを追加できます。</p>
<pre class="xsource" title="パッケージ参照の例(csproj 内に以下の行を追加)">
<code><span class="attvalue">  &lt;</span><span class="element">ItemGroup</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">PackageReference</span><span class="attvalue"> </span><span class="attribute">Include</span><span class="attvalue">=</span>&quot;<span class="attvalue">NonCopyableAnalyzer</span>&quot;<span class="attvalue"> </span><span class="attribute">Version</span><span class="attvalue">=</span>&quot;<span class="attvalue">0.6.0</span>&quot;<span class="attvalue"> /&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">PackageReference</span><span class="attvalue"> </span><span class="attribute">Include</span><span class="attvalue">=</span>&quot;<span class="attvalue">StringLiteralGenerator</span>&quot;<span class="attvalue"> </span><span class="attribute">Version</span><span class="attvalue">=</span>&quot;<span class="attvalue">1.0.1</span>&quot;<span class="attvalue"> /&gt;</span>
<span class="attvalue">  &lt;/</span><span class="element">ItemGroup</span><span class="attvalue">&gt;</span>
</code></pre>
<h2><a id="empty-body">括弧の省略</a></h2>
<h5 class="version version12">Ver. 12</h5>
<p>C# 12 から、<code>class A;</code> というように、クラスの本体の <code>{}</code> を省略できるようになりました。
(<a href="https://ufcpp.net/study/csharp/cheatsheet/ap_ver12/#primary-constructor">プライマリ コンストラクター</a>導入のついでで実装された機能です。)
コード生成とは相性のいい機能なのでここで少しだけ触れておきます。</p>
<p>コード生成や<a href="https://ufcpp.net/study/csharp/sp_reflection.html#reflection">リフレクション</a>に頼るコードでは、
「属性だけつけてクラスの中身は空っぽ」ということが割とよく起きます。</p>
<p>一例が <code>System.Text.Json</code> なんですが、
以下のように、<a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.text.json.serialization.jsonserializableattribute"><code>JsonSerializable</code> 属性</a>を使ったコード生成をします。</p>
<pre class="source" title="コード生成だよりで中身空っぽのクラスの例">
<span class="reserved">using</span> System<span class="operator">.</span>Text<span class="operator">.</span>Json<span class="operator">.</span>Serialization;

<span class="comment">// JsonSerializable 属性を付けていると、シリアライズ処理に必要なメンバーをコード生成する。</span>
[<span class="type">JsonSerializable</span>(<span class="reserved">typeof</span>(<span class="type">Person</span>))]
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">MyJsonContext</span> : <span class="type">JsonSerializerContext</span>
{
    <span class="comment">// 手書きでは何もする必要がないので空っぽ。</span>
}

<span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable local">FirstName</span>, <span class="reserved">string</span> <span class="variable local">LastName</span>);
</pre>
<p>ここで <code>{}</code> の省略が使えます。
たかだか2行、1文字の差ですが、以下のように書けるようになります。</p>
<pre class="source" title="中身空っぽなら ; を使おうという例">
<span class="reserved">using</span> System<span class="operator">.</span>Text<span class="operator">.</span>Json<span class="operator">.</span>Serialization;

<span class="comment">// JsonSerializable 属性を付けていると、シリアライズ処理に必要なメンバーをコード生成する。</span>
[<span class="type">JsonSerializable</span>(<span class="reserved">typeof</span>(<span class="type">Person</span>))]
<span class="reserved">partial</span> <span class="reserved">class</span> <span class="type">MyJsonContext</span> : <span class="type">JsonSerializerContext</span>;

<span class="reserved">record</span> <span class="type">Person</span>(<span class="reserved">string</span> <span class="variable local">FirstName</span>, <span class="reserved">string</span> <span class="variable local">LastName</span>);
</pre> ]]></description>
				<pubDate>Sat, 06 Feb 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] 型の決定</title>
				<link>http://www.ufcpp.net/study/csharp/start/misctyperesolution/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>C# の<a href="/study/csharp/st_variable.html#variable">変数</a>や<a href="/study/csharp/st_variable.html#expression">式</a>はそれぞれが「型」を持っています。
例えば <code>int x;</code> として宣言した変数 <code>x</code> は <code>int</code> 型になりますし、<code>&quot;abc&quot;</code> という式(文字列<a href="/study/csharp/st_variable.html#literal">リテラル</a>も式の一種)は <code>string</code> 型になります。</p>
<p>そして、代入(<code>=</code>)などの処理では、左右両辺の型が一致しないとコンパイル時にエラーを起こします。
例えば以下のコードはコンパイルできません。</p>
<pre class="source" title="型の不一致でのコンパイル エラー">
<code><span class="reserved">int</span> <span class="variable">x</span> = <span class="error"><span class="string">&quot;abc&quot;</span></span>;
</code></pre> 
<p>どうせ左右で型を合わせる必要があるわけで、片方からもう片方の型を自動決定する構文もいくつかあります。
<a href="/study/csharp/sp3_inference.html#type-inference">ローカル変数の型推論(<code>var</code> 変数宣言)</a>が代表例で、
例えば以下のような書き方をすると、「右辺の型に合わせて <code>x</code> の型が自動的に <code>string</code> になる」という挙動になります。</p>
<pre class="source" title="ローカル変数の型推論">
<code><span class="reserved">var</span> <span class="variable">x</span> = <span class="string">&quot;abc&quot;</span>;
</code></pre>
<p>逆に、反対側の辺を見ないと型が決定できないようなものもいくつかあります。
<a href="/study/csharp/sp_delegate.html">デリゲート</a>や<a href="/study/csharp/functional/fun_localfunctions/#anonymous-function">匿名関数</a>が代表例で、
例えば以下のコードは「型が決定できなくてコンパイル エラー」になります。</p>
<pre class="source" title="左辺の型が必須な構文">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="error"><span class="variable">m</span> = Main</span>;
        <span class="reserved">var</span> <span class="error"><span class="variable">f</span> = () =&gt; { }</span>;
 
        <span class="comment">// 以下の書き方ならコンパイル可能。左辺の型が必須。</span>
        <span class="type">Action</span> <span class="variable">m1</span> = <span class="method">Main</span>;
        <span class="type">Action</span> <span class="variable">f1</span> = () =&gt; { };
    }
}
</code></pre>
<p>本項では、こういった「型の決定」について説明していきます。</p>
<h2><a id="source-target">型決定の「向き」</h2>
<p>型の決定には「向き」があります。
概要で話した通り、型決定の代表例は代入処理で、<code>=</code> 演算子の左右を指して「左辺」(left hand side)、「右辺」(right hand side)と言ったりします。
ただ、同様の型決定は、必ずしも「左右」になっていない構文でも発生します。
例えば、メソッド呼び出し(<a href="/study/csharp/structured/miscoverloadresolution/">オーバーロード解決</a>)の場合は「左右」というよりは「内外」といった方がいいかもしれません。</p>
<pre class="source" title="型決定の「左右」、「内外」">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// 右辺の &quot;abc&quot; から左辺の s の型が string に決定。</span>
        <span class="reserved">var</span> <span class="variable">s</span> = <span class="string">&quot;abc&quot;</span>;
 
        <span class="comment">// 内側の 1 から外側の X (の引数)の型が int に決定(X(int x) が呼ばれる)。</span>
        <span class="method">X</span>(1);
 
        <span class="comment">// 左辺の Action から右辺の () =&gt; { } の型が決定。</span>
        <span class="type">Action</span> <span class="variable">a</span> = () =&gt; { };
 
        <span class="comment">// 外側の Y (の引数の Action)から内側の () =&gt; { } の型が決定。</span>
        <span class="method">Y</span>(() =&gt; { });
    }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">X</span>(<span class="reserved">int</span> <span class="variable">x</span>) { }
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">X</span>(<span class="reserved">string</span> <span class="variable">x</span>) { }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Y</span>(<span class="type">Action</span> <span class="variable">a</span>) { }
}
</code></pre>
<p>どちらの場合でも、「値の出所」と「値を受け取る側」に分かれます。
そして、出所の方を<strong id="source-type" class="keyword">ソース型</strong>(source type)、受け取る側を<strong id="target-type" class="keyword">ターゲット型</strong>(target type)と言います。</p>
<table>
<thead>
<tr>
	<th>型の「向き」</th>
	<th>例</th>
</tr>
</thead>
<tbody>
<tr>
	<td>ソース</td>
	<td>代入の右辺、メソッド呼び出しの実引数</td>
</tr>
<tr>
	<td>ターゲット</td>
	<td>代入の左辺、メソッドの仮引数</td>
</tr>
</tbody>
</table>
<p>元々 C# ではソース型の方を明示的に指定して、ターゲット型の方を自動決定することが多いです。
なので、単に推論(inference)とか解決(resolution)という場合、この向き(ソース型からの決定)なことが多いです。</p>
<pre class="source" title="ソース型からの型決定">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// 変数の型推論(type inference)はソース型からの型決定</span>
        <span class="reserved">var</span> <span class="variable">s</span> = <span class="string">&quot;abc&quot;</span>;
 
        <span class="comment">// オーバーロード解決(overload resolution)はソース型からの型決定。</span>
        <span class="method">X</span>(1);
    }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">X</span>(<span class="reserved">int</span> <span class="variable">x</span>) { }
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">X</span>(<span class="reserved">string</span> <span class="variable">x</span>) { }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Y</span>(<span class="type">Action</span> <span class="variable">a</span>) { }
}
</code></pre>
<p>しかし徐々にターゲット型の方を明示的に指定する構文が増えています。
後入りな構文が多いせいか、こちらは「ターゲット型からの(target typed)」という形容をすることが多いです。
例えば C# 7.1 で入った <a href="/study/csharp/rm_default.html#default-expr"><code>default</code> 式</a>は「target typed default」などと呼ばれることがあります。
また、C# 8.0 で入った <a href="/study/csharp/datatype/typeswitch/?p=5#target-typed"><code>switch</code> 式はターゲットからの型決定</a>をしていますが、
こちらも「target typed switch」と言われたりします。</p>
<pre class="source" title="ターゲット型からの型決定">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">b</span>)
{
    <span class="comment">// 以前の C# では default(DateTime) と書く必要があった。</span>
    <span class="comment">// C# 7.1 から、ターゲットからの型推論で default だけで書けるようになった。</span>
    <span class="type">DateTime</span> <span class="variable">t</span> = <span class="reserved">default</span>;
 
    <span class="comment">// C# の型決定機構では「1 と null の共通型が何かわからない」ということでコンパイルできなかった。</span>
    <span class="comment">// switch 式ではターゲット型(この場合 int?)を見て、switch の型を決めて、1 と null を受け付けできるようにした。</span>
    <span class="reserved">int</span>? <span class="variable">x</span> = <span class="variable">b</span> <span class="control">switch</span>
    {
        <span class="reserved">true</span> =&gt; 1,
        <span class="reserved">false</span> =&gt; <span class="reserved">null</span>
    };
}
</code></pre>
<h5><a id="source-typed">ソース型からの決定</h5>
<p>ソース型によって挙動が決まる構文として以下のようなものがあります。</p>
<ul>
<li><a href="/study/csharp/sp3_inference.html#implicit">ローカル変数の型推論</a></li>
<li><a href="/study/csharp/sp3_inference.html#impl_array">配列の暗黙的型付け</a></li>
<li>
<a href="/study/csharp/structured/miscoverloadresolution/">オーバーロード解決</a>
<ul>
<li>特に、<a href="/study/csharp/sp2_generics.html#method">ジェネリック型引数の推論</a></li>
</ul>
</li>
</ul>
<h5><a id="source-typed">ターゲット型からの決定</h5>
<p>ターゲット型によって挙動が決まる構文として以下のようなものがあります。</p>
<p>単に「ターゲットを見るまで型が確定しない」程度のものもあります。
暗黙的型変換の一種として考えることができます(未確定の型から確定した型への変換)。</p>
<ul>
<li><a href="/study/csharp/st_embeddedtype.html#intl">整数リテラル</a></li>
<li><a href="/study/csharp/oo_class.html#null">null</a></li>
<li><a href="/study/csharp/rm_default.html#default-expr"><code>default</code> 式</a></li>
<li><a href="/study/csharp/oo_construct.html#target-typed-new"><code>new</code> 演算子</a></li>
<li><a href="/study/csharp/sp_delegate.html">デリゲート</a></li>
</ul>
<p>もう少し積極的にターゲット型の情報を使う構文もあります。</p>
<ul>
<li><a href="/study/csharp/datatype/typeswitch/?p=5#target-typed"><code>switch</code> 式</a></li>
<li><a href="/study/csharp/st_branch.html#terget-typed-conditional">条件演算子</a></li>
</ul>
<p>また、ターゲットの型によってまるっきり異なる挙動になるものもあります。</p>
<ul>
<li>
<a href="/study/csharp/st_string.html#string-interpolation">文字列補間</a>
<ul>
<li><a href="/study/csharp/st_string.html#FormattableString"><code>IFormattable</code> 型に渡すとき</a></li>
</ul>
</li>
<li>
<a href="/study/csharp/sp3_lambda.html">ラムダ式</a>
<ul>
<li><a href="/study/csharp/sp3_lambda.html#expression"><code>Expression</code> 型に渡すとき</a></li>
</ul>
</li>
</ul>
<p>ちなみに、組み合わせも行けます。
以下のように、<code>switch</code> 式中の条件演算子中の <code>new</code> みたいな入れ子になった状況でもターゲット型推論が働きます。</p>
<pre class="source" title="ターゲット型推論の入れ子">
<code><span class="reserved">using</span> System;
 
<span class="comment">// target-typed switch 式中の</span>
<span class="comment">// target-typed 条件演算子中の</span>
<span class="comment">// target-typed new 式。</span>
<span class="type">TimeSpan</span> <span class="method">X</span>(<span class="reserved">int</span> <span class="variable">i</span>, <span class="reserved">bool</span> <span class="variable">b</span>) =&gt; <span class="variable">i</span> <span class="control">switch</span>
{
    &lt; 0 =&gt; <span class="variable">b</span> ? <span class="reserved">new</span>(0) : <span class="reserved">new</span>(1),
    0 =&gt; <span class="variable">b</span> ? <span class="reserved">new</span>(2) : <span class="reserved">new</span>(6),
    &gt; 0 =&gt; <span class="variable">b</span> ? <span class="reserved">new</span>(4) : <span class="reserved">new</span>(5),
};
</code></pre>
<h2><a id="history">自動型決定の歴史</h2>
<p>ソース/ターゲットのいずれか一方だけの型を指定して他方を自動決定するというのは、
2000年代頃から増え始めたものです。
20世紀の(1990年代以前の)プログラミング言語では少数派でしたし、
C# でも、C# 2.0 や 3.0 から導入された構文が多いです。
例えば、C# 1.0 (2000年発表、2002年正式リリース)時代には以下のような書き方はできませんでした。</p>
<pre class="source" title="C# 1.0 時代">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
{
    <span class="comment">// C# 2.0 から。</span>
    <span class="comment">// C# 1.0 時代は Action m = new Action(Main); と書く必要あり。</span>
    <span class="type">Action</span> <span class="variable">m</span> = <span class="method">Main</span>;
 
    <span class="comment">// C# 3.0 から。</span>
    <span class="comment">// C# 1.0 時代は string s = &quot;abc&quot;; と書く必要あり。</span>
    <span class="reserved">var</span> <span class="variable">s</span> = <span class="string">&quot;abc&quot;</span>;
}
</code></pre>
<p>ただ、明確に型推論(type inference)という言葉が出始めたのは C# 3.0 の頃からですが、
それ以前でも、推論に類するものはありました。
例えばメソッドのオーバーロード解決は「ソース型からの型決定」に類するものですし、
整数リテラルや null などは実は「ターゲット型からの型決定」をしています
(正確に言うと「暗黙的型変換」なんですが、いずれにせよターゲット型が決まるまで解釈が確定しません)。</p>
<pre class="source" title="整数リテラルの型決定">
<code><span class="comment">// byte リテラルや short リテラルは存在していなくて、「整数リテラル」の暗黙的型変換で代用している。</span>
<span class="reserved">byte</span> <span class="variable">a</span> = 1;  <span class="comment">// この 1 は byte (に代入可能)</span>
<span class="reserved">short</span> <span class="variable">b</span> = 1; <span class="comment">// この 1 は short (に代入可能)</span>

<span class="comment">// 変数だと int から byte や short への暗黙的変換は認められていない。コンパイル エラーに。</span>
<span class="reserved">int</span> <span class="variable">i</span> = 1;
<span class="variable">a</span> = <span class="error"><span class="variable">i</span></span>;
 
<span class="comment">// ちゃんと精度チェックが入る。byte に代入できない大きさの整数リテラルはコンパイル エラーを起こす。</span>
<span class="variable">a</span> = <span class="error">256</span>;

<span class="comment">// ただし、var に対して使った時は int 扱い。</span>
<span class="reserved">var</span> <span class="variable">c</span> = 1; <span class="comment">// c の型は int</span>
 
<span class="comment">// 配列初期化子はターゲット型を見ているのでこの書き方は OK。</span>
<span class="reserved">byte</span>[] <span class="variable">d</span> = { 1, 2 }; <span class="comment">// この 1, 2 は byte 扱い</span>
 
<span class="comment">// でも、配列の型推論はソース型からの型決定なので NG。</span>
<span class="comment">// 右辺は int[] 扱いで、左辺の byte[] と型が合わなくてコンパイル エラーになる。</span>
<span class="reserved">byte</span>[] <span class="variable">e</span> = <span class="error"><span class="reserved">new</span>[] { 1, 2 }</span>;
</code></pre>
<h2><a id="conflict">自動型決定の競合</h2>
<p>ソースから型決定する構文とターゲットから型決定する構文は、当然ですが両立はできません。
どちらもあいまいでは型決定できません。片方は明示的な型指定が必要になります。</p>
<pre class="source" title="推論に推論は重ねられない">
<code><span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// OK。引数の側の型を明示。</span>
        <span class="method">X</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">a</span>);
 
        <span class="comment">// OK。メソッドの側の型を明示。</span>
        <span class="method">X</span>&lt;<span class="reserved">int</span>&gt;(<span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">b</span>);
 
        <span class="comment">// NG。(型引数の)推論と(ローカル変数の)推論が重なって型決定不可。</span>
        <span class="error">X</span>(<span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">c</span>);
    }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">X</span>&lt;<span class="type">T</span>&gt;(<span class="reserved">out</span> <span class="type">T</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> = <span class="reserved">default</span>;
}
</code></pre>
<p>ちなみに、型推論は「後から」競合を起こす原因になり得たりもします。
例えば以下のようなコードはコンパイルできるコードなんですが、</p>
<pre class="source" title="有効な型推論">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">DateTime</span>? x) { }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="method">M</span>(<span class="reserved">null</span>);
        <span class="method">M</span>(<span class="reserved">default</span>);
        <span class="method">M</span>(<span class="reserved">new</span>());
    }
}
</code></pre>
<p>ここに1行、オーバーロードを増やすとどちらを呼ぶべきか決定できなくてコンパイル エラーになります。</p>
<pre class="source" title="オーバーロードの追加が破壊的変更になり得る">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span>? x) { } <span class="comment">// この行を追加</span>
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">DateTime</span>? x) { }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="error">M</span>(<span class="reserved">null</span>);
        <span class="error">M</span>(<span class="reserved">default</span>);
        <span class="error">M</span>(<span class="reserved">new</span>());
    }
}
</code></pre>
<h2><a id="priority">優先度付きのターゲットからの型決定</h2>
<p>ターゲットの型を見て挙動が変わりはするものの、
未指定の場合の既定の挙動が決まっていて、ソース型からの型推論と競合しないものもあります。</p>
<p>整数リテラルなどがそうで、整数リテラルはターゲットの型によって挙動を変えますが、
型推論に対しては <code>int</code> 扱いになりますし、
オーバーロード解決では <code>int</code> が最優先になります。</p>
<pre class="source" title="整数リテラルの既定の型は int">
<code><span class="comment">// ターゲットの型を見ている。</span>
<span class="reserved">byte</span> <span class="variable">a</span> = 1;  <span class="comment">// この 1 は byte 扱い</span>
<span class="reserved">short</span> <span class="variable">b</span> = 1; <span class="comment">// この 1 は short 扱い</span>
 
<span class="comment">// ターゲット型が決まっていない場合は int になる。</span>
<span class="reserved">var</span> <span class="variable">c</span> = 1; <span class="comment">// 1 は int で、そこからの型推論で c の型は int</span>

<span class="reserved">void</span> <span class="method">f</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">x</span>) { }
<span class="method">f</span>(1); <span class="comment">// 型引数の推論でも int 扱い</span>
</code></pre>
<p><a href="/study/csharp/st_string.html#string-interpolation">文字列補間</a>にも優先度があります。
文字列補間は <code>IFormattable</code> 型よりも <code>string</code> が優先です。</p>
<pre class="source" title="文字列補間は IFormattable より string が優先">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">x</span>)
    {
        <span class="comment">// var に対して文字列補間を使うと string 扱い。</span>
        <span class="reserved">var</span> <span class="variable">s</span> = <span class="string">$&quot;abc </span>{<span class="variable">x</span>}<span class="string">&quot;</span>;
 
        <span class="comment">// M(string) が優先的に呼ばれる。</span>
        <span class="method">M</span>(<span class="string">$&quot;abc </span>{<span class="variable">x</span>}<span class="string">&quot;</span>);
 
        <span class="comment">// M(IFormattable) の方を呼びたければキャストが必要。</span>
        <span class="method">M</span>((<span class="type">IFormattable</span>)<span class="string">$&quot;abc </span>{<span class="variable">x</span>}<span class="string">&quot;</span>);
    }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">s</span>) { }
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">IFormattable</span> <span class="variable">s</span>) { }
}
</code></pre>
<h2><a id="cost">自動型決定のコスト</h2>
<p>ソースとターゲットのどちらか片方から他方を決定できるといっても、
その推論が低コストなものと、意外と高コストなものがあったりします。</p>
<p>例えば、ローカル変数の型推論はほとんどコストがかからないそうです。
なんせ左辺と右辺が1対1ですし、元々「型が合うかどうか」の判定のために左右どちらにも明確な型を求めています。
単に片方を他方に伝搬させるだけなので低コストです。</p>
<p>一方、オーバーロード解決は結構高コストです。
多数の候補の中から1つを選ばないといけないので単純に検索コストがかかります。
例えば、以下のようなコードでは <code>Parse(&quot;&quot;)</code> で呼び出せるメソッドの候補が4つあります。</p>
<pre class="source" title="複数の候補があるメソッド呼び出しの例">
<code><span class="comment">// この1行によって DateTime.Parse(string) がオーバーロード解決候補に入る。</span>
<span class="reserved">using</span> <span class="reserved">static</span> System.<span class="type">DateTime</span>;
 
<span class="reserved">class</span> <span class="type">Base</span>
{
    <span class="comment">// 基底クラスにも同名のメソッド。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Parse</span>(<span class="reserved">string</span> <span class="variable">x</span>) { }
}
 
<span class="reserved">class</span> <span class="type">Derived</span> : <span class="type">Base</span>
{
    <span class="comment">// Parse(&quot;&quot;) で呼び出せる候補が複数。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Parse</span>(<span class="reserved">object</span> <span class="variable">x</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Parse</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">x</span>) { }
 
    <span class="reserved">void</span> <span class="method">M</span>()
    {
        <span class="method">Parse</span>(<span class="string">&quot;abc&quot;</span>);
    }
}
</code></pre>
<p>オーバーロードの数や引数の数が多くなれば多くなるほど複雑になることは容易に想像できるかと思います。
標準ライブラリ中にも多数のオーバーロードを持つメソッドは多く、容易に複雑化します。
実は、C# ソースコードのコンパイル時間のうち数割程度はオーバーロード解決が占めているといわれています。</p>
<pre class="source" title="いかにも複雑そうなオーバーロード解決の例">
<code><span class="comment">// 以下の5つの Parse が候補に</span>
<span class="comment">// int Parse(ReadOnlySpan&lt;char&gt; s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)</span>
<span class="comment">// int Parse(string s)</span>
<span class="comment">// int Parse(string s, NumberStyles style)</span>
<span class="comment">// int Parse(string s, NumberStyles style, IFormatProvider provider)</span>
<span class="comment">// int Parse(string s, IFormatProvider provider)</span>
<span class="reserved">using</span> <span class="reserved">static</span> System.<span class="type">Int32</span>;
 
<span class="comment">// 以下の4つの Parse が候補に</span>
<span class="comment">// DateTime Parse(ReadOnlySpan&lt;char&gt; s, IFormatProvider provider = null, DateTimeStyles styles = DateTimeStyles.None)</span>
<span class="comment">// DateTime Parse(string s)</span>
<span class="comment">// DateTime Parse(string s, IFormatProvider provider)</span>
<span class="comment">// DateTime Parse(string s, IFormatProvider provider, DateTimeStyles styles)</span>
<span class="reserved">using</span> <span class="reserved">static</span> System.<span class="type">DateTime</span>;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// 2引数で、第2引数が NumberStyles なものは1個しかないので、</span>
        <span class="comment">// int Parse(string, NumberStyles)</span>
        <span class="method">Parse</span>(<span class="reserved">null</span>, System.Globalization.<span class="type">NumberStyles</span>.HexNumber);
 
        <span class="comment">// stackalloc によって第1引数の型が ReadOnlySpan&lt;char&gt; に決定</span>
        <span class="comment">// 第3引数が DateTimeStyles なので、</span>
        <span class="comment">// DateTime Parse(ReadOnlySpan&lt;char&gt;, IFormatProvider, DateTimeStyles)</span>
        <span class="method">Parse</span>(<span class="reserved">stackalloc</span> <span class="reserved">char</span>[0], <span class="reserved">null</span>, System.Globalization.<span class="type">DateTimeStyles</span>.None);
    }
}
</code></pre>
<p>ちなみに、C# は、ローカル変数に対しては型推論(<code>var</code> 変数宣言)を認めていますが、
メンバー(フィールド、プロパティやメソッド)の引数・戻り値に対しては認めていません。
これは、作法的な問題(メンバーの型は明示すべきという思想)もありますが、
簡単に高コストになりうるから認められないという問題もあるそうです。</p>
<pre class="source" title="メンバーの型推論は認めない">
<code><span class="comment">// 以下、仮定的な構文。C# では認めていない(おそらく今後も認めない)。</span>
 
<span class="comment">// 再帰しているので当然型決定が不可能。</span>
<span class="comment">// この例はまだ単純なものの、「再帰の検知」も十分複雑になりえる。</span>
<span class="reserved">static</span> <span class="reserved">var</span> a = b;
<span class="reserved">static</span> <span class="reserved">var</span> b = a;
 
<span class="comment">// ただでさえ複雑なオーバーロード解決と組み合わせると悲惨なことに…</span>
<span class="reserved">static</span> (<span class="type">T</span>, <span class="type">U</span>) <span class="method">M</span>&lt;<span class="type">T</span>, <span class="type">U</span>&gt;(<span class="type">T</span> <span class="variable">t</span>, <span class="type">U</span> <span class="variable">u</span>) =&gt; (<span class="variable">t</span>, <span class="variable">u</span>);
<span class="reserved">static</span> <span class="reserved">short</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">string</span> <span class="variable">y</span>) =&gt; 0;
<span class="reserved">static</span> <span class="reserved">float</span> <span class="method">M</span>(<span class="reserved">double</span> <span class="variable">x</span>, <span class="reserved">string</span> <span class="variable">y</span>) =&gt; 0;
 
<span class="reserved">static</span> <span class="reserved">var</span> <span class="method">A</span>() =&gt; M(<span class="method">B</span>(), <span class="method">C</span>());
<span class="reserved">static</span> <span class="reserved">var</span> <span class="method">B</span>() =&gt; M(<span class="method">D</span>(), <span class="method">E</span>());
<span class="reserved">static</span> <span class="reserved">var</span> <span class="method">C</span>() =&gt; M(<span class="method">F</span>(), <span class="string">&quot;&quot;</span>);
<span class="reserved">static</span> <span class="reserved">var</span> <span class="method">D</span>() =&gt; <span class="method">M</span>(1, 1.2);
<span class="reserved">static</span> <span class="reserved">var</span> <span class="method">E</span>() =&gt; <span class="method">M</span>(1, <span class="string">&quot;&quot;</span>);
<span class="reserved">static</span> <span class="reserved">var</span> <span class="method">F</span>() =&gt; <span class="method">M</span>(1.2, <span class="reserved">new</span> <span class="reserved">object</span>());
</code></pre>
<h2><a id="nest">入れ子</h2>
<p>いくつかの構文では、多段に中身を追って型決定してくれます。
例えば、以下のように、多重のラムダ式からオーバーロード解決することができます。
(ただし制限あり。)</p>
<pre class="source" title="多重ラムダ式からのオーバーロード解決">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// 非ジェネリックなオーバーロードなら、多段ラムダ式でも解決可能。</span>
        <span class="comment">// (ただし、この解決ができるのは C# 6.0 以降)</span>
        <span class="method">M</span>(() =&gt; () =&gt; 1);   <span class="comment">// M(Func&lt;Func&lt;int&gt;&gt; x)</span>
        <span class="method">M</span>(() =&gt; () =&gt; 1.0); <span class="comment">// M(Func&lt;Func&lt;double&gt;&gt; x)</span>
 
        <span class="comment">// ただ、ジェネリックなものについては無理。コンパイル エラーに。</span>
        <span class="comment">// M&lt;string&gt; は呼んでもらえない。</span>
        M(() =&gt; () =&gt; <span class="string">&quot;&quot;</span>);
    }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">Func</span>&lt;<span class="type">Func</span>&lt;<span class="reserved">int</span>&gt;&gt; <span class="variable">x</span>) { }
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">Func</span>&lt;<span class="type">Func</span>&lt;<span class="reserved">double</span>&gt;&gt; <span class="variable">x</span>) { }
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">Func</span>&lt;<span class="type">Func</span>&lt;<span class="type">T</span>&gt;&gt; <span class="variable">x</span>) { }
}
</code></pre>
<p>暗黙の型変換の類は<a href="/study/csharp/datatype/tuples/">タプル</a>の中でも働きますし、この場合、タプルが入れ子になっていても大丈夫です。</p>
<pre class="source" title="入れ子のタプル">
<code><span class="comment">// 整数リテラルはターゲット型を見て暗黙的に変換がかかる。</span>
<span class="comment">// たとえ入れ子のタプルになっていてもこの仕組みは働く。</span>
(<span class="reserved">byte</span>, (<span class="reserved">short</span>, <span class="reserved">long</span>)) <span class="variable">t</span> = (1, (2, 3));
 
<span class="comment">// ちなみに、以下のコードだとコンパイル エラー。</span>
<span class="comment">// リテラル以外では、int から byte, short への変換は暗黙的にできない。</span>
(<span class="reserved">int</span>, (<span class="reserved">int</span>, <span class="reserved">int</span>)) <span class="variable">i</span> = (1, (2, 3));
<span class="variable">t</span> = <span class="variable">i</span>;
</code></pre>
<p><a href="/study/csharp/datatype/typeswitch/?p=5#target-typed">target-typed な<code>switch</code> 式</a>も、入れ子になっていても平気です。</p>
<pre class="source" title="入れ子の swtich 式">
<code><span class="reserved">static</span> <span class="reserved">byte</span>? <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>) =&gt; <span class="variable">obj</span> <span class="control">switch</span>
{
    <span class="reserved">string</span> <span class="variable">s</span> =&gt; <span class="variable">s</span>.Length <span class="control">switch</span>
    {
        0 =&gt; 1,    <span class="comment">// 2重の switch の中でも byte に変換できる</span>
        <span class="reserved">_</span> =&gt; <span class="reserved">null</span>, <span class="comment">// 同、null を byte? 扱いできる</span>
    },
    <span class="reserved">byte</span> <span class="variable">i</span> =&gt; <span class="variable">i</span>,
    <span class="reserved">_</span> =&gt; <span class="reserved">null</span>,
};
</code></pre>
<p>一方で、条件演算子や配列の型推論、ジェネリック型引数などは、ターゲット型からの型推論に対応していなくて、
以下のコードはコンパイル エラーになります。
(ただし、条件演算子については C# 9.0 でターゲット型推論を導入する予定があります。)</p>
<pre class="source" title="ターゲット型からの型推論を持っていない構文">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Fail</span>()
{
    <span class="comment">// 以下のいずれもコンパイル エラー。</span>
    <span class="reserved">byte</span>? <span class="variable">a</span> = <span class="error"><span class="reserved">true</span> ? 1 : <span class="reserved">null</span></span>;
    <span class="reserved">byte</span>?[] <span class="variable">b</span> = <span class="reserved">new</span>[] { 1, <span class="error"><span class="reserved">null</span></span> };
    <span class="reserved">byte</span>? <span class="variable">c</span> = M(1, <span class="error"><span class="reserved">null</span></span>);
}
 
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Success</span>()
{
    <span class="comment">// ターゲット型推論に頼らない書き方が求められる。</span>
    <span class="comment">// 以下の書き方ならソースからだけで型決定できる。</span>
    <span class="reserved">byte</span>? <span class="variable">a</span> = <span class="reserved">true</span> ? (<span class="reserved">byte</span>?)1 : <span class="reserved">null</span>;
    <span class="reserved">byte</span>?[] <span class="variable">b</span> = <span class="reserved">new</span>[] { (<span class="reserved">byte</span>?)1, <span class="reserved">null</span> };
    <span class="reserved">byte</span>? <span class="variable">c</span> = <span class="method">M</span>((<span class="reserved">byte</span>?)1, <span class="reserved">null</span>);
}
 
<span class="reserved">static</span> <span class="type">T</span> <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">x</span>, <span class="type">T</span> <span class="variable">y</span>) =&gt; <span class="variable">x</span>;
</code></pre>
<h2><a id="common-type">共通型</h2>
<p><code>switch</code> 式や条件演算子など、いくつかの「枝」を持つ構文では、枝ごとの型の「共通の型」(common type)を探す作業を一応行います。
ただ、C# 8.0 時点では制約がきつく、「枝のうちいずれか1つ」しか選ばれません。</p>
<p>ちょっとわかりにくいと思うので具体例を挙げます。
まず、以下のようなクラスを用意します。</p>
<pre class="source" title="型階層の例">
<code><span class="reserved">class</span> <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">A</span> : <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">Base</span> { }
</code></pre>
<p>このクラスと、あと、int を使って共通型を決定できるかどうかの例を示します。</p>
<pre class="source" title="共通型の決定">
<code><span class="comment">// 型の候補は A, B。それぞれお互いには変換不可なので、共通型の決定不可。</span>
<span class="reserved">var</span> <span class="variable">ng1</span> = <span class="error"><span class="variable">x</span> ? <span class="reserved">new</span> <span class="type">A</span>() : <span class="reserved">new</span> <span class="type">B</span>()</span>;
 
<span class="comment">// 型の候補は int。null は int に変換不可なので、共通型の決定不可。</span>
<span class="reserved">var</span> <span class="variable">ng2</span> = <span class="error"><span class="variable">x</span> ? 1 : <span class="reserved">null</span></span>;
 
<span class="comment">// 型の候補は Base, A。A から Base に変換可能なので、共通型は Base に決定。</span>
<span class="reserved">var</span> <span class="variable">ok1</span> = <span class="variable">x</span> ? <span class="reserved">new</span> <span class="type">Base</span>() : <span class="reserved">new</span> <span class="type">A</span>();
 
<span class="comment">// 型の候補は int?。null は int? に変換可能なので、共通型は int?。</span>
<span class="reserved">var</span> <span class="variable">ok2</span> = <span class="variable">x</span> ? (<span class="reserved">int</span>?)1 : <span class="reserved">null</span>;
 
<span class="comment">// 型の候補は int, int?。int は int? に変換可能なので、共通型は int?。</span>
<span class="reserved">var</span> <span class="variable">ok3</span> = <span class="variable">x</span> ? 1 : <span class="reserved">default</span>(<span class="reserved">int</span>?);
</code></pre>
<p><code>int</code> と null の共通型は <code>int?</code> だとわかりそうなものですが、少なくとも C# 8.0 ではそういう自動判定はしません。
枝のいずれか1つが <code>int?</code> でないと共通型判定できません。</p>
<p>ちなみに、「提案が出ている」という程度の状態で実現するかはわかりませんが、
値型 <code>T</code>と null が並んでいた場合、共通の型として <code>T?</code> を選ぶようにするという案もあります。</p>
<p>また、クラスの場合も共通の基底クラス(<code>A</code> と <code>B</code> の場合 <code>Base</code>)を共通型として選ぶかどうかも検討されています。
こちらは「基底クラスに限る」(共通インターフェイスの場合は相変わらず)という条件付きです。
インターフェイスが絡むと以下のように多段派生があったり複雑なのでおそらく認められません。</p>
<pre class="source" title="共通型の決定が難しい例">
<code><span class="comment">// 型 D と F の「共通型」といわれると何？</span>
<span class="comment">// インターフェイス J？ それともクラス A？</span>
<span class="reserved">interface</span> <span class="type">I</span> { }
<span class="reserved">interface</span> <span class="type">J</span> { }
<span class="reserved">class</span> <span class="type">A</span> { }
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">A</span>, <span class="type">I</span> { }
<span class="reserved">class</span> <span class="type">C</span> : <span class="type">A</span> { }
<span class="reserved">class</span> <span class="type">D</span> : <span class="type">B</span>, <span class="type">J</span> { }
<span class="reserved">class</span> <span class="type">E</span> : <span class="type">B</span> { }
<span class="reserved">class</span> <span class="type">F</span> : <span class="type">C</span>, <span class="type">J</span> { }
</code></pre> ]]></description>
				<pubDate>Sat, 02 Jan 2021 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>エントリー ポイント</title>
				<link>http://www.ufcpp.net/study/csharp/misc/miscentrypoint/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>実行可能なプログラムを書くとき、最初に呼び出される処理を<strong id="key-entry-point" class="keyword">エントリー ポイント</strong>(entry point: 入場地点、入り口)と言います。
C# の場合、通常、<code>Main</code> という名前の静的メソッドを1個だけ書くことで、このメソッドがエントリー ポイントになります。</p>
<p>また、複数の <code>Main</code> メソッドを書いてそのうちの1つをエントリー ポイントに選ぶ方法があったり、
C# 9.0 からはトップ レベル ステートメントという書き方でエントリー ポイントを作れたりします。</p>
<p>本項ではこの C# のエントリー ポイントに関する仕様について説明します。</p>
<h2><a id="entry-point-in-csharp">C# のエントリー ポイント</h2>
<p>C# 関連のチュートリアルでのサンプル コードや、
テンプレート通りに C# プログラムを新規作成すると以下のような内容になっていることが多いと思います。</p>
<pre class="source" title="よくあるチュートリアル・テンプレート通りの C# コード">
<code><span class="reserved">using</span> System;
 
<span class="reserved">namespace</span> ConsoleApp1
{
    <span class="reserved">class</span> <span class="type">Program</span>
    {
        <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>(<span class="reserved">string</span>[] args)
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Hello World!&quot;</span>);
        }
    }
}
</code></pre>
<p>C# の仕様上、実行可能プログラムを C# で書きたい場合、どこかに1つ、<code>Main</code> という名前のメソッドが必要です。
(後述しますが、C# 9.0 からは別の方法も追加されました。)</p>
<p>名前空間は必須ではありません。クラス名も何でも構いません。
例えば以下のようなコードでも、<code>Main</code> メソッドがエントリー ポイントになります。</p>
<pre class="source" title="名前空間はなくてもいい。クラス名も任意">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">X</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>(<span class="reserved">string</span>[] args)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Hello World!&quot;</span>);
    }
}
</code></pre>
<p>通常、エントリー ポイントとして使うためには、<code>Main</code> メソッドに以下のような制限があります。</p>
<ul>
<li><a href="/study/csharp/oo_static.html">静的</a>である(<code>static</code> 修飾子が付いてる)必要がある</li>
<li>引数はなしか、<code>string[]</code> のどちらか</li>
<li>
戻り値はなし(<code>void</code>)か、<code>int</code> のどちらか
<ul>
<li><a href="/study/csharp/cheatsheet/ap_ver7_1/#async-Main">C# 7.1</a> 以降は追加で <code>Task</code> か <code>Task&lt;int&gt;</code> も OK</li>
</ul>
</li>
</ul>
<p>つまり、C# 7.0 以前だと以下の4つのうちのいずれかが、</p>
<pre class="source" title="エントリー ポイントとして許される Main メソッドの書き方">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>(<span class="reserved">string</span>[] args)
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">Main</span>()
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">Main</span>(<span class="reserved">string</span>[] args)
</code></pre>
<p>加えて、C# 7.1 以降だと以下の4つのうちのいずれかが認められます。</p>
<pre class="source" title="エントリー ポイントとして許される Main メソッドの書き方 (C# 7.1 以降)">
<code><span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">static</span> <span class="type">Task</span> <span class="method">Main</span>()
<span class="reserved">static</span> <span class="type">Task</span> <span class="method">Main</span>(<span class="reserved">string</span>[] args)
<span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; <span class="method">Main</span>()
<span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; <span class="method">Main</span>(<span class="reserved">string</span>[] args)
</code></pre>
<h2><a id="entry-point-in-dotnet">.NET のエントリー ポイント</h2>
<p>前述の <code>Main</code> という名前が必須なのは C# の仕様上の話で、
その下層、 .NET ランタイムにはそういう制限はありません。
<code>.entrypoint</code> ディレクティブで修飾したメソッドがエントリー ポイントになります。</p>
<p>例えば、以下のような .NET IL アセンブラー コードを書けば、<code>A</code> というクラス内の <code>B</code> というメソッドをエントリー ポイントにできます。</p>
<pre class="source" title="">
<code>.class public auto ansi beforefieldinit A
       extends [mscorlib]System.Object
{
  .method public hidebysig static void B(string[] args) cil managed
  {
    <em>.entrypoint</em>
    .maxstack  8
    IL_0000:  ldstr      "Hello World!"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  nop
    IL_000b:  ret
  }
}
</code></pre>
<p>逆に .NET ランタイム的には <code>Task</code> 戻り値のエントリー ポイントを認めていなくて、
<a href="/study/csharp/cheatsheet/ap_ver7_1/#async-Main">C# 7.1 の非同期 <code>Main</code></a> は、C# コンパイラーが以下のようなコードに相当する IL を生成しています。</p>
<pre class="source" title="非同期メインから生成される実際のエントリー ポイント">
<code><span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// C# 7.1 以降書ける「非同期 Main」。</span>
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
    }
 
    <span class="comment">// 非同期 Main から C# コンパイラーが自動生成するメソッド。</span>
    <span class="comment">// これに .entrypoint ディレクティブが付く。</span>
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">&lt;Main&gt;</span>()
    {
        <span class="type">Main</span>().<span class="type">GetAwaiter</span>().<span class="type">GetResult</span>();
    }
}
</code></pre>
<h2><a id="startup-option">複数の Main メソッドからエントリー ポイントを選択</h2>
<p>C# で複数のクラスに <code>Main</code> メソッドを書くこともできますが、
素の状態ではコンパイル エラーになります。
(エラー内容は「複数のエントリー ポイントが定義されています」。)</p>
<pre class="source" title="">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="error"><span class="method">Main</span></span>()
    {
    }
}
 
<span class="reserved">class</span> <span class="type">B</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
    }
}
</code></pre>
<p>ただ、オプションによってこのうちのどれをエントリー ポイントにするかを指定する方法があります。
csc (C# コンパイラー)を直接呼び出す場合は <code>-main</code> オプションを、</p>
<pre class="source" title="よくあるチュートリアル・テンプレート通りの C# コード">
<code>csc <em>-main:A</em>
</code></pre>
<p>csproj (プロジェクト)に設定を書く場合は <code>StartupObject</code> タグでクラス名を指定します。</p>
<pre class="xsource" title="">
<code><span class="attvalue">&lt;</span><span class="element">Project</span><span class="attvalue"> </span><span class="attribute">Sdk</span><span class="attvalue">=</span>&quot;<span class="attvalue">Microsoft.NET.Sdk</span>&quot;<span class="attvalue">&gt;</span>
 
<span class="attvalue">  &lt;</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">OutputType</span><span class="attvalue">&gt;</span>Exe<span class="attvalue">&lt;/</span><span class="element">OutputType</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">TargetFramework</span><span class="attvalue">&gt;</span>net5.0<span class="attvalue">&lt;/</span><span class="element">TargetFramework</span><span class="attvalue">&gt;</span>
<em><span class="attvalue">    &lt;</span><span class="element">StartupObject</span><span class="attvalue">&gt;</span>A<span class="attvalue">&lt;/</span><span class="element">StartupObject</span><span class="attvalue">&gt;</span></em>
<span class="attvalue">  &lt;/</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>
 
<span class="attvalue">&lt;/</span><span class="element">Project</span><span class="attvalue">&gt;</span>
</code></pre>
<p>この例の場合は、この書き方で、<code>A.Main</code> の方がエントリー ポイントになります。</p>
<h2><a id="top-level-statements">トップ レベル ステートメント</h2>
<h5 class="version version9">Ver. 9.0</h5>
<p>C# 9.0 から、トップ レベル(top-leve: クラスや名前空間よりも外側、ファイル直下)に<a href="/study/csharp/st_variable.html#statement">ステートメント</a>を直接書けるようになりました。</p>
<p>例えば前述の「Hello World」であれば、単に以下のように書けるようになります。</p>
<pre class="source" title="トップ レベルに直接「Hello World」">
<code><span class="reserved">using</span> System;
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Hello World!&quot;</span>);
</code></pre>
<p>この機能を<strong id="key-top-level-statements" class="keyword">トップ レベル ステートメント</strong>(top-level statements)と言います。</p>
<p>挙動としては、<code>Main</code>に相当するメソッドの自動生成になります。
上記の例の場合、以下のようなコードが生成された上で、<code>$Main</code> メソッドに <code>.entrypoint</code> が付きます。</p>
<pre class="source" title="トップ レベル ステートメントから生成されるエントリー ポイント">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">&lt;Program&gt;$</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">$Main</span>(<span class="reserved">string</span>[] args)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;Hello World!&quot;</span>);
    }
}
</code></pre>
<p>クラス名もメソッド名も、通常の C# コードでは定義できない・呼び出しできない名前で生成されます<sup>※</sup>。
名前も決まった名前にはなっていません(今現在の実装が <code>$Main</code> という名前で生成しているからといって、将来ずっとこの名前とは限らない)。</p>
<p><sup>※</sup> <a href="https://ufcpp.net/blog/2021/11/top-level-csharp10/">C# 10.0 以降は、クラス名に関しては <code>Program</code> という普通の名前に変更されました</a>。
メソッド名の方は <code>&lt;Main&gt;$</code> になっています。</p>
<h3><a id="top-level-statement-restriction">ステートメントを書ける場所</h3>
<p>トップ レベル ステートメントを書ける場所には少し制約があります。</p>
<ul>
<li>プロジェクト全体で1ファイルだけがトップ レベル ステートメントを持てる</li>
<li>クラスや名前空間よりも上にだけトップ レベル ステートメントを書ける</li>
</ul>
<p>要は、実行順序で迷いそうになったり、
不慮の事故で予定外の処理を足してしまったりすることがないように、
書ける場所を1か所に絞っています。</p>
<p>例えば以下のようなコードはコンパイル エラーになります。</p>
<pre class="source" title="クラスよりも下にステートメントを書くことは認められていない">
<code><span class="reserved">using</span> System;
 
<span class="comment">// ここにステートメントを書くのは OK。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;above class&quot;</span>);
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">void</span> <span class="method">M</span>() { }
}
 
<span class="comment">// ここにステートメントを書くのはダメ。</span>
<span class="error"><span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;below class&quot;</span>);</span>
</code></pre>
<h3><a id="top-level-method">トップ レベルにメソッド記述</h3>
<p>トップ レベルにはメソッドを書くこともできます。
これは扱いとしては、生成される <code>Main</code> (相当の)メソッドのローカル関数になります。</p>
<p>例えば以下のようなコードを書いた場合、</p>
<pre class="source" title="トップ レベルでメソッドを定義">
<code><span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">string</span> s) =&gt; System.<span class="type">Console</span>.<span class="method">WriteLine</span>(s);
 
<span class="method">m</span>(<span class="string">&quot;abc&quot;</span>);
<span class="method">m</span>(<span class="string">&quot;123&quot;</span>);
</code></pre>
<p>コンパイラーが生成するコードは以下のような感じになります。</p>
<pre class="source" title="トップ レベルのメソッドは、生成される Main メソッドのローカル関数扱い">
<code><span class="reserved">class</span> <span class="type">&lt;Program&gt;$</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">$Main</span>(<span class="reserved">string</span>[] args)
    {
        <span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">string</span> s) =&gt; System.<span class="type">Console</span>.<span class="method">WriteLine</span>(s);
 
        <span class="method">m</span>(<span class="string">&quot;abc&quot;</span>);
        <span class="method">m</span>(<span class="string">&quot;123&quot;</span>);
    }
}
</code></pre>
<p>ただ、定義したメソッドの名前はプロジェクト全域に影響を及ぼします。
以下のように、「メソッドがあることは全域で見えているけども、使ってはいけない」という扱いを受けます。</p>
<pre class="source" title="トップ レベルのメソッドの扱い(名前は全域から見えてるけど、使っちゃダメ)">
<code><span class="reserved">void</span> <span class="method">m</span>(<span class="reserved">string</span> s) =&gt; System.<span class="type">Console</span>.<span class="method">WriteLine</span>(s);
 
<span class="method">m</span>(<span class="string">&quot;abc&quot;</span>);
<span class="method">m</span>(<span class="string">&quot;123&quot;</span>);
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>()
    {
        <span class="comment">// ここはエラーになるものの、エラー内容は</span>
        <span class="comment">// 「m が見つからない」ではなく、</span>
        <span class="comment">// 「トップ レベルで定義した m をここから使うことはできない」になる。</span>
        <span class="method">m</span>(<span class="string">&quot;Program.M&quot;</span>);
    }
}
</code></pre>
<p>(将来的に、トップ レベルで定義したメソッドを、ローカル関数扱いからグローバル関数(どこからでも参照できる静的メソッド)扱いに変更する可能性もなくはなく、その場合、C# 9.0 時点ではこの例のようなエラーにしておく方が将来の憂いがないみたいです。)</p>
<h3><a id="top-level-vs-script">トップ レベル ステートメントとスクリプト実行</h3>
<p>今の C# には<a href="/study/csharp/cheatsheet/apscripting/">スクリプト実行用の文法</a>もあったりするんですが、
それとトップ レベル ステートメントは微妙に仕様が違っていたりします。</p>
<p>スクリプト実行の場合にはクラスの後ろにもステートメントを書けます。
また、<a href="/study/csharp/cheatsheet/apscripting/#directive"><code>#r</code> や <code>#load</code> など</a>、一部のディレクティブはスクリプト実行専用です。
スクリプト実行では、<code>;</code> なしで式を書くと、その値をREPL(Read Eval Print Loop: 1行式を評価しては、即座にその値を画面に表示する)実行できたりします。</p>
<p>例えば、以下のコードはスクリプト実行では有効ですが、トップ レベル ステートメントとしてはコンパイル エラーになります。</p>
<pre class="source" title="スクリプト実行でだけ有効な C# コード">
<code><span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="reserved">int</span> Y;
}
 
<span class="reserved">var</span> p = <span class="reserved">new</span> <span class="type">Point</span> { X = 1, Y = 2 };
 
p.X
p.Y
</code></pre>
<p>一方で、スクリプト実行では名前空間を書けないので、例えば以下のコードはトップ レベル ステートメントでだけコンパイルできます。</p>
<pre class="source" title="トップ レベル ステートメントでだけ有効な C# コード">
<code><span class="reserved">var</span> p = <span class="reserved">new</span> App1.<span class="type">Point</span> { X = 1, Y = 2 };
 
<span class="reserved">namespace</span> App1
{
    <span class="reserved">struct</span> <span class="type">Point</span>
    {
        <span class="reserved">public</span> <span class="reserved">int</span> X;
        <span class="reserved">public</span> <span class="reserved">int</span> Y;
    }
}
</code></pre>
<h3><a id="args-returns">コマンドライン引数と戻り値</h3>
<p>トップ レベル ステートメントを使う場合、暗黙的に <code>args</code> という名前の変数が定義されていて、
この変数にはコマンドライン引数(<code>Main</code> メソッドを書いた時、<code>string[]</code> 引数に入っているのと同じもの)が入っています。</p>
<p>また、トップ レベル ステートメントには <code>return</code> を書くことができますが、<code>int</code> 戻り値の <code>Main</code> メソッドと同じ意味になります(プログラムの終了コードになる)。</p>
<p>例えば以下のようなトップ レベル ステートメントを書けます。</p>
<pre class="source" title="トップ レベル ステートメントにおけるコマンドライン引数と終了コード">
<code><span class="reserved">if</span> (args.Length == 0)
{
    System.<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;コマンドライン引数が必要です&quot;</span>);
    <span class="reserved">return</span> 1;
}
<span class="reserved">else</span>
{
    System.<span class="type">Console</span>.<span class="method">WriteLine</span>(args[0]);
    <span class="reserved">return</span> 0;
}
</code></pre>
<p>このコードは以下のような意味で解釈されます。</p>
<pre class="source" title="トップ レベル ステートメントから生成される Main メソッド">
<code><span class="reserved">class</span> <span class="type">&lt;Program&gt;$</span>
{
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">$Main</span>(<span class="reserved">string</span>[] args)
    {
        <span class="reserved">if</span> (args.Length == 0)
        {
            System.<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;コマンドライン引数が必要です&quot;</span>);
            <span class="reserved">return</span> 1;
        }
        <span class="reserved">else</span>
        {
            System.<span class="type">Console</span>.<span class="method">WriteLine</span>(args[0]);
            <span class="reserved">return</span> 0;
        }
    }
}
</code></pre>
<p><code>return</code> がない時には <code>void Main(string[] args)</code> で、あるときには <code>int Main(string[] args)</code> 相当のコードが生成されます。</p>
<p>ちなみに、トップ レベル ステートメント中には <code>await</code> を書けます。
<code>await</code> があるときに限って、<code>Task Main(string[] args)</code> 、 <code>Task&lt;int&gt; Main(string[] args)</code> 相当のコード生成になります。</p>
 ]]></description>
				<pubDate>Sun, 05 Jul 2020 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>null 許容参照型</title>
				<link>http://www.ufcpp.net/study/csharp/resource/nullablereferencetype/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# くらいの世代(1990年代後半～2000年代前半)のプログラミング言語では、
<a href="/study/csharp/oo_reference.html#reftype">参照型</a>には <a href="/study/csharp/oo_reference.html#null">null</a> が「つきもの」で、不可避なものでした。
(参考: 「<a href="https://www.buildinsider.net/column/iwanaga-nobuyuki/011">null参照問題</a>」。)</p>
<p>ただ、2010年代ともなると、「つきもの」として惰性で null を認めるのはよくないとされています。
C# でも、少なくとも「意図して null を使っているかどうか」を区別できる必要性が生まれました。</p>
<p>そこで C# 8.0 では、以下のような機能を提供することにしました。</p>
<ul>
<li>参照型でも単に型 <code>T</code> と書くと null を認めない型になる</li>
<li><code>T?</code> と書くと null を代入できる型になる</li>
</ul>
<p>C# 7.X の頃と 8.0 で何が変わったかというと、
「参照型でも null を拒否できるようになった」ということになります。
ただ、「<code>T?</code> と書いたときに null 許容」という方式なのと、値型との対比として、
この機能は<strong id="key-nrt" class="keyword">null許容参照型</strong>(nullable reference type)と呼びます(略してNRTと言うことも)。</p>
<p>構文的には C# 2.0 からあった<a href="/study/csharp/resource/sp2_nullable/">null許容値型</a>と極力そろうように作られています。</p>
<p>ただ、後入りな機能なので、以下のような制約が掛かります。</p>
<ul>
<li>
opt-in (オプションを明示しないと有効にならない)方式
<ul>
<li><code>T</code> の意味が変わるので、opt-in にしないと既存のコードがコンパイルできなくなる</li>
</ul>
</li>
<li>
警告のみ
<ul>
<li><code>T</code> 型の変数に null を代入しても警告だけで、エラーにはならない</li>
</ul>
</li>
<li>
値型と参照型で、<code>T?</code> の挙動が違う
<ul>
<li>参照型の <code>T</code> と <code>T?</code> はアノテーション<sup>※</sup>だけの差で、内部的には差がない</li>
<li>値型の場合は <code>T?</code> と書くと実体は <code>Nullable&lt;T&gt;</code> という <code>T</code> と明確に異なる型になる</li>
<li>特に、<a href="/study/csharp/sp2_generics.html">ジェネリクス</a>を使うときに困る</li>
</ul>
</li>
</ul>
<p><sup>※</sup> annotation。「単なる注釈」という意味で、この場合は「コンパイラーがソースコード解析するために使うヒントとなる情報」くらいの意味合い。</p>
<h2><a id="opt-in">null許容参照型の有効化</h2>
<p>無条件に「参照型でも null を拒否する」としてしまうと、既存の C# コードの挙動を壊します。</p>
<pre class="source" title="opt-in した瞬間に警告">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// NRT を opt-in した時点で警告が出るようになる</span>
        <span class="reserved">string</span> <span class="variable">s</span> = <span class="warning"><span class="reserved">null</span></span>; <span class="comment">// string (非 null)に null を入れちゃダメ</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable"><span class="warning">s</span></span>.Length); <span class="comment">// null の可能性があるものを null チェックせずに使っちゃダメ</span>
    }
}
</code></pre>
<p>警告だから追加してもいいということにはなりません。
警告を残すのは作法的によくないことですし、
なので、C# には<a href="https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/compiler-options/warnaserror-compiler-option">「警告をすべてエラー扱いする」というオプション</a>もあります。
警告の追加も破壊的変更の一種になります。</p>
<p>C# は「既存のソースコードがコンパイルできなくなる」というのをかなり慎重に避けている言語なので、null許容参照型は無条件に入れられる機能ではありません。
そのため、明示的な有効化(opt-in)が必要になります。</p>
<p>有効化された状態かどうかを指して、<strong id="nullable-context" class="keyword">null 許容コンテキスト</strong>(nullable context)と言います。
(有効・無効を切り替えることを「null 許容コンテキストの切り替え」とか言ったりします。)</p>
<p>null 許容コンテキストの切り替え方は2通りあります。</p>
<ul>
<li>ソースコード中の行単位での切り替え … <code>#nullable</code> ディレクティブ</li>
<li>プロジェクト全体での切り替え … <code>Nullable</code> オプション</li>
</ul>
<p>また、単純な有効・無効以外に、後述する warnings/annotations (それぞれ警告のみ、アノテーションのみの有効・無効化)というモードもあります。</p>
<p>ちなみに、C# は本来、オプションでのオン/オフ切り替えなど、
「文法の分岐」に対してもかなり消極的な言語です。
opt-in 方式で <code>T</code> の意味が変わるnull許容参照型もだいぶ悩んだ末の苦渋の決断で、
それだけnull参照問題が深刻だということです。
おそらく、C# 史上最初で最後の大きな「分岐」になると思われます。</p>
<h3><a id="nullable-directive">#nullable ディレクティブ</h3>
<p>それなりの規模のソースコードを保守している場合、いきなりnull許容参照型を全面的に有効化してしまうと結構大変なことになります。
(筆者の経験的な話で言うと、少なくとも50行に1個くらいは警告が出ます。何万行ものソースコードを持っている場合、とてもじゃないけど直して回れるものではありません。)</p>
<p>そのため、<a href="/study/csharp/sp_preprocess.html">プリプロセッサー</a>的に、書いたその行以降の opt-in/opt-out をする <code>#nullable</code> ディレクティブが用意されています。
(<a href="/study/csharp/sp_preprocess.html#pragma"><code>#pragma warning</code></a>と似たような使い方をします。)</p>
<p>以下のような書き方をします。</p>
<pre class="source" title="nullable ディレクティブ">
<code><span class="inactive">#nullable</span> <span class="input">enable|disable|restore</span> <span class="input">[warnings|annotations]</span>
</code></pre>
<p>null 許容参照型を有効にしたければ<code>#nullable enable</code>、
無効にしたければ<code>#nullable disable</code>と書きます。
<code>#nullable restore</code>は「1つ前のコンテキストに戻す」という処理になります。
<code>warnings</code>と<code>annotations</code>については後述しますが、省略可能で、省略した場合は「両方をオン・オフ」になります。</p>
<pre class="source" title="null 許容コンテキストの切り替え例">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
        <span class="method">E1</span>(<span class="warning"><span class="reserved">null</span></span>); <span class="comment">// 警告が出る</span>
 
<span class="inactive">#nullable</span> <span class="inactive">disable</span>
        <span class="method">E1</span>(<span class="reserved">null</span>); <span class="comment">// 警告が出ない</span>
    }
 
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
    <span class="comment">// 有効化したのでここでは string で非 null、string? で null 許容。</span>
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">E1</span>(<span class="reserved">string</span> <span class="variable">s</span>) =&gt; <span class="variable">s</span>.Length;
    <span class="reserved">static</span> <span class="reserved">int</span>? <span class="method">E2</span>(<span class="reserved">string</span>? <span class="variable">s</span>) =&gt; <span class="variable">s</span>?.Length;
 
<span class="inactive">#nullable</span> <span class="inactive">disable</span>
    <span class="comment">// 無効化したので string に null が入っている可能性あり。</span>
    <span class="comment">// string? とは書けない(書くだけで警告になる)。</span>
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">D1</span>(<span class="reserved">string</span> <span class="variable">s</span>) =&gt; <span class="variable">s</span>.Length;
 
<span class="inactive">#nullable</span> <span class="inactive">restore</span>
    <span class="comment">// 1つ前のコンテキストに戻す。</span>
    <span class="comment">// この場合、disable から enable に戻る。</span>
    <span class="reserved">static</span> <span class="reserved">int</span>? <span class="method">R1</span>(<span class="reserved">string</span>? <span class="variable">s</span>) =&gt; <span class="variable">s</span>?.Length;
}
</code></pre>
<h3><a id="nullable-option">Nullable オプション</h3>
<p>一方で、これから新規に作成するプログラムの場合、最初から全部null許容参照型を有効化してしまう方がいいでしょう。
そのくらい、null参照問題は避けたいものです。</p>
<p>プロジェクト全体で null 許容コンテキストを切り替えるには、コンパイラー オプションを指定します。
<code>csc</code> (C# コンパイラー)コマンドを直接使う場合は <code>/nullable</code> オプションで指定します。</p>
<pre class="console" title="csc の /nullable オプション">
<code>csc <span class="input">source.cs</span> <em>/nullable:enable</em> /langversion:8
</code></pre>
<p>csproj (C# プロジェクト)ファイル中でオプション指定する場合、<code>&lt;Nullable&gt;</code> タグを使います。</p>
<pre class="xsource" title="csproj の Nullable オプション">
<code><span class="attvalue">&lt;</span><span class="element">Project</span><span class="attvalue"> </span><span class="attribute">Sdk</span><span class="attvalue">=</span>&quot;<span class="attvalue">Microsoft.NET.Sdk</span>&quot;<span class="attvalue">&gt;</span>
 
<span class="attvalue">  &lt;</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">OutputType</span><span class="attvalue">&gt;</span>Exe<span class="attvalue">&lt;/</span><span class="element">OutputType</span><span class="attvalue">&gt;</span>
<span class="attvalue">    &lt;</span><span class="element">TargetFramework</span><span class="attvalue">&gt;</span>netcoreapp3.0<span class="attvalue">&lt;/</span><span class="element">TargetFramework</span><span class="attvalue">&gt;</span>
<span class="attvalue">    <em>&lt;</span><span class="element">Nullable</span><span class="attvalue">&gt;</span>enable<span class="attvalue">&lt;/</span><span class="element">Nullable</span><span class="attvalue">&gt;</span></em>
<span class="attvalue">  &lt;/</span><span class="element">PropertyGroup</span><span class="attvalue">&gt;</span>
 
<span class="attvalue">&lt;/</span><span class="element">Project</span><span class="attvalue">&gt;</span>
</code></pre>
<p>指定できる値は <code>enable</code>(有効)、<code>disable</code> (無効)、<code>warnings</code> (警告のみ有効)、<code>annotations</code> (アノテーションのみ有効)の4種類です。
<code>warnings</code> と <code>annotations</code> については次節で説明します。</p>
<h3><a id="nullable-directive">warnings/annotations</h3>
<p>null 許容参照型には以下の2つの側面があります。</p>
<ul>
<li>アノテーション: 型に <code>?</code> を付けて null 許容か非 null かを明示する</li>
<li>警告: アノテーションを見て、適切な null チェックが行われてるかどうかを調べて警告を出す</li>
</ul>
<p><img src="/media/1177/annotation_warning.png" alt="warnings/annotations" /></p>
<p>既存コードを null 許容参照型に段階的に対応させていくにあたって、
これら2つは別々に有効化・無効化できます。
以下のような状況を想定しています。</p>
<ul>
<li>差し当たってアノテーションだけは付けたいけど、中身の警告を全部消す作業まで手が回らない</li>
<li>差し当たって警告は出してほしいけど、自分が公開している API にまでは責任を持てないのでアノテーションは付けたくない</li>
</ul>
<p>アノテーションを付けるかどうかだけを切り替えるのが <code>annotations</code> で、
警告の有無だけを切り替えるのが <code>warnings</code> です。</p>
<p>例えば、元々以下のようなコードがあったとします。</p>
<pre class="xsource" title="既存コード(null 許容参照型に未対応)">
<code><span class="inactive"><span class="attvalue">string</span> <span class="method">NotNull</span>() =&gt; <span class="element">&quot;&quot;</span>;
<span class="attvalue">string</span> <span class="method">MaybeNull</span>() =&gt; <span class="attvalue">null</span>;
 
<span class="attvalue">int</span> <span class="method">M</span>(<span class="attvalue">string</span> <span class="variable">s</span>)
{
    <span class="attvalue">var</span> <span class="variable">s1</span> = <span class="method">NotNull</span>();
    <span class="attvalue">var</span> <span class="variable">s2</span> = <span class="method">MaybeNull</span>();
    <span class="control">return</span> <span class="variable">s</span>.Length + <span class="variable">s1</span>.Length + <span class="variable">s2</span>.Length;
}
</code></pre>
<p>これに対して、単に <code>#nullable enable</code> を付けるとアノテーションも警告も有効になります。</p>
<pre class="xsource" title="enable のみ指定(アノテーションも警告も有効化)">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="attvalue">string</span> <span class="method">NotNull</span>() =&gt; <span class="element">&quot;&quot;</span>;
<span class="attvalue">string</span>? <span class="method">MaybeNull</span>() =&gt; <span class="attvalue">null</span>; <span class="comment">// 戻りに ? を追加</span>
 
<span class="attvalue">int</span> <span class="method">M</span>(<span class="attvalue">string</span> <span class="variable">s</span>) <span class="comment">// この s は非 null の意味になる</span>
{
    <span class="attvalue">var</span> <span class="variable">s1</span> = <span class="method">NotNull</span>();
    <span class="attvalue">var</span> <span class="variable">s2</span> = <span class="method">MaybeNull</span>();
    <span class="control">return</span> <span class="variable">s</span>.Length + <span class="variable">s1</span>.Length + <span class="variable">s2</span>.Length; <span class="comment">// s2 のところに警告が出る</span>
}
</code></pre>
<p><code>#nullable enable warnings</code> とすると警告のみ有効化できます。
この場合、引数の <code>string</code> は「C# 7.3 以前と同じ扱い」で、null 許容かどうか「未指定」になります。</p>
<pre class="xsource" title="警告のみ有効化">
<code><span class="comment">// 警告のみ有効化</span>
<span class="inactive">#nullable</span> <span class="inactive">enable</span> <span class="inactive">warnings</span>
<span class="attvalue">int</span> <span class="method">M</span>(<span class="attvalue">string</span> <span class="variable">s</span>) <span class="comment">// この s は null 許容かどうか「未指定」</span>
{
    <span class="attvalue">var</span> <span class="variable">s1</span> = <span class="method">NotNull</span>();
    <span class="attvalue">var</span> <span class="variable">s2</span> = <span class="method">MaybeNull</span>();
    <span class="control">return</span> <span class="variable">s</span>.Length + <span class="variable">s1</span>.Length + <span class="variable">s2</span>.Length; <span class="comment">// s2 のところに警告が出る</span>
}
</code></pre>
<p>一方、<code>#nullable enable annotations</code> とするとアノテーションのみが有効化されます。
null のチェック漏れがあっても警告は出ない状態です。</p>
<pre class="xsource" title="">
<code><span class="comment">// アノテーションのみ有効化</span>
<span class="inactive">#nullable</span> <span class="inactive">enable</span> <span class="inactive">annotations</span>
<span class="attvalue">int</span> <span class="method">M</span>(<span class="attvalue">string</span> <span class="variable">s</span>) <span class="comment">// この s は非 null</span>
{
    <span class="attvalue">var</span> <span class="variable">s1</span> = <span class="method">NotNull</span>();
    <span class="attvalue">var</span> <span class="variable">s2</span> = <span class="method">MaybeNull</span>();
    <span class="control">return</span> <span class="variable">s</span>.Length + <span class="variable">s1</span>.Length + <span class="variable">s2</span>.Length; <span class="comment">// 警告は出ない</span>
}
</code></pre>
<h2><a id="flow-analysis">フロー解析</h2>
<p>null 許容参照型は、フロー解析(flow analysis)で成り立っています。
フロー解析というのは、コードの流れ(flow)を追って、
「使っている場所より前で正しく代入・チェックが行われるか」を C# コンパイラーが調べるものです。</p>
<p>例えば以下のように、変数 <code>s</code> に何を代入したかによって、それ以降、<code>s.Length</code> というようなメンバー アクセス時に警告が出たり出なかったりします。</p>
<pre class="source" title="null 許容参照型はフロー解析で null チェックをしてる">
<code><span class="comment">// null 許容で宣言されていても、</span>
<span class="reserved">string</span>? <span class="variable">s</span>;
 
<span class="comment">// ちゃんと有効な値を代入すれば</span>
<span class="variable">s</span> = <span class="string">&quot;abc&quot;</span>;
 
<span class="comment">// 警告は出なくなる。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span>.Length);
 
<span class="comment">// 逆に null を代入すると、</span>
<span class="variable">s</span> = <span class="reserved">null</span>;
 
<span class="comment">// それ以降警告が出る。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="warning"><span class="variable">s</span></span>.Length);
</code></pre>
<p>分岐などもきっちり調べられます。</p>
<pre class="source" title="フロー解析は分岐もちゃんと調べる">
<code><span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">flag</span>)
{
    <span class="reserved">string</span>? <span class="variable">s</span>;
 
    <span class="comment">// 分岐の1つでも null があれば、その後ろでは警告が出る。</span>
    <span class="control">if</span> (<span class="variable">flag</span>) <span class="variable">s</span> = <span class="string">&quot;abc&quot;</span>;
    <span class="control">else</span> <span class="variable">s</span> = <span class="reserved">null</span>;
 
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="warning"><span class="variable">s</span></span>.Length);
 
    <span class="comment">// 分岐の全部で非 null なら、その後ろでは警告が出ない。</span>
    <span class="control">if</span> (<span class="variable">flag</span>) <span class="variable">s</span> = <span class="string">&quot;abc&quot;</span>;
    <span class="control">else</span> <span class="variable">s</span> = <span class="string">&quot;123&quot;</span>;
 
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span>.Length);
}
</code></pre>
<p>非 null (<code>?</code> が付いていない)変数・引数には null を渡した時点で警告が出て、
null 許容(<code>?</code> が付いてる)変数・引数の場合はメンバー アクセスの時点で警告が出ます。
また、null 代入の有無の他、<code>is null</code> や <code>== null</code> での null チェックをすれば、それ以降の警告は消えます。</p>
<pre class="source" title="警告の出方">
<code><span class="reserved">using</span> System;
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
    <span class="comment">// enable なコンテキストでは、string と書くと非 null、string? と書くと null 許容。</span>
    <span class="reserved">string</span> <span class="method">NotNull</span>(<span class="reserved">string</span> <span class="variable">s</span>) =&gt; <span class="variable">s</span>;
    <span class="reserved">string</span>? <span class="method">MaybeNull</span>(<span class="reserved">string</span>? <span class="variable">s</span>) =&gt; <span class="variable">s</span>;
 
    <span class="reserved">void</span> <span class="method">M</span>()
    {
        <span class="comment">// 非 null。</span>
        <span class="reserved">var</span> <span class="variable">n</span> = <span class="method">NotNull</span>(<span class="warning"><span class="reserved">null</span></span>); <span class="comment">// 引数に null を渡した時点で警告。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">n</span>.Length);
 
        <span class="comment">// null 許容。</span>
        <span class="reserved">var</span> <span class="variable">m</span> = <span class="method">MaybeNull</span>(<span class="reserved">null</span>);
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="warning"><span class="variable">m</span></span>.Length); <span class="comment">// 戻り値の null チェックをしなかった時点で警告。</span>
 
        <span class="control">if</span> (<span class="variable">m</span> <span class="reserved">is</span> <span class="reserved">null</span>) <span class="control">return</span>;
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">m</span>.Length); <span class="comment">// 前の行で null チェックしたのでもう警告にならない。</span>
    }
}
</code></pre>
<p>ちなみに、一度何らかのメンバー アクセスをした時点で「null チェックした」扱いを受けます。
「null 許容型を null チェックなしで使ってる」警告が出るのは最初の1個だけになります。</p>
<pre class="source" title="メンバー アクセスを持って null チェック扱い">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span>? <span class="variable">x</span>)
{
    <span class="comment">// null チェックせずに使ったので警告。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="warning"><span class="variable">x</span></span>[0]);
 
    <span class="comment">// ただ、2重には警告がでない。警告が出るのは↑の行だけ。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span>.Length);
}
</code></pre>
<p>他の変数との比較でも null チェックになることがあります。
例えば以下のように、非 null な変数 <code>x</code> と一致したら null 許容な変数 <code>y</code> も null ではないことが確定します。
これもちゃんとフロー解析の対象になっています。</p>
<pre class="source" title="他の変数との比較で null チェック">
<code><span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">x</span>, <span class="reserved">string</span>? <span class="variable">y</span>)
{
    <span class="comment">// 非 null な x との比較で y が null じゃないことがわかる。</span>
    <span class="control">if</span> (<span class="variable">x</span> == <span class="variable">y</span>)
    {
        <span class="comment">// こっちは y が非 null なことがわかるので警告が出ない。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">y</span>.Length);
    }
    <span class="control">else</span>
    {
        <span class="comment">// こっちは null な可能性が残るので警告が出る。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="warning"><span class="variable">y</span></span>.Length);
    }
}
</code></pre>
<h4>注意: 別スレッドでの書き換え</h4>
<p>フィールドやプロパティに対するフロー解析では、利便性を優先して、シングルスレッド動作を前提としたフロー解析をしています。
例えば、以下のように、マルチスレッド動作をしていて、他のスレッドで書き換えられてしまうと、本来 null が来るはずがなく警告も出ない場面で null 参照例外が起こることがあります。</p>
<pre class="source" title="別スレッドで null を代入することで不整合が起こる例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span>? S;
 
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetNull</span>()
    {
        S = <span class="reserved">null</span>;
    }
 
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">SetNonNull</span>()
    {
        <span class="control">if</span> (S <span class="reserved">is</span> <span class="reserved">null</span>) S = <span class="string">&quot;&quot;</span>;
 
        <span class="type">Thread</span>.<span class="method">Sleep</span>(200);
 
        <span class="comment">// 警告はでない。 S = &quot;&quot; しているので非 null 扱い。</span>
        <span class="comment">// 単一スレッド実行の場合はおかしくはない。</span>
        <span class="comment">// でも、Sleep 中に SetNull を呼ばれると null 参照例外になる。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(S.Length);
    }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">p</span> = <span class="reserved">new</span> <span class="type">Program</span>();
        <span class="type">Task</span>.<span class="method">Run</span>(<span class="variable">p</span>.<span class="method">SetNonNull</span>);
        <span class="type">Thread</span>.<span class="method">Sleep</span>(100);
        <span class="type">Task</span>.<span class="method">Run</span>(<span class="variable">p</span>.<span class="method">SetNull</span>);
 
        <span class="type">Thread</span>.<span class="method">Sleep</span>(300);
    }
}
</code></pre>
<h3><a id="initialize-field">フィールドやプロパティの初期化</h3>
<p>非 null 型のフィールドやプロパティは、コンストラクター内で必ず初期化しなければなりません。
例えば以下のコードはフィールド <code>X</code>、プロパティ <code>Y</code> のところに警告が出ます。</p>
<pre class="source" title="非 null なフィールド・プロパティを初期化しないと警告が出る">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="warning">X</span>;
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="warning">Y</span> { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</code></pre>
<p>以下のように、コンストラクターを追加すれば警告が消えます。</p>
<pre class="source" title="初期化コードを足すことで警告が消える">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> X;
    <span class="reserved">public</span> <span class="reserved">string</span> Y { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="type">A</span>(<span class="reserved">string</span> <span class="variable">x</span>, <span class="reserved">string</span> <span class="variable">y</span>) =&gt; (X, Y) = (<span class="variable">x</span>, <span class="variable">y</span>);
}
</code></pre>
<p>ちなみに、コンストラクターは書いたものの初期化を忘れると、
フィールド・プロパティの方だけではなく、コンストラクターの方にも警告が出ます。</p>
<pre class="source" title="初期か忘れ警告">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> <span class="warning">X</span>;
 
    <span class="comment">// X を初期化していないのでコンストラクターにも警告が出る</span>
    <span class="reserved">public</span> <span class="warning"><span class="type">A</span></span>() { }
}
</code></pre>
<p>ちなみに、最終的には非 null になるものの、コンストラクターの時点ではどうしても一時的に null を入れておかないといけない場面というものもあったりします。
そういうときの回避策として、後述する <a href="/study/csharp/resource/nullablereferencetype/?p=3#null-forgiving"><code>!</code> 演算子</a>というものもあります。</p>
<pre class="source" title="null をあえて見逃すための ! 演算子">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 一時的に null になってしまうことを強制的に容認</span>
    <span class="reserved">public</span> <span class="reserved">string</span> X = <span class="reserved">null</span><em>!</em>;
}
</code></pre>
<h3><a id="oblivious">oblivious</h3>
<p>opt-in にしたので、null 許容(nullable)、非 null (non-nullable, not null)の他に、
「アノテーションが付いていない、未指定」という状態があり得ます。
この未指定状態を oblivious (忘れてる、気づかない)と呼びます。</p>
<p>要するに、C# 7.3 以前で書かれたコードや、<code>#nullable enable annotations</code>になっていない場所で書かれたコードの型が oblivious です。
oblivious な型の変数は一切フロー解析の対象になりません。</p>
<pre class="source" title="oblivious な変数">
<code><span class="reserved">using</span> System;
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
<span class="inactive">#nullable</span> <span class="inactive">disable</span>
    <span class="comment">// C# 7.3 以前でコンパイルされたものや、disable なコンテキストで定義されると</span>
    <span class="comment">// アノテーション「未指定」(oblivious)という扱いになる。</span>
    <span class="reserved">string</span> <span class="method">Oblivious</span>(<span class="reserved">string</span> <span class="variable">s</span>) =&gt; <span class="variable">s</span>;
 
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
    <span class="reserved">void</span> <span class="method">M</span>()
    {
        <span class="comment">// 未指定。</span>
        <span class="comment">// null チェックの対象にならない(警告出ない)。</span>
        <span class="reserved">var</span> <span class="variable">o</span> = <span class="method">Oblivious</span>(<span class="reserved">null</span>);
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">o</span>.Length);
 
        <span class="comment">// たとえ明示的な型で受けても、もうこの変数は oblivious 扱いでチェック対象にならない(警告出ない)。</span>
        <span class="reserved">string</span>? <span class="variable">o1</span> = <span class="method">Oblivious</span>(<span class="reserved">null</span>);
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">o1</span>.Length);
    }
}
</code></pre>
<h3><a id="nvt-defference">null 許容値型との違い</h3>
<p>null 許容<em>参照</em>型は、
<code>?</code> を使う文法こそ<a href="/study/csharp/sp2_nullable.html">null 許容<em>値</em>型</a>と同じですが、
内部的にはだいぶ違う実装になっています。
null 許容参照型の <code>?</code> は単なるアノテーション(フロー解析のためのヒント)で、実装上、<code>T</code>と<code>T?</code>が本質的には同じ型です。
一方で、null 許容値型の <code>?</code> は明確に別の型になります(<code>T?</code> と書くと<code>Nullable&lt;T&gt;</code>型になります)。</p>
<p>この実装上の差から、使い勝手にも差が出てきます。
まず、以下のように、<code>T</code> と <code>T?</code> でオーバーロードできるのは値型だけです。</p>
<pre class="source" title="オーバーロードの可否">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="comment">// 参照型の場合、アノテーションだけが違うオーバーロードは作れない。</span>
<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">x</span>) { }
<span class="reserved">void</span> <span class="error"><span class="method">M</span></span>(<span class="reserved">string</span>? <span class="variable">x</span>) { }
 
<span class="comment">// 値型の場合、? が付くと別の型なのでオーバーロードできる。</span>
<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">x</span>) { }
<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span>? <span class="variable">x</span>) { }
</code></pre>
<p>また、null チェック後の挙動が違います。
参照型の場合は null チェックさえ挟めば以後「null ではない」という扱いを受けますが、
値型の場合は null チェックを挟んでも <code>Nullable&lt;T&gt;</code> は <code>Nullable&lt;T&gt;</code> のままです。</p>
<pre class="source" title="null チェック後の挙動">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="comment">// 参照型の場合</span>
<span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span>? <span class="variable">x</span>)
{
    <span class="comment">// null チェックさえすれば</span>
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">null</span>) <span class="control">return</span>;
    <span class="comment">// 警告が消える。</span>
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span>.Length);
}
 
<span class="comment">// 値型の場合</span>
<span class="reserved">void</span> <span class="method">M</span>(<span class="type">DateTime</span>? <span class="variable">x</span>)
{
    <span class="comment">// null チェックしても</span>
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">null</span>) <span class="control">return</span>;
    <span class="comment">// こういう書き方はできない(x?.Minute や x.Value.Minute なら大丈夫)。</span>
    <span class="type">Console</span>.WriteLine(<span class="variable">x</span>.<span class="error">Minute</span>);
}
</code></pre>
<p>null 許容参照型は <code>typeof</code> 演算子に対しても使えません。
<code>T</code> と <code>T?</code> が内部的には同じ型なのに、<code>typeof(T?)</code> を認めると混乱の元です。
以下のコードはコンパイル エラーになります。</p>
<pre class="source" title="null 許容参照型に対して typeof を使うとコンパイル エラー">
<code><span class="reserved">var</span> <span class="variable">t</span> = <span class="error"><span class="reserved">typeof</span>(<span class="reserved">string</span>?)</span>;
</code></pre>
<!-- pageBreak -->
<h2><a id="compile">アノテーションのコンパイル結果</h2>
<p>null 許容参照型のアノテーションのコンパイル結果は、
<code>NullableContext</code>と<code>Nullable</code> という2つの属性(いずれも<code>System.Runtime.CompilerServices</code>名前空間)を使って表現されます。</p>
<p>2つの属性を使い分けるのはプログラムのサイズを小さくするためです。
属性は付けば付くだけ少しずつプログラムを大きくするため、ちょっとでも付く量を減らす工夫をしています。
例えば以下のようなメソッドを考えます。
引数が4つあって、非nullとnull許容がそれぞれ2つずつになっています。</p>
<pre class="source" title="非null引数が2つ、null許容引数が2つのメソッド">
<code><span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span>? <span class="variable">b</span>, <span class="reserved">string</span> <span class="variable">c</span>, <span class="reserved">string</span>? <span class="variable">d</span>) { }
</code></pre>
<p>初期の案では <code>Nullable</code> 属性だけを使って、以下のようにコンパイルする予定でした。</p>
<pre class="source" title="初期案(Nullable のみ)">
<code><span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>([<span class="type">Nullable</span>(1)]<span class="reserved">string</span> <span class="variable">a</span>, [<span class="type">Nullable</span>(2)]<span class="reserved">string</span> <span class="variable">b</span>, [<span class="type">Nullable</span>(1)]<span class="reserved">string</span> <span class="variable">c</span>, [<span class="type">Nullable</span>(2)]<span class="reserved">string</span> <span class="variable">d</span>) { }
</code></pre>
<p>これだとすべての引数に属性が付くことになります。
その後、少しでも属性の数を減らすために、<code>NullableContext</code> 属性が追加され、
以下のようにコンパイルされる仕様になりました。</p>
<pre class="source" title="NullableContext の導入">
<code>[<span class="type">NullableContext</span>(1)]
<span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">a</span>, [<span class="type">Nullable</span>(2)]<span class="reserved">string</span> <span class="variable">b</span>, <span class="reserved">string</span> <span class="variable">c</span>, [<span class="type">Nullable</span>(2)]<span class="reserved">string</span> <span class="variable">d</span>) { }
</code></pre>
<p><code>NullableContext</code> は、クラス内やメソッド内で、<code>Nullable</code> 属性が付いていない引数・戻り値をどう扱うかを示しています。
(前述の「<a href="/study/csharp/resource/nullablereferencetype/#nullable-context">null 許容コンテキスト</a>」とは微妙に違う意味で context (文脈)という単語を使ってしまっていますが、
まあどちらも「前後のコードの意味を変える」という意味で「文脈」です。)</p>
<p>この例でいうと、「メソッドに1と付いているので、引数 <code>a</code>、<code>c</code> は1扱い」ということになります。
メソッドに対する属性が1個増えた代わりに、引数に対する属性が2個減って、全体では属性の数が減りました。</p>
<p>ちなみに、属性の引数になっている1とか2とかの数値は以下の意味になります。
(<code>Nullable</code>も<code>NullableContext</code>も付いていない場合は0、すなわち oblivious 扱いになります。)</p>
<table>
<thead>
<tr>
	<th>値</th>
	<th>意味</th>
</tr>
</thead>
<tbody>
<tr>
	<td>0</td>
	<td>oblivious</td>
</tr>
<tr>
	<td>1</td>
	<td>非 null</td>
</tr>
<tr>
	<td>2</td>
	<td>null 許容</td>
</tr>
</tbody>
</table>
<p>属性は、総数が極力少なくなるように付きます。
例えば以下のような2つのメソッドを考えます。</p>
<pre class="source" title="非 null、null 許容の引数の数">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 非 null が2個、null 許容が1個</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>, <span class="reserved">string</span>? <span class="variable">c</span>) { }
 
    <span class="comment">// 非 null が1個、null 許容が2個</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M2</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span>? <span class="variable">b</span>, <span class="reserved">string</span>? <span class="variable">c</span>) { }
}
</code></pre>
<p>これは、以下のようなコードにコンパイルされます。
要するに、多い方が「context」になることで、属性が必要な引数が減ります。</p>
<pre class="source" title="多い方を Context で指定">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="comment">// 非 null が多いので NullableContext(1)</span>
    [<span class="type">NullableContext</span>(1)]
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>, [<span class="type">Nullable</span>(2)] <span class="reserved">string</span> <span class="variable">c</span>) { }
 
    <span class="comment">// null 許容が多いので NullableContext(2)</span>
    [<span class="type">NullableContext</span>(2)]
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M2</span>([<span class="type">Nullable</span>(1)] <span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>, <span class="reserved">string</span> <span class="variable">c</span>) { }
}
</code></pre>
<p>(ちなみに、数が同じ場合は2よりも1を、1よりも0を優先するようです。)</p>
<p>型自体に <code>NullableContext</code> が付く例も見てみましょう。
以下のような2つの型を考えます。</p>
<pre class="source" title="型に NullableContext が付く例">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M2</span>(<span class="reserved">string</span>? <span class="variable">a</span>) { }
 
    <span class="comment">// 非 null なメソッドが多い</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N1</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N2</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N3</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
}
 
<span class="reserved">class</span> <span class="type">B</span>
{
    <span class="comment">// M1, M2 は A と同じ</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M2</span>(<span class="reserved">string</span>? <span class="variable">a</span>) { }
 
    <span class="comment">// null 許容なメソッドが多い</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N1</span>(<span class="reserved">string</span>? <span class="variable">a</span>, <span class="reserved">string</span>? <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N2</span>(<span class="reserved">string</span>? <span class="variable">a</span>, <span class="reserved">string</span>? <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N3</span>(<span class="reserved">string</span>? <span class="variable">a</span>, <span class="reserved">string</span>? <span class="variable">b</span>) { }
}
</code></pre>
<p>この場合、メソッドに付く属性が減るように、クラスに <code>NullableContext</code> 属性が付きます。
以下のようなコンパイル結果になります。</p>
<pre class="source" title="型に NullableContext が付いた結果">
<code>[<span class="type">NullableContext</span>(1)]
<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
    [<span class="type">NullableContext</span>(2)]
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M2</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
 
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N1</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N2</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N3</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
}
 
[<span class="type">NullableContext</span>(2)]
<span class="reserved">class</span> <span class="type">B</span>
{
    [<span class="type">NullableContext</span>(1)]
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M2</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
 
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N1</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N2</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">N3</span>(<span class="reserved">string</span> <span class="variable">a</span>, <span class="reserved">string</span> <span class="variable">b</span>) { }
}
</code></pre>
<h3><a id="generic-annotation">型引数に対するアノテーション</h3>
<p><a href="/study/csharp/sp2_generics.html">ジェネリクス</a>が絡むともう少し複雑になります。
<a href="/study/csharp/sp4_callsite.html#DynamicAttribute"><code>dynamic</code>型の場合</a>と同じなんですが、
<code>Nullable</code>属性の引数が配列になります。
例えば以下のようなメソッドを考えます。</p>
<pre class="source" title="引数がジェネリックな型の場合">
<code><span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>(
    <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="reserved">string</span>?&gt; <span class="variable">a</span>,
    <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="reserved">string</span>?&gt;? <span class="variable">b</span>,
    (<span class="reserved">string</span>, <span class="reserved">string</span>, <span class="reserved">string</span>?) <span class="variable">c</span>
    ) { }
</code></pre>
<p><code>Dictionary</code>型やタプルの型引数1個1個で null 許容性が違います。
また、「<code>Dictionary</code> 自体」と「<code>Dictionary</code> の型引数」でも null 許容性が違っています。
こういう場合には、以下のような属性が付きます。</p>
<pre class="source" title="引数がジェネリックな型の場合の Nullable 属性">
<code><span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>(
    [<span class="type">Nullable</span>(<span class="reserved">new</span> <span class="reserved">byte</span>[] { 1, 1, 2 })]
    <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="reserved">string</span>?&gt; <span class="variable">a</span>,
    [<span class="type">Nullable</span>(<span class="reserved">new</span> <span class="reserved">byte</span>[] { 2, 1, 2 })]
    <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="reserved">string</span>?&gt;? <span class="variable">b</span>,
    [<span class="type">Nullable</span>(<span class="reserved">new</span> <span class="reserved">byte</span>[] { 0, 1, 1, 2 })]
    (<span class="reserved">string</span>, <span class="reserved">string</span>, <span class="reserved">string</span>?) <span class="variable">c</span>
    ) { }
</code></pre>
<p>配列の最初の要素が型自体で、2個目以降が型引数の null 許容性を表しています。</p>
<p>ちなみに、この他いくつか細かい条件を上げると以下のようなものがあります
(公式ドキュメント: <a href="https://github.com/dotnet/roslyn/blob/master/docs/features/nullable-metadata.md">Nullable Metadata</a>)。</p>
<ul>
<li>非ジェネリックな値型には属性は付けない</li>
<li>ジェネリックな値型の場合、0 に続けて型引数の値を並べる</li>
<li>型引数が値型のところはスキップ</li>
<li>配列中のすべて要素が同じ値のとき、配列ではなく1要素に置き換える</li>
<li>タプルには元となる<code>ValueTuple</code>構造体に準じた属性を付ける</li>
</ul>
<h3><a id="reflection">Nullable 属性とリフレクション</h3>
<p>これで、プログラムのサイズはだいぶ小さくなっています。
しかし、すでに察している人もいるかもしれませんが、
その分、<a href="/study/csharp/sp_reflection.html">リフレクション</a>で null 許容かどうかを取るのがだいぶ面倒になります。</p>
<p>例えば、前述のクラス <code>A</code>、<code>B</code> のメソッド <code>M1</code> の引数を調べたい場合を考えます。
(<code>M1</code> に関連する部分を抜粋して再掲します。)</p>
<pre class="source" title="型に NullableContext が付いた結果(M1 がらみを抜粋)">
<code>[<span class="type">NullableContext</span>(1)]
<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
}
 
[<span class="type">NullableContext</span>(2)]
<span class="reserved">class</span> <span class="type">B</span>
{
    [<span class="type">NullableContext</span>(1)]
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M1</span>(<span class="reserved">string</span> <span class="variable">a</span>) { }
}
</code></pre>
<p>ここで、引数 <code>a</code> が null 許容かどうか調べようとするとき、</p>
<ul>
<li>どちらも引数 <code>a</code> 自体には属性が付いていない</li>
<li>メソッドには <code>B</code> の <code>M1</code> にだけ属性が付いている</li>
<li><code>A</code> の場合は型までたどらないと引数 <code>a</code> の null 許容性がわからない</li>
</ul>
<p>ということになります。</p>
<!-- pageBreak -->
<h2><a id="null-forgiving">! 演算子</h2>
<p>null 許容なものを、<code>is null</code> や <code>== null</code> などによるチェック抜きで、
強制的に非 null 扱いしたい場合があります。
原因としては2つあって、以下のような場面で「強制非 null 扱い」が必要になります。</p>
<ul>
<li>コンストラクターの時点では非 null 保証が絶対にできない(後からの初期化が必須になる)場合がある</li>
<li>フロー解析の未熟さからコンパイラーが判定しきれない場合がある</li>
</ul>
<p>前者のわかりやすい例は循環参照がある場合です。
お互いにインスタンスを持ち合う必要がある場面では、どちらか片方は絶対にコンストラクターよりも後でないとインスタンスを渡せません。</p>
<pre class="source" title="循環参照があるとき、コンストラクターでは非 null 保証ができない">
<code><span class="reserved">class</span> <span class="type">PairedNode</span>
{
    <span class="comment">// このプロパティに対する警告が消せない。</span>
    <span class="reserved">public</span> <span class="type">PairedNode</span> <span class="warning">Pairing</span> { <span class="reserved">get</span>; <span class="reserved">private</span> <span class="reserved">set</span>; }
 
    <span class="reserved">public</span> <span class="reserved">static</span> (<span class="type">PairedNode</span> a, <span class="type">PairedNode</span> b) <span class="method">Create</span>()
    {
        <span class="reserved">var</span> <span class="variable">a</span> = <span class="reserved">new</span> <span class="type">PairedNode</span>();
 
        <span class="comment">// 後から作る方は new の時点でインスタンスを受け取れる。</span>
        <span class="comment">// なのでやろうと思えばコンストラクターにも渡せる。</span>
        <span class="reserved">var</span> <span class="variable">b</span> = <span class="reserved">new</span> <span class="type">PairedNode</span> { Pairing = <span class="variable">a</span> };
 
        <span class="comment">// でも、先に作った方にはどうしても後からの指しなおしが必要。</span>
        <span class="variable">a</span>.Pairing = <span class="variable">b</span>;
 
        <span class="control">return</span> (<span class="variable">a</span>, <span class="variable">b</span>);
    }
}
</code></pre>
<p>後者の例は、例えば <code>ReferenceEquals</code> とかです。
null に関するフロー解析は結構ぎりぎりまで作業をしているようで、
<code>ReferenceEquals</code> に関する解析は Visual Studio 16.3 Preview 1 (2019年7月)時点では未対応、
Preview 2 (同8月) 時点で初めて対応しました。</p>
<pre class="source" title="ReferenceEquals でも等価チェックになるはずなのに">
<code><span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">x</span>, <span class="reserved">string</span>? <span class="variable">y</span>)
{
    <span class="control">if</span> (<span class="method">ReferenceEquals</span>(<span class="variable">x</span>, <span class="variable">y</span>))
    {
        <span class="comment">// x == y なら警告が消えるのに、ReferenceEquals だと残ってた。</span>
        <span class="comment">// 16.3 Preview 1 の時点では警告あり、Preview 2 から消える。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="warning"><span class="variable">y</span></span>.Length);
    }
}
</code></pre>
<p>この例はまだ需要もあって対処も楽な類なので対応されましたが、
もっとレアだったり、対処にコストがかかりすぎる場合は対応してもらえない可能性が高いです。</p>
<p>要するに、null がらみのフロー解析には無理なもの・やっても割に合わないものがざらにあるので、
フロー解析をあえて抑止するような手段が必要になります。</p>
<p>そこで用意されているのが後置き <code>!</code> 演算子です。
<code>a!</code> というように、式の後ろに <code>!</code> を付けると、式 <code>a</code> の null 許容性は無視して常に非 null 扱いになります。</p>
<pre class="source" title="! を付けて強制非 null 扱い">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">PairedNode</span>
{
    <span class="comment">// null を無理やり非 null 扱いにして警告を消す。</span>
    <span class="comment">// (省略したものの前述の) Create の中で自己責任で非 null を保証してるので大丈夫。</span>
    <span class="reserved">public</span> <span class="type">PairedNode</span> Pairing { <span class="reserved">get</span>; <span class="reserved">private</span> <span class="reserved">set</span>; } = <em><span class="reserved">null</span>!</em>;
}
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">x</span>, <span class="reserved">string</span>? <span class="variable">y</span>)
    {
        <span class="control">if</span> (<span class="method">ReferenceEquals</span>(<span class="variable">x</span>, <span class="variable">y</span>))
        {
            <span class="comment">// string? だけども気にせずメンバー アクセスする。</span>
            <span class="comment">// コンパイラーにはわからないかもしれないけども、人間はこの時点で y が非 null なことを知っている。</span>
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">y</span><em>!</em>.Length);
        }
    }
}
</code></pre>
<p>この <code>!</code> 演算子は null forgiving (null に寛大)演算子とか、
null suppression (null 抑止) 演算子などと呼ばれています。
コンパイラーが厳しく(ただ、過剰に)チェックしてくれているものを、あえて緩めておおらかにコードを書く「回避策」的なものなのでこんな呼び名になっています。</p>
<p>(ただ、最近、C# のドキュメントは結構ぎりぎりになるまで正式な用語決定をしないので、
この呼称も最後までこのままかどうかはわかりません。「通称」になる可能性あり。)</p>
<p>ちなみに、<code>!</code> 演算子は英語で口頭だと bang operator とか言ったりもするみたいです。
(bang は破裂音の擬音語。「バンと音を立ててびっくりさせる」から、ビックリマークのことを bang と読んだりするそうです。)</p>
<p>(他のプログラミング言語では、「(コンパイラーには無理な) null 判定をプログラマーが明示する」という意味で not-null assertion (非 null 表明)と言ったり、
「強制的に非 null にしてしまう」という意味で force unwrap (強制アンラップ)と言ったりします。)</p>
<p><code>!</code> 演算子を使うと本当に自己責任になります。
フロー解析の対象から外れて、<code>NullReferenceException</code> を起こす可能性が出てきます。
また、<code>!</code> を書いた地点には特に何も実行時チェックが入りません。
実際に <code>NullReferenceException</code> を起こすのはメンバー アクセスした瞬間です。
問題の真の原因と、例外が発生する場所がずれるので注意が必要です。</p>
<pre class="source" title="! 演算子を誤用するとそれなりに面倒事を起こす例">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// 悪用して、本当に null を渡してはいけないところに null を渡す。</span>
        <span class="comment">// この時点では例外が出ない。</span>
        <span class="method">M</span>(<span class="reserved">null</span>!);
    }
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">x</span>)
    {
        <span class="comment">// 実際に NullReferenceException を起こすのは以下の行。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span>.Length);
    }
}
</code></pre>
<p>ちなみに、2重に <code>!</code> を付けようとするとコンパイル エラーになります。
例えば以下のコードは<code>x!!</code> のところでコンパイル エラーが出ます。</p>
<pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">string</span>? <span class="variable">x</span>)
{
    <span class="reserved">var</span> <span class="variable">y</span> = <span class="error"><span class="variable">x</span></span>!!;
}
</code></pre>
<h2><a id="type-constraints">ジェネリクス</h2>
<p><a href="?p=1#nvt-defference">前述の通り</a>、
null 許容型の <code>T?</code> は参照型と値型でだいぶ実装方法が違います。
これで特に問題になるのは<a href="/study/csharp/sp2_generics.html">ジェネリクス</a>です。
型引数には参照型が渡される場合も値型が渡される場合もあって、
そういうときに <code>T?</code> の扱いに困ります。</p>
<p>扱いに困るというか、C# 8.0 では制約なしでは <code>T?</code> とは書けませんでした。
以下のコードはコンパイル エラーになります。
(後述しますが、C# 9.0 でもこの書き方には注意が必要です。)</p>
<pre class="source" title="制約なしの型引数 T に対して T? は使えない">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">class</span> <span class="type">Generic</span>&lt;<span class="type">T</span>&gt;
{
    <span class="comment">// T? と書くと C# 8.0 ではコンパイル エラー。</span>
    <span class="reserved">public</span> <span class="error"><span class="type">T</span></span>? <span class="method">M</span>() =&gt; <span class="reserved">default</span>;
}
</code></pre>
<p>一方、<code>struct</code> 制約や <code>class</code> 制約、基底クラス制約を付けると <code>T?</code> と書けるようになります。
<code>struct</code> 制約は <a href="/study/csharp/sp2_nullable.html">null 許容値型</a>の仕様によるもので、C# 2.0 の頃から書けます。
「制約に単に <code>class</code> と書くと非 null の意味になる」というのが新仕様になります。</p>
<pre class="source" title="制約を付けて T? を使えるようにできる例">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System;
 
<span class="comment">// struct 制約を付けると null 許容&quot;値型&quot;を使えるようになる。</span>
<span class="reserved">class</span> <span class="type">StructConstraint</span>&lt;<span class="type">T</span>&gt; <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span>
{
    <span class="reserved">public</span> <span class="type">T</span>? <span class="method">M</span>() =&gt; <span class="reserved">default</span>;
}
 
<span class="comment">// class 制約は「非 null 参照型」の意味の制約になる。</span>
<span class="comment">// なので T? と書いて null 許容&quot;参照&quot;型を作れるようになる。</span>
<span class="reserved">class</span> <span class="type">ClassConstraint</span>&lt;<span class="type">T</span>&gt; <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span>
{
    <span class="reserved">public</span> <span class="type">T</span>? <span class="method">M</span>() =&gt; <span class="reserved">null</span>;
}
 
<span class="comment">// 基底クラス制約も「非 null」扱い。</span>
<span class="reserved">class</span> <span class="type">BaseTypeConstarint</span>&lt;<span class="type">T</span>&gt; <span class="reserved">where</span> <span class="type">T</span> : <span class="type">Exception</span>
{
    <span class="reserved">public</span> <span class="type">T</span>? <span class="method">M</span>() =&gt; <span class="reserved">null</span>;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// class 制約を満たしてる。</span>
        <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">ClassConstraint</span>&lt;<span class="reserved">string</span>&gt;();
 
        <span class="comment">// class 制約は「非 null」扱いなので以下のコードには警告あり。</span>
        <span class="reserved">var</span> <span class="variable">y</span> = <span class="reserved">new</span> <span class="type">ClassConstraint</span>&lt;<span class="warning"><span class="reserved">string</span>?</span>&gt;();
    }
}
</code></pre>
<p>その代わり、<code>class</code>、基底クラス制約に <code>?</code> を付けることで null 許容参照型を受け付けることができます。</p>
<pre class="source" title="">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System;
 
<span class="comment">// class? 制約で「null 許容参照型」を表す。</span>
<span class="reserved">class</span> <span class="type">ClassConstraint</span>&lt;<span class="type">T</span>&gt; <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span>?
{
    <span class="comment">// class? な型 T をさらに T? にはできず、コンパイル エラーになる。</span>
    <span class="reserved">public</span> <span class="error"><span class="type">T</span></span>? <span class="method">M</span>() =&gt; <span class="reserved">null</span>;
}
 
<span class="comment">// 基底クラス制約でも ? を使って null 許容にできる。</span>
<span class="reserved">class</span> <span class="type">BaseTypeConstarint</span>&lt;<span class="type">T</span>&gt; <span class="reserved">where</span> <span class="type">T</span> : <span class="type">Exception</span>?
{
    <span class="comment">// この行がコンパイル エラーになるのは class? 制約と同じ。</span>
    <span class="reserved">public</span> <span class="error"><span class="type">T</span></span>? <span class="method">M</span>() =&gt; <span class="reserved">null</span>;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// class? 制約なので特に警告なし。</span>
        <span class="reserved">var</span> <span class="variable">y</span> = <span class="reserved">new</span> <span class="type">ClassConstraint</span>&lt;<span class="reserved">string</span>?&gt;();
    }
}
</code></pre>
<h3><a id="notnull">notnull 制約</h3>
<p>また、新たに <code>notnull</code> 制約というものが追加されて、
非 null 参照型もしくは非 null 値型のみを受け付けることができます。</p>
<pre class="source" title="notnull 制約">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
 
<span class="reserved">class</span> <span class="type">NotNullConstraint</span>&lt;<span class="type">T</span>&gt;
    <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">notnull</span>
{
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// この2行は OK。</span>
        <span class="reserved">var</span> <span class="variable">ok1</span> = <span class="reserved">new</span> <span class="type">NotNullConstraint</span>&lt;<span class="reserved">int</span>&gt;();
        <span class="reserved">var</span> <span class="variable">ok2</span> = <span class="reserved">new</span> <span class="type">NotNullConstraint</span>&lt;<span class="reserved">string</span>&gt;();
 
        <span class="comment">// この2行には警告が出る。</span>
        <span class="reserved">var</span> <span class="variable">ng1</span> = <span class="reserved">new</span> <span class="type">NotNullConstraint</span>&lt;<span class="warning"><span class="reserved">int</span>?</span>&gt;();
        <span class="reserved">var</span> <span class="variable">ng2</span> = <span class="reserved">new</span> <span class="type">NotNullConstraint</span>&lt;<span class="warning"><span class="reserved">string</span>?</span>&gt;();
    }
}
</code></pre>
<p>例えば、<code>Dictionary&lt;TKey, TValue&gt;</code> (<code>System.Collections.Generic</code>名前空間)のキーは元々 null を受け付けていません。<code>d[null] = 0</code> みたいな書き方をすると null 参照例外が発生します。
なので、.NET Core 3.0 の <code>Dictionary</code> の <code>TKey</code> には <code>notnull</code> 制約が付いています。
<code>new Dicitionary&lt;int?, string&gt;()</code> みたいに書くと警告が出るようになります。</p>
<p>ただ、C# 8.0 では <code>notnull</code> 制約を付けてもなお、<code>T?</code> とは書けません。
(参照型と値型での null 許容の仕様の差が大きすぎてちょっと難しいようです。
もし実現しようと思うなら、C# コンパイラーのレベルでは無理で、.NET ランタイムの型システム レベルでの改修が必要。)</p>
<pre class="source" title="notnull を付けても T? とは書けない">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
 
<span class="reserved">class</span> <span class="type">NotNullConstraint</span>&lt;<span class="type">T</span>&gt;
    <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">notnull</span>
{
    <span class="comment">// 以下の2行はコンパイル エラーになる。</span>
    <span class="error"><span class="type">T</span>?</span> <span class="method">M</span>() =&gt; <span class="error"><span class="reserved">null</span></span>;
    <span class="reserved">int</span> <span class="method">M</span>(<span class="error"><span class="type">T</span>?</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">null</span> ? 0 : <span class="variable">x</span>.<span class="method">GetHashCode</span>();
}
</code></pre>
<p>一応、<a href="#annotation-attributes">次節</a>で説明する属性を使ってある程度の問題回避はできます。</p>
<pre class="source" title="アノテーション属性(次節で説明)で問題回避">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System.Diagnostics.CodeAnalysis;
 
<span class="reserved">class</span> <span class="type">NotNullConstraint</span>&lt;<span class="type">T</span>&gt;
    <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">notnull</span>
{
    <span class="comment">// T? と書けないことに対する代替手段。</span>
    [<span class="reserved">return</span>: <span class="type">MaybeNull</span>] <span class="reserved">public</span> <span class="type">T</span> <span class="method">M</span>() =&gt; <span class="reserved">default</span>!;
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="method">M</span>([<span class="type">AllowNull</span>] <span class="type">T</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">null</span> ? 0 : <span class="variable">x</span>.<span class="method">GetHashCode</span>();
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">NotNullConstraint</span>&lt;<span class="reserved">string</span>&gt;();
        <span class="reserved">string</span>? <span class="variable">nullable</span> = <span class="variable">x</span>.<span class="method">M</span>(); <span class="comment">// string M() だけど null が返ってくる。</span>
        <span class="variable">x</span>.<span class="method">M</span>(<span class="reserved">null</span>); <span class="comment">// M(string) だけど null を渡せる。</span>
    }
}
</code></pre>
<h3><a id="unconstrained-generics">制約なしジェネリック型引数</h3>
<h5 class="version version9">Ver. 9</h5>
<p>C# 9.0 で、制約なしのジェネリック型引数 <code>T</code> に対して <code>T?</code> と書けるようになりました。
ジェネリクスの話の冒頭で「C# 8.0 ではエラーになる」と説明した以下のコードが C# 9.0 では有効です。</p>
<pre class="source" title="C# 9.0 で有効になったコード">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">class</span> <span class="type">Generic</span>&lt;<span class="type">T</span>&gt;
{
    <span class="comment">// C# 9.0 では一応 T? と書ける。</span>
    <span class="reserved">public</span> <span class="type">T</span>? <span class="method">M</span>() =&gt; <span class="reserved">default</span>;
}
</code></pre>
<p>「一応」と言っているのは、この <code>T?</code> にはちょっと注意が必要だからです。
前述のとおり、<code>T?</code> は内部実装的に、値型(構造体など)と参照型(クラスなど)とで結構差があって、
その影響で素直に「nullable (null 許容)」と言えるものになっていません。</p>
<p>どちらかというと「defaultable (<a href="/study/csharp/resource/rm_struct/#default">規定値</a>になる可能性がある)」というべきで、
以下のように、<code>T?</code> であっても null にはならない(規定値の 0 になる)ことがあります。</p>
<pre class="source" title="ジェネリックな T? はどちらかというと「defaultable」">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
 
<span class="reserved">using</span> System;
 
<span class="comment">// この2つに関しては default == null なので変なことにはならない。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">M</span>&lt;<span class="reserved">string</span>?&gt;()); <span class="comment">// null</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">M</span>&lt;<span class="reserved">string</span>&gt;()); <span class="comment">// null</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">M</span>&lt;<span class="reserved">int</span>?&gt;()); <span class="comment">// null</span>
 
<span class="comment">// 問題が非 null 値型で、この場合 default != null なのでちょっと変。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">M</span>&lt;<span class="reserved">int</span>&gt;()); <span class="comment">// 0</span>
 
<span class="comment">// ジェネリックな T? は nullable じゃなくて defaultable。</span>
<span class="comment">// default を渡しても警告にならない。 </span>
<span class="reserved">static</span> <span class="type">T</span>? <span class="method">M</span>&lt;<span class="type">T</span>&gt;() =&gt; <span class="reserved">default</span>;
</code></pre>
<p>これはちょっと罠になるので、検討当初は <code>T??</code> みたいな文法で「nullable」と「defaultable」を区別しようかという案も出ていました。
ただ、これはこれで、<a href="/study/csharp/rm_nullusage.html#null-coalesce"><code>??</code> 演算子</a>との区別が付かなくて困る場面があるということで断念されました。
他に新しい記号を導入するのも微妙で、結局、「<code>T?</code> で defaultable 扱い」という決定が下りました。</p>
<h2><a id="default-constraint">default 制約</h2>
<h5 class="version version9">Ver. 9</h5>
<p><a href="#unconstrained-generics">前節の制約なし型引数</a>のせいなんですが、
ちょっと限定的な状況でだけ必要となる制約として、<code>default</code> 制約というものも増えました。</p>
<p><code>default</code> 制約が必要になるのは以下のような状況です。</p>
<pre class="source" title="default 制約">
<code><span class="inactive">#nullable</span> <span class="inactive">disable</span>
 
<span class="comment">// さかのぼること、null 許容参照型導入前にから以下のような書き方ができた。</span>
<span class="reserved">class</span> <span class="type">Csharp7</span>
{
    <span class="comment">// これは Nullable&lt;T&gt; の意味に。</span>
    <span class="reserved">public</span> <span class="type">T</span>? <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span>? <span class="variable">x</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span> =&gt; <span class="reserved">null</span>;
 
    <span class="comment">// T と Nullable&lt;T&gt; は別の型扱いなのでオーバーロード可能。</span>
    <span class="reserved">public</span> <span class="type">T</span> <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">x</span>) =&gt; <span class="reserved">default</span>;
}
 
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
 
<span class="comment">// ここで、null 許容参照型を有効化。</span>
<span class="comment">// 特に、C# 9.0 では制約なし型引数に対して T? と書けるようになったので…</span>
<span class="reserved">class</span> <span class="type">Base</span>
{
    <span class="comment">// これは Nullable&lt;T&gt; の意味に。</span>
    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="type">T</span>? <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span>? <span class="variable">t</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span> =&gt; <span class="reserved">null</span>;
 
    <span class="comment">// これは C# 9.0 の制約なし型引数に対する null 許容(正確には default 許容)アノテーション。</span>
    <span class="comment">// T と Nullable&lt;T&gt; 違いのオーバーロードという扱いになる。</span>
    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="type">T</span>? <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span>? <span class="variable">t</span>) =&gt; <span class="reserved">default</span>;
}
 
<span class="comment">// さらに紛らわしいのが↑を override したときで…</span>
<span class="reserved">class</span> <span class="type">Derived</span> : <span class="type">Base</span>
{
    <span class="comment">// これ、実は Nullable&lt;T&gt; の意味。</span>
    <span class="comment">// 親クラス側の where T : struct 制約を自動的に引き継いでしまう。</span>
    <span class="comment">// こうしないと C# 8.0 以前との整合性が取れないとのこと。</span>
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="type">T</span>? <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span>? <span class="variable">t</span>) =&gt; <span class="reserved">null</span>;
 
    <span class="comment">// ということで、制約なし T? の方を参照するために別の制約が必要になったという経緯があり。</span>
    <span class="comment">// override 時に限り、where T : struct じゃない方に、逆に where T : default という制約を書く必要がある。</span>
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="type">T</span>? <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span>? <span class="variable">t</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">default</span> =&gt; <span class="reserved">default</span>;
}
</code></pre>
<p>まとめると、</p>
<ul>
<li>古いバージョンとの互換性のため、ジェネリック型引数に対して <code>T</code> と <code>T?</code> は別の型になっている</li>
<li>基底クラス側で <code>where T : struct</code> と書いているものは、派生クラスでは改めて <code>where T : struct</code> と書かなくてもいい仕様だった</li>
<li>C# 9.0 で制約なし型引数に対しても <code>T?</code> と書けるようになったことで、派生クラス側の挙動が怪しくなった</li>
<li>この問題を回避するため、派生クラス側には <code>where T : default</code> という制約を書く必要がある</li>
</ul>
<p>という感じです。
前節で説明した通り、制約なしの型引数に対する <code>T?</code> は「null 許容」というよりは「default 許容」(defaultable)なので、<code>where T : default</code> というキーワードを用います。</p>
<!-- pageBreak -->
<h2><a id="annotation-attributes">アノテーション属性</h2>
<p><a href="?p=3#type-constraints">前節</a>のジェネリクスの問題を筆頭に、
いくつか、<code>T?</code> という記法だけでは解決できない問題があります。
ジェネリックな型でなくても例えば以下のような場合に、<code>?</code> の有無だけではフロー解析がうまく働きません。</p>
<ul>
<li>プロパティの get と set で null 許容性が違う場合がある</li>
<li><a href="/study/csharp/sp_ref.html#sec-byref">参照引数</a>で、「null が渡ってきてもいいけど、非 null な値で必ず上書きする」みたいな挙動があり得る</li>
<li><code>TryGetValue</code> のように、戻り値が true の時だけ非 null な値を返す<a href="/study/csharp/sp_ref.html#out">出力引数</a>がある</li>
<li>「引数が null の場合に限り戻り値も null」みたいな場合がある</li>
</ul>
<p>こういう場合への対処としていくつか、<a href="/study/csharp/sp_attribute.html">属性</a>によってフロー解析を制御する手段が用意されています。
いずれの属性も<code>System.Diagnostics.CodeAnalysis</code>名前空間で定義されています。</p>
<table>
<caption>.NET Core 3.0 からあるもの</caption>
<tr>
<th>分類</th><th>属性名</th><th>概要</th>
</tr>
<tr>
<td rowspan="2">事前条件</td>
<td><code>AllowNull</code></td>
<td>(<code>T</code> であっても)入力として null を受け付ける</td>
</tr>
<tr>
<td><code>DisallowNull</code></td>
<td>(<code>T?</code> であっても)入力として null を受け付けない</td>
</tr>
<tr>
<td rowspan="2">事後条件</td>
<td><code>MaybeNull</code></td>
<td>(<code>T</code> であっても)出力として null を返す</td>
</tr>
<tr>
<td><code>NotNull</code></td>
<td>(<code>T?</code> であっても)出力として null を返さない<sup>※</sup></td>
</tr>
<tr>
<td rowspan="2">条件付き<br/>事後条件</td>
<td><code>MaybeNullWhen</code></td>
<td>戻り値が true/false どちらかの時だけ <code>MaybeNull</code> 使い</td>
</tr>
<tr>
<td><code>NotNullWhen</code></td>
<td>戻り値が true/false どちらかの時だけ <code>NotNull</code> 使い</td>
</tr>
<tr>
<td>null 依存性</td>
<td><code>NotNullIfNotNull</code></td>
<td>引数が null の時に限り戻り値が null</td>
</tr>
<tr>
<td rowspan="2">フロー</td>
<td><code>DoesNotReturn</code></td>
<td>このメソッドを呼んだらもう戻ってこないという意味で、それ以降のフロー解析をしない</td>
</tr>
<tr>
<td><code>DoesNotReturnIf</code></td>
<td>引数が true/false どちらかの時だけ <code>DoesNotReturn</code> 扱い</td>
</tr>
</table>
<table>
<caption>.NET 5 からあるもの</caption>
<tr>
<th>分類</th><th>属性名</th><th>概要</th>
</tr>
<tr>
<td rowspan="2">他のメンバー</td>
<td><code>MemberNotNull</code></td>
<td>この属性が付いたメンバーを呼んだ時点で、他のメンバーの非 null が確定する</td>
</tr>
<tr>
<td><code>MemberNotNullWhen</code></td>
<td>この属性が付いたメンバーを呼ばれて、かつ、戻り値が特定の値だった時点で、他のメンバーの非 null が確定する</td>
</tr>
</table>
<p><sup>※</sup> <a href="/study/csharp/sp_ref.html#out"><code>out</code>引数</a>に対しては「メソッド内で非 null な値を代入している」、
通常の引数や<a href="/study/csharp/sp_ref.html#in"><code>in</code>引数</a>に対しては「もし null が渡ってきたら例外を出すなど、それ以降の処理を続行させない」という扱い。</p>
<h3><a id="attribute-usage">アノテーション属性の利用例</h3>
<p>これらの属性が必要になる具体例をいくつか紹介していきましょう。</p>
<h4>Array.Resize (NotNull)</h4>
<p>まず、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.array.resize"><code>Array.Resize</code></a> は配列の長さを変更するメソッドですが、参照引数で null を受け付けはするものの、絶対に非 null なインスタンスを作って渡します。そこで、以下のように、<code>NotNull</code> 属性が付いています。</p>
<pre class="source" title="ref の入力と出力で null 許容性が違う例">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Array</span>
{
    <span class="comment">// null を受け付けるけど、返しはしない。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Resize</span>&lt;<span class="type">T</span>&gt;([<span class="type">NotNull</span>] <span class="reserved">ref</span> <span class="type">T</span>[]? <span class="variable">array</span>, <span class="reserved">int</span> <span class="variable">newSize</span>);
}
</code></pre>
<p>その結果、以下のようなコードが書けます。</p>
<pre class="source" title="Array.Resize の AllowNull の効果">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// null を渡せる。</span>
        <span class="reserved">int</span>[]? <span class="variable">array</span> = <span class="reserved">null</span>;
        <span class="type">Array</span>.<span class="method">Resize</span>(<span class="reserved">ref</span> <span class="variable">array</span>, 4);
 
        <span class="comment">// でも、呼び出し後は非 null 保証がある。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">array</span>.Length); <span class="comment">// 警告なし</span>
    }
}
</code></pre>
<h4>TextWriter.NewLine (AllowNull)</h4>
<p><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.io.textwriter.newline"><code>TextWriter.NewLine</code></a> は get で null を返すことはありません。
しかし、「null を set すると <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.io.textwriter.newline"><code>Environment.NewLine</code></a> を使う」という仕様があって、set だけが null 許容です。
そこで、以下のように、<code>AllowNull</code> が付いています。
(<code>AllowNull</code> は意味としては「入力(引数とか)に <code>null</code> を許す」なので、プロパティに付けると <code>set</code> の <code>value</code> が nullable の意味になるみたいです。)</p>
<pre class="source" title="set と get で null 許容性が違う例">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">TextWriter</span>
{
    [<span class="type">AllowNull</span>] <span class="comment">// set だけ null 許容</span>
    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="reserved">string</span> NewLine
    {
        <span class="reserved">get</span> =&gt; ...
        <span class="reserved">set</span> =&gt; ...
    }
}
</code></pre>
<h4>ジェネリック型引数に対するアノテーション (MeybeNull)</h4>
<p>ジェネリクス都合で <code>T?</code> と書けない問題を <code>MaybeNull</code> 属性で回避している例としては
<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.compilerservices.strongbox-1.value"><code>StrongBox&lt;T&gt;.Value</code></a>や<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.threadlocal-1.value"><code>ThreadLocal&lt;T&gt;.Value</code></a>などがあります。</p>
<pre class="source" title="ジェネリクス都合で MaybeNull">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">StrongBox</span>&lt;<span class="type">T</span>&gt;
{
    [<span class="type">MaybeNull</span>] <span class="reserved">public</span> <span class="type">T</span> Value =&gt; ...
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">ThreadLocal</span>&lt;<span class="type">T</span>&gt;
{
    [<span class="type">MaybeNull</span>] <span class="reserved">public</span> <span class="type">T</span> Value =&gt; ...
}
</code></pre>
<h4>Try メソッド (NotNullWhen)</h4>
<p>.NET には名前が <code>Try</code> から始まって、処理の成否を <code>bool</code> で返すメソッドが結構多いですが、
こういう場合「戻り値が true の時だけ null でない値を取れる」ということが多いです。
例えば、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.version.tryparse">Version.TryParse</a>が該当します。
また、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.string.isnullorempty"><code>string.IsNullEmpty</code></a> のように、他の処理と兼ねて null チェックしているものがあります。
こういう場合に <code>NotNullWhen</code> などの条件付き事後条件を使います。</p>
<pre class="source" title="条件付き事後条件の例">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Version</span>
{
    <span class="comment">// 戻り値が true の時には非 null 値を version 変数に入れて返す。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">TryParse</span>(
        <span class="reserved">string</span>? <span class="variable">input</span>,
        [<span class="type">NotNullWhen</span>(<span class="reserved">true</span>)] <span class="reserved">out</span> <span class="type">Version</span>? <span class="variable">version</span>);
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">String</span>
{
    <span class="comment">// 中で null チェックをしているので、true を返すなら value は非 null とわかる。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">IsNullOrEmpty</span>([<span class="type">NotNullWhen</span>(<span class="reserved">false</span>)] <span class="reserved">string</span>? <span class="variable">value</span>);
}
</code></pre>
<h4>null 伝搬 (NotNullIfNotNull)</h4>
<p><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.io.path.getfilename">Path.GetFileName</a>など、単純に null を伝搬する(null が来たら素通しで null を返す)ようなメソッドも多いです。
また、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.volatile.read">Volatile.Read</a>/<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.volatile.write">Write</a>のように、引数の値を戻り値や他の参照引数に伝搬するものがあって、値の伝搬によって null 許容性も伝搬します。
こういう場合に使うのが <code>NotNullIfNotNull</code> 属性です。</p>
<pre class="source" title="null 許容性の伝搬">
<code><span class="reserved">class</span> <span class="type">Path</span>
{
    <span class="comment">// 引数が null のとき、戻り値に null を素通しする仕様。</span>
    [<span class="reserved">return</span>: <span class="type">NotNullIfNotNull</span>(<span class="string">&quot;path&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">string</span>? <span class="method">GetFileName</span>(<span class="reserved">string</span>? <span class="variable">path</span>);
}
 
<span class="reserved">class</span> <span class="type">Volatile</span>
{
    <span class="comment">// location に value を書き込むメソッドなので、value の null 判定が location に伝搬。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Write</span>&lt;<span class="type">T</span>&gt;([<span class="type">NotNullIfNotNull</span>(<span class="string">&quot;value&quot;</span>)] <span class="reserved">ref</span> <span class="type">T</span> <span class="variable">location</span>, <span class="type">T</span> <span class="variable">value</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span>?;
 
    <span class="comment">// location に入っている値をそのまま返すメソッドなので、location の null 判定が戻り値に伝搬。</span>
    [<span class="reserved">return</span>: <span class="type">NotNullIfNotNull</span>(<span class="string">&quot;location&quot;</span>)]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">T</span> <span class="method">Read</span>&lt;<span class="type">T</span>&gt;(<span class="reserved">ref</span> <span class="type">T</span> <span class="variable">location</span>) <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span>?;
}
</code></pre>
<p>(ちなみに、この例の <code>&quot;path&quot;</code> や <code>&quot;location&quot;</code> は <code>nameof(path)</code>、<code>nameof(location)</code> と書きたいところですが、<a href="/study/csharp/st_string.html#nameof-operator"><code>nameof</code> 演算子</a>の仕様上、メソッドの外から引数を参照することは残念ながらできません。
この <code>NotNullIfNotNull</code> 属性によってそれなりに強い需要が生じてしまったので修正が入る可能性はありますが、破壊的変更になりそうなのであんまり期待はできません。)</p>
<h4>FailFast (DoesNotReturn)</h4>
<p>一部のメソッドは、そのメソッドを呼んだら最後、もう絶対に正常には戻ってこないものがあります。例えば<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.environment.failfast">Environment.FailFast</a>はプログラムを即座に止めてしまう(おかしな状態のままプログラムが進むよりは、一思いにクラッシュした方がマシな場面で使う)メソッドなので、このメソッドの呼び出しから後ろが実行されることは絶対にありません。
こういう場合、フロー解析もそのメソッドまでで止めてしまいたく、そのために使う属性が <code>DoesNotReturn</code> です。</p>
<pre class="source" title="呼んだら最後、絶対に戻ってこないメソッド">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Environment</span>
{
    [<span class="type">DoesNotReturn</span>]
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">FailFast</span>(<span class="reserved">string</span> <span class="variable">message</span>);
}
</code></pre>
<p>これは以下のような使い方を想定しています。</p>
<pre class="source" title="DoesNotReturn 付きメソッドの利用例">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">string</span>? <span class="variable">s</span>)
{
    <span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> <span class="reserved">null</span>)
    {
        <span class="type">Environment</span>.<span class="method">FailFast</span>(<span class="string">&quot;null は許さない。絶対にだ！&quot;</span>);
    }
 
    <span class="comment">// null だったら FailFast 行きで、FailFast は DoesNotReturn なので、</span>
    <span class="comment">// ここに来た時点で s は非 null な保証がある。</span>
    <span class="control">return</span> <span class="variable">s</span>.Length;
}
</code></pre>
<p>プログラムのクラッシュの他、絶対に例外を出すことがわかっているメソッドにも <code>DoesNotReturn</code> 属性が使えます。</p>
<pre class="source" title="絶対に例外を出すメソッドにも DoesNotReturn が使える">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">string</span>? <span class="variable">s</span>)
{
    <span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> <span class="reserved">null</span>)
    {
        <span class="method">Throw</span>(<span class="reserved">nameof</span>(<span class="variable">s</span>));
    }
 
    <span class="control">return</span> <span class="variable">s</span>.Length;
}
 
<span class="comment">// throw はインライン展開を阻害するのでここだけメソッドを分離</span>
[<span class="type">DoesNotReturn</span>]
<span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Throw</span>(<span class="reserved">string</span> <span class="variable">name</span>) =&gt; <span class="control">throw</span> <span class="reserved">new</span> <span class="type">ArgumentNullException</span>(<span class="variable">name</span>);
</code></pre>
<h4>Assert (DoesNotReturnIf)</h4>
<p>同じプログラムのクラッシュでも、条件付きな場合があります。
<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.debug.assert"><code>Debug.Assert</code></a>がわかりやすいでしょう。
このメソッドは引数が false の時に限ってプログラムを止めます。
こういうメソッドに対して使うがの <code>DoesNotReturnIf</code> 属性です。</p>
<pre class="source" title="条件次第で戻ってこなくなるメソッドの例">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Debug</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Assert</span>([<span class="type">DoesNotReturnIf</span>(<span class="reserved">false</span>)] <span class="reserved">bool</span> <span class="variable">condition</span>);
}
</code></pre>
<p>ちなみに、「絶対に戻ってこないからフロー解析をしなくていい」という処理は、
null 許容性の他に<a href="/study/csharp/resource/rm_struct/#definite-assignment">確実な初期化</a>でも使いたいものです。
ただ、<code>DoesNotReturn</code>/<code>DoesNotReturnIf</code> 属性は null に関してしか働きません。
(確実な初期化の方がシビアな判定をすべき(でないとセキュリティ ホールになりえる)もので、
C# コンパイラーのフロー解析だけじゃなく .NET ランタイムのレベルでも検証をしたいけど、そこまで実装する余裕がないからという理由。)</p>
<h2><a id="special-treatment">特殊扱いされるメソッド</h2>
<p>前節で紹介した属性を使うことで、いろいろな状況に対応可能です。
しかし、「属性を使って汎用的に解決するほどの需要がない」ということで、
1つ1つ特別扱いすることでフロー解析しているメソッドがいくつかあります。</p>
<p>以下のようなものが該当します(要するに、<code>==</code> の代用になる類のメソッドです)。</p>
<ul>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.object.equals"><code>object.Equals</code></a></li>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.object.referenceequals"><code>object.ReferenceEquals</code></a></li>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.iequalitycomparer-1.equals"><code>IEqualityComparer&lt;T&gt;.Equals</code></a></li>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.iequatable-1.equals"><code>IEquatable&lt;T&gt;.Equals</code></a></li>
<li><a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.interlocked.compareexchange"><code>Interlocked.CompareExchange</code></a></li>
</ul>
<p>これらはちゃんと、<code>==</code> 演算子と同様、null 許容性を伝搬します。
例えば以下のように、<code>EqualityComparer&lt;T&gt;.Default.Euqlas</code> を使って null チェックができます。</p>
<pre class="source" title="">
<code><span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">EqualityComaprerEquals</span>(<span class="reserved">string</span> <span class="variable">x</span>, <span class="reserved">string</span>? <span class="variable">y</span>)
{
    <span class="comment">// IEqualityComparer.Equals は == と同じ扱いを受ける。</span>
    <span class="control">if</span> (<span class="type">EqualityComparer</span>&lt;<span class="reserved">string</span>&gt;.Default.<span class="method">Equals</span>(<span class="variable">x</span>, <span class="variable">y</span>))
    {
        <span class="comment">// こっちは y が非 null なことがわかるので警告が出ない。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">y</span>.Length);
    }
    <span class="control">else</span>
    {
        <span class="comment">// こっちは null な可能性が残るので警告が出る。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">y</span>.Length);
    }
}
</code></pre>
<h2><a id="gradual">段階的な改善</h2>
<p>null 許容参照型はそれなりの期間を掛けて徐々に完成していく予定です。
以下の2つの意味で、少しずつ警告が増えたり減ったりします。</p>
<ul>
<li>C# コンパイラーのフロー解析の精度が上がる</li>
<li>.NET Core の基本ライブラリに正しくアノテーション属性が付く</li>
</ul>
<p><a href="?p=3#null-forgiving"><code>!</code> 演算子</a>の説明でも出てきましたが、
フロー解析はそれなりに労力がかかり、完璧なものは作れません。
バージョンアップとともに少しずつ精度が上がっていくものと思われます。</p>
<p>ほとんどの場合は「過剰に警告が出てしまっていて、それを <code>!</code> 演算子で抑止している状態」が解消できるもので、
精度が上がれるほど警告が減る方に変化すると思われます。</p>
<h3><a id="array-element">配列の要素のフロー解析</h3>
<p>しかし一部は、もしかすると<em>警告が増える</em>ことが考えられます。</p>
<p>例えば今「抜け穴になっていることはわかっているけど見逃している」状態なのが配列の要素の初期化です。
以下のコードは、フロー解析の漏れであって、可能であれば警告を出したいコードです。
(コンストラクター内で全要素に対して 非 null 初期化しているかどうかまで解析したい。)
しかし、少なくとも C# 8.0 時点では警告を出せません。</p>
<pre class="source" title="C# 8.0 時点でのフロー解析の不足の例">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">ArrayInit</span>
{
    <span class="reserved">string</span>[] _buffer;
 
    <span class="reserved">public</span> <span class="type">ArrayInit</span>()
    {
        <span class="comment">// _buffer 自体には new string[] を代入したけど、その要素には何も代入していない。</span>
        <span class="comment">// C# の仕様上、_buffer[0] は null になってる(おかしい)。</span>
        <span class="comment">// string (? を付けていない)なので null になってはいけないはず。</span>
        _buffer = <span class="reserved">new</span> <span class="reserved">string</span>[1];
    }
 
    <span class="comment">// string[] からの要素の取り出しなので、string (非 null)のはず。</span>
    <span class="comment">// 警告は出ない。</span>
    <span class="reserved">public</span> <span class="reserved">string</span> Value =&gt; _buffer[0];
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">ArrayInit</span>();
        <span class="reserved">string</span> <span class="variable">s</span> = <span class="variable">x</span>.Value;
 
        <span class="comment">// どこにも警告が出ないものの、実行するとここで null 参照例外発生。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span>.Length);
    }
}
</code></pre>
<h3><a id="patch-version-up">C# バージョン変更なしでのフロー解析の改善</h3>
<p>フロー解析の改善は、
C# の文法に追加があるわけではなく単に警告の増減なこともあって、
C# のバージョン変更なし(パッチ バージョンアップ)で機能が増えたりします。</p>
<h4><a id="attribute-affect">アノテーション属性のメソッド内への影響</h4>
<p>C# 8.0 のリリース直後の時点では、
null 許容性に関する属性はメソッドの外に対してだけ影響を及ぼしていました。
以下のように、メソッド内ではフロー解析に寄与していませんでした。</p>
<pre class="source" title="アノテーション属性の影響はメソッド内部には及んでなかった(リリース当初)">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System;
<span class="reserved">using</span> System.Diagnostics.CodeAnalysis;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// メソッドを作る側(メソッドの中)には影響していない。</span>
    [<span class="reserved">return</span>: <span class="type">MaybeNull</span>]
    <span class="reserved">static</span> <span class="reserved">string</span> <span class="method">M</span>() =&gt; <span class="warning"><span class="reserved">null</span></span>; <span class="comment">// ここで警告が出る。</span>
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// メソッドを使う側(メソッドの外)にはちゃんと影響してる。</span>
        <span class="reserved">var</span> <span class="variable">s</span> = <span class="method">M</span>();
 
        <span class="comment">// MaybeNull なのに null チェックしていないのでここで警告。</span>
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="warning"><span class="variable">s</span>.Length</span>);
    }
}
</code></pre>
<p>外から見た都合(メソッドを使う側)の方が大事なので優先的に実装された結果です。
当初、<code>null</code> 戻り値のところに <a href="?p=3#null-forgiving"><code>!</code> 演算子</a>を付けて警告を回避するしかありませんでした。</p>
<p>この挙動は Visual Studio 16.6 (2020年5月リリース)で改善されていて、今はもうメソッド <code>M</code> の定義側の警告は出ません
(ちゃんと、<code>MaybeNull</code> 属性を解釈して <code>null</code> 戻り値を許す)。
「C# 8.1」になったとかではなく、「C# 8.0」のまま、フロー解析だけ改善されています。</p>
<h4><a id="MemberNotNull">MemberNotNull 属性の追加</h4>
<p><code>MemberNotNull</code>と <code>MemberNotNullWhen</code> 属性のフロー解析も Visual Studio 16.6 (2020年5月リリース)で追加されています。</p>
<p><code>MemberNotNull</code> 属性は、あるメンバー(メソッドやプロパティ)を呼んだ時点で、
別のメンバーが非 null であることを決定するための属性です。</p>
<p>例えば以下のような状況を考えます
(実際、標準ライブラリの <a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.io.compression.deflatestream"><code>DeflateStream</code></a>クラスに似たようなコードが入っています)。</p>
<pre class="source" title="間接的な初期化をしているフィールド">
<code><span class="reserved">class</span> <span class="type">DeflateStream</span>
{
    <span class="reserved">private</span> <span class="type">Stream</span> _stream; <span class="comment">// コンストラクターで初期化していないので警告が出る。</span>
 
    <span class="reserved">public</span> <span class="warning"><span class="type">DeflateStream</span></span>(<span class="type">Stream</span> stream)
    {
        <span class="method">Initialize</span>(stream);
    }
 
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">Initialize</span>(<span class="type">Stream</span> stream)
    {
        _stream = stream;
    }
}
</code></pre>
<p><code>Initialize</code> メソッドを介して間接的には非 null なフィールドをちゃんと初期化しているんですが、
これまでだとこの状況を正しくフロー解析する手段がありませんでした。
これに対して、<code>MemberNotNull</code> 属性が追加されたことで以下のように書けるようになりました。</p>
<pre class="source" title="MemberNotNull で警告消し">
<code><span class="reserved">class</span> <span class="type">DeflateStream</span>
{
    <span class="reserved">private</span> <span class="type">Stream</span> _stream; <span class="comment">// Initialize 内で初期化される。</span>
 
    <span class="reserved">public</span> <span class="type">DeflateStream</span>(<span class="type">Stream</span> stream)
    {
        <span class="comment">// Initialize 内で _stream が初期化されることがわかるので警告が消える。</span>
        <span class="method">Initialize</span>(stream);
    }
 
    <span class="comment">// この属性によって正しくフロー解析できるようになってる。</span>
    [<span class="type">MemberNotNull</span>(<span class="reserved">nameof</span>(_stream))]
    <span class="reserved">private</span> <span class="reserved">void</span> <span class="method">Initialize</span>(<span class="type">Stream</span> stream)
    {
        _stream = stream;
    }
}
</code></pre>
<h3><a id="over-a-period">移行期間</h3>
<p>.NET Core 側としても、基本クラス ライブラリに膨大な数のクラス、メソッドがあり、
1度のリリースですべてにアノテーションを付けることは不可能です。
なので、段階的にアノテーションが増える予定です。</p>
<p>実際例えば、LINQ to Object (<code>Enumerable</code>クラス(<code>System.Linq</code> 名前空間の各種拡張メソッド)には .NET Core 3.0 (C# 8.0 と同世代)時点では<a href="?p=4#annotation-attributes">アノテーション属性</a>が付いていません。</p>
<pre class="source" title=".NET Core 3.0 時点のアノテーション不足の例">
<code><span class="inactive">#nullable</span> <span class="inactive">enable</span>
<span class="reserved">using</span> System;
<span class="reserved">using</span> System.Linq;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// 以下のコードは null 参照例外を起こすんだから、ToDictionary には DisallowNull 属性が付くべき。</span>
        _ = <span class="reserved">new</span>[] { <span class="string">&quot;&quot;</span>, <span class="reserved">null</span> }.<span class="method">ToDictionary</span>(<span class="variable">x</span> =&gt; <span class="variable">x</span>);
 
        <span class="comment">// 以下のコードは null を返してくるんだから、FirstOrDefault には MaybeNull 属性が付くべき。</span>
        <span class="reserved">string</span> <span class="variable">s</span> = <span class="reserved">new</span>[] { <span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span> }.<span class="method">FirstOrDefault</span>(<span class="variable">x</span> =&gt; <span class="variable">x</span>.Length &gt; 2);
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">s</span>.Length);
    }
}
</code></pre>
<p>これらについては、後からアノテーションが増える予定です。</p>
<p>フロー解析の発達にしろアノテーションの追加にしろ、
いずれもあとから警告が増える可能性があるという点に注意してください。
しばらくの間、「移行期だから仕方がない」と受け入れてもらうしかなさそうです。</p>
<p>(通常、C# は警告の追加すらも「破壊的変更になるから」という理由で避ける文化のプログラミング言語です。
<a href="?p=1#opt-in">opt-inであること</a>と同様、段階移行も苦渋の選択です。)</p>
 ]]></description>
				<pubDate>Sat, 13 Jun 2020 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>名前のない複合型</title>
				<link>http://www.ufcpp.net/study/csharp/structured/st_anonymoustype/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>型名がなくても、メンバー名だけでその型が何をしたいものなのか十分にわかる場合があります。
このとき、むしろ、良い型名が付かない(メンバー名と重複した名前にしかならない)こともあります。</p>
<p>そういう場合に、「名前のない複合型」を作りたくなります。
C#には、歴史的経緯から、<a href="https://ufcpp.net/study/csharp/sp3_inference.html#anonymous">匿名型</a>(anonymous type)と<a href="http://ufcpp.net/study/csharp/data/tuples/#key-tuple">タプル</a>(tuple)という2種類の「名前のない複合型」があります。</p>
<h2><a id="use-case">型に良い名前が付かない場合</h2>
<p>一般的には、型にはちゃんとした名前を考えるべきです。
「型の名前だけを見れば、その型を使って何をしたいのかがわかる」というのが理想形です。
読みやすいプログラムを書くための1手法としても、「良い名前が付く単位でデータを1まとめにする」というのが非常に有効です。</p>
<p>しかし、常に良い名前が思いつくかというと、現実にはそうはいきません。
メンバー名だけ見ればその型が何をしたいのか十分にわかる場合、
型には良い名前が付きにくかったりします。</p>
<p>以下に2例ほど紹介しましょう。
それぞれ、タプルと匿名型が生まれた動機になります。</p>
<ul>
<li>多値戻り値 → タプル</li>
<li>部分的なメンバー抜き出し → 匿名型</li>
</ul>
<p>これらはタプル・匿名型の一番の動機ではありますが、別にこれ以外の用途でタプル・匿名型が使えないというわけではありません。</p>
<p>また、タプルと匿名型は似たような機能ですが、動機が異なれば実装はかなり変わります。</p>
<h2><a id="multiple-returns">多値戻り値</h2>
<p>関数を作るとき、複数の値を返したい場合があります。
例えば、「最小値、最大値、平均値を同時に求めるメソッド」があったとしましょう。</p>
<pre class="source" title="最小値、最大値、平均値を同時に求めるメソッド">
<code><span class="reserved">static</span> <span class="type">X</span> Measure(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; items)
{
    <span class="reserved">var</span> count = 0;
    <span class="reserved">var</span> sum = 0;
    <span class="reserved">var</span> min = <span class="reserved">int</span>.MaxValue;
    <span class="reserved">var</span> max = <span class="reserved">int</span>.MinValue;
    <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> items)
    {
        sum += x;
        count++;
        min = <span class="type">Math</span>.Min(x, min);
        max = <span class="type">Math</span>.Max(x, max);
    }

    <span class="reserved">return</span> <span class="reserved">new</span> <span class="type">X</span>(min, max, (<span class="reserved">double</span>)sum / count);
}
</code></pre>
<p>この、戻り値の型<code>X</code>は、どういう名前であるべきでしょう。
メソッドがメソッドなので、「最小値と最大値と平均値」みたいな名前、すなわち、<code>MinMaxAverage</code>とかでしょうか？
<code>Measure</code>(計測)した結果なので、<code>MeasureResult</code>とかでしょうか？</p>
<p>どちらも、メンバー名やメソッド名を見ればわかります。
メンバー名やメソッド名と重複した名前です。
重複は後々プログラムを修正しにくくなるのであまりいいことではありません。
例えば、メソッド名を<code>Measure</code>から<code>Tally</code>(勘定、計算)に変えたくなったとします。<code>MeasureResult</code>も<code>TallyResult</code>に変えないといけないでしょう。
返したい値として、個数と分散、中央値も増やしたくなったとします。<code>CountMinMaxAverabeVarianceMedian</code>にすべきでしょうか？</p>
<p>こういう場合には、「名前のない型」を認めるべきです。例えば、以下のような書き方です。</p>
<pre class="source" title="タプルを使った書き方">
<code><span class="reserved">static</span> <em>(<span class="reserved">int</span> min, <span class="reserved">int</span> max, <span class="reserved">double</span> average)</em> Measure(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; items)
{
    <span class="reserved">var</span> count = 0;
    <span class="reserved">var</span> sum = 0;
    <span class="reserved">var</span> min = <span class="reserved">int</span>.MaxValue;
    <span class="reserved">var</span> max = <span class="reserved">int</span>.MinValue;
    <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> items)
    {
        sum += x;
        count++;
        min = <span class="type">Math</span>.Min(x, min);
        max = <span class="type">Math</span>.Max(x, max);
    }

    <span class="reserved">return</span> (min, max, (<span class="reserved">double</span>)sum / count);
}
</code></pre>
<p>これで十分に、「itemsの最小値(min)、最大値(max)、平均値(average)を計って(measure)返す」という意図を書き表せています。</p>
<p>ちなみに、この、<code>(<span class="reserved">int</span> min, <span class="reserved">int</span> max, <span class="reserved">double</span> average)</code>という書き方をタプルと呼びます。
この機能については「<a href="http://ufcpp.net/study/csharp/data/tuples/">タプル</a>」で説明します。</p>
<h2><a id="projection">部分的なメンバー抜き出し</h2>
<p>主に「<a href="部分的なメンバー抜き出し">データ処理</a>」以降で説明して行きますが、
データ処理では、ある型のデータの中から、所定のメンバーだけを抜き出したいことがよくあります。</p>
<p>例えば、以下のようなデータがあったとします。
これは、「<a href="http://hogehoge.tk/personal/">疑似個人情報データ生成サービス</a>」を使って作った架空の個人情報です。</p>
<pre class="source">
1,奥野茉奈,オクノマナ,女,0288250107,1972/05/18
2,久保敏行,クボトシユキ,男,086288618,1984/10/13
3,長瀬由美,ナガセユミ,女,0548252320,1965/09/25
4,植田良子,ウエダヨシコ,女,0954083389,1977/03/18
・・・
</pre>
<p>全データ: <a href="https://github.com/ufcpp/UfcppSample/blob/master/Chapters/StructuredProgramming/Tuples/personal_infomation.csv">personal_infomation.csv</a></p>
<p>このデータを以下のような型で読み込んで使うとします。</p>
<pre class="source" title="個人情報を表すクラス">
<code><span class="reserved">class</span> <span class="type">Person</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> Id { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">string</span> Name { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">string</span> Kana { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">Sex</span> Sex { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">string</span> PhoneNumber { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">DateTime</span> BirthDay { <span class="reserved">get</span>; }
}
</code></pre>
<p>このデータ列に対して、性別・年代ごとの人数構成を調べたいとします。
C# には、グループ化するための関数(<code>GroupBy</code>)や、個数を調べるための関数(<code>Count</code>)が備わっているのでそれを使いたいと思います。</p>
<pre class="source" title="性別・年代ごとの人数調査">
<code><span class="reserved">var</span> persons = ReadAll(<span class="string">"personal_infomation.csv"</span>).ToArray();

<span class="comment">// 性別・年代(10年区切り)ごとに何人いるかを集計</span>
<span class="reserved">var</span> histgram = persons
    .GroupBy(p =&gt; <span class="reserved">new</span> <span class="type">X</span> { Sex = p.Sex, BirthDecade = p.BirthDay.Year / 10 })
    .Select(g =&gt; <span class="reserved">new</span> <span class="type">Y</span>{ Sex = g.Key.Sex, BirthDecade = g.Key.BirthDecade, Count = g.Count() })
    .OrderBy(x =&gt; x.BirthDecade)
    .ThenBy(x =&gt; x.Sex);
</code></pre>
<p>ここで再び命名問題です。
グループ化のキーとして使っている<code>X</code>型と、結果をまとめるために使っている<code>Y</code>型は、どういう名前であるべきでしょう。
<code>Person</code>の一部分なので<code>PartOfPerson</code>とかでしょうか？別の情報を抜き出したくなった時との区別はどうしましょう。
グループ化のキーなわけで<code>GroupKey</code>とか？これも、グループ化の条件をいろいろ変えたいときは、条件ごとに<code>GroupKey</code>が必要になります。
多値戻り値の時と同様、「性別と年代の組み合わせ」であれば、メンバー名(<code>Sex</code>、<code>BirthDecade</code>)を見れば十分に意味が分かります。</p>
<p>こういう場合もやはり、「名前のない型」を認めるべきです。例えば以下のような書き方です。</p>
<pre class="source" title="匿名型を使った書き方">
<code><span class="reserved">var</span> persons = ReadAll(<span class="string">"personal_infomation.csv"</span>).ToArray();

<span class="comment">// 性別・年代(10年区切り)ごとに何人いるかを集計</span>
<span class="reserved">var</span> histgram = persons
    .GroupBy(p =&gt; <span class="reserved">new</span> { p.Sex, BirthDecade = p.BirthDay.Year / 10 })
    .Select(g =&gt; <span class="reserved">new</span> { g.Key.Sex, g.Key.BirthDecade, Count = g.Count() })
    .OrderBy(x =&gt; x.BirthDecade)
    .ThenBy(x =&gt; x.Sex);
</code></pre>
<p>コード全体: <a href="https://github.com/ufcpp/UfcppSample/blob/master/Chapters/StructuredProgramming/Tuples/AnonymousTypes.cs">AnonymousTypes.cs</a></p>
<pre class="console" title="実行結果">
<code>{ Sex = Male, BirthDecade = 195, Count = 45 }
{ Sex = Female, BirthDecade = 195, Count = 43 }
{ Sex = Male, BirthDecade = 196, Count = 117 }
{ Sex = Female, BirthDecade = 196, Count = 115 }
{ Sex = Male, BirthDecade = 197, Count = 126 }
{ Sex = Female, BirthDecade = 197, Count = 131 }
{ Sex = Male, BirthDecade = 198, Count = 140 }
{ Sex = Female, BirthDecade = 198, Count = 133 }
{ Sex = Male, BirthDecade = 199, Count = 79 }
{ Sex = Female, BirthDecade = 199, Count = 71 }
</code></pre>
<p>この、<code><span class="reserved">new</span> { p.Sex, BirthDecade = p.BirthDay.Year / 10 }</code>というような書き方を匿名型と言います。</p>
<h2><a id="summary">まとめ</h2>
<p>ここでは、型名を付けるに付けられない場合を2例ほど紹介しました。</p>
<ul>
<li>多値戻り値</li>
<li>部分的なメンバー抜き出し</li>
</ul>
<p>それぞれ、タプルと匿名型という機能がC#に入った動機にあたります。これらの機能の詳細については、別項で説明して行きます。</p>
<ul>
<li><a href="https://ufcpp.net/study/csharp/sp3_inference.html#anonymous">匿名型</a>(anonymous type)</li>
<li><a href="http://ufcpp.net/study/csharp/data/tuples/#key-tuple">タプル</a>(tuple)</li>
</ul>
 ]]></description>
				<pubDate>Tue, 02 Jun 2020 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>特殊な変数宣言</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/declarationexpressions/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>C# 7.0～9.0 に掛けて、
<a href="/study/csharp/datatype/patterns/">パターン マッチング</a>をはじめとして、
<a href="https://ufcpp.net/study/csharp/st_variable.html#var-decl">変数宣言</a>を拡張するような機能が入っています。</p>
<ul>
<li>
<a href="http://ufcpp.net/study/csharp/datatype/typeswitch/">型スイッチ</a>
<ul>
<li><a href="http://ufcpp.net/study/csharp/datatype/typeswitch/#is">is演算子の拡張</a></li>
<li><a href="http://ufcpp.net/study/csharp/datatype/typeswitch/?p=2#switch">switchステートメントの拡張</a></li>
</ul>
</li>
<li><a href="http://ufcpp.net/study/csharp/sp_ref.html#out-var">出力変数宣言</a></li>
<li><a href="http://ufcpp.net/study/csharp/datatype/deconstruction/#deconstruction-assignment">分解代入</a></li>
</ul>
<p>C# 6.0 までの変数宣言と違って、以下のような性質があります。</p>
<ul>
<li>式の途中でも変数宣言できる</li>
<li>複数の値のうち一部だけを受け取り、残りを破棄したいことがある</li>
</ul>
<h2><a id="declaration-expression">式中の変数宣言</h2>
<p>C# 7.0 以降の構文に特有な点の1つとして、式の途中で変数を宣言できるようになるという点があります。</p>
<pre class="source" title="式中の変数宣言">
<code><span class="comment">// C# 6.0 以前は、この x のように単独の変数宣言しかなかった。</span>
<span class="reserved">object</span> <span class="variable">x</span> = 1;
 
<span class="comment">// C# 7.0 以降、この y とか z とかのように式の途中で宣言される変数が増えた。</span>
<span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">int</span> <span class="variable">y</span>) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">y</span>);
<span class="control">if</span> (<span class="reserved">int</span>.<span class="method">TryParse</span>(<span class="string">&quot;1&quot;</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">z</span>)) <span class="type">Console</span>.<span class="method">WriteLine</span>( <span class="variable">z</span>);
</code></pre>
<p>ちなみに、案としてはここからさらに発展して、任意の式の中で変数を宣言できるような話も出ています。
この機能を<strong id="key-declaration-expression" class="keyword">変数宣言式</strong>(variable declaration expression)といいます。
例えば以下のように書けるようになるかもしれません。
(優先度低めとされていて、この機能が入る期待はそれほどしない方がいいです。
代わりに、<a href="https://github.com/dotnet/csharplang/issues/3086">Expression blocks</a>のような機能が入るみたいな話もありますが、こちらもそれほど高い優先度は付いていません。)</p>
<pre class="source" title="宣言式の例">
<code><span class="comment">// (草案。このままの文法が採用されるとは限らない) </span>
<span class="reserved">static</span> <span class="reserved">int</span> X(<span class="reserved">string</span> s) =&gt; (<span class="reserved">int</span> x = <span class="reserved">int</span>.Parse(s)) * x;
</code></pre>
<p><code>(int x = int.Parse(s))</code> の部分の戻り値は、<code>x</code>に代入された値です。結局、以下のコードと同じ意味ですが、これが「式」として書けます。</p>
<pre class="source" title="宣言式の展開結果">
<code><span class="reserved">static</span> <span class="reserved">int</span> X(<span class="reserved">string</span> s)
{
    <span class="reserved">int</span> x = <span class="reserved">int</span>.Parse(s);
    <span class="reserved">return</span> x * x;
}
</code></pre>
<p>式中で変数宣言があり得ることによって、
変数のスコープに関するルールがいくつか追加されています。
詳しくは「<a href="/study/csharp/start/st_scope/?p=3#csharp7">C# 7での新しいスコープ ルール</a>」で説明します。</p>
<h2><a id="discards">値の破棄</h2>
<p>型スイッチや分解では、変数を宣言しつつ何らかの値を受け取るわけですが、
特に受け取る必要のない余剰の値が生まれたりします。</p>
<p>例えば、分解の場合、複数の値のうち、1つだけを受け取りたい場合があったとします。
そういう場面が複数並んでしまった場合、以下のようなコードになりがちです。</p>
<pre class="source" title="要らない値を無視するための適当な変数">
<code><span class="reserved">static</span> <span class="reserved">void</span> Deconstruct()
{
    <span class="comment">// 商と余りを計算するメソッドがあるけども、ここでは商しか要らない</span>
    <span class="comment">// 要らないので適当な変数 x とかで受ける</span>
    <span class="reserved">var</span> (q, x) = DivRem(123, 11);

    <span class="comment">// 逆に、余りしか要らない</span>
    <span class="comment">// 要らないから再び適当な変数 x で受けたいけども、x はもう使ってる</span>
    <span class="comment">// <em>しょうがないから x1 とかにしとくか…</em></span>
    <span class="reserved">var</span> (<em>x1</em>, r) = DivRem(123, 11);
}

<span class="reserved">static</span> (<span class="reserved">int</span> quotient, <span class="reserved">int</span> remainder) DivRem(<span class="reserved">int</span> dividend, <span class="reserved">int</span> divisor)
    =&gt; (<span class="type">Math</span>.DivRem(dividend, divisor, <span class="reserved">out</span> <span class="reserved">var</span> remainder), remainder);
</code></pre>
<p>「しょうがないから」感がひどく、どう見ても不格好です。</p>
<p>こういう時に使うのが、値の<strong id="discard" class="keyword">破棄</strong>(discard)です。
以下のように、<code>_</code>を書くことで値を無視できます。</p>
<pre class="source" title="_ で値の破棄">
<code>{
    <span class="comment">// _ を書いたところでは、値を受け取らずに無視する</span>
    <span class="reserved">var</span> (q, <span class="reserved"><em>_</em></span>) = DivRem(123, 11);

    <span class="comment">// _ は変数にはならないので、スコープを汚さない。別の場所でも再び _ を書ける</span>
    <span class="comment">// また、本来「var x」とか変数宣言を書くべき場所にも _ だけを書ける</span>
    (<span class="reserved"><em>_</em></span>, <span class="reserved">var</span> r) = DivRem(123, 11);
}
</code></pre>
<p>1つ目の例では一見、<code>_</code>という名前の変数を定義しているようにも見えますが、別の挙動になります。
変数は作らず、スコープ内の別の場所でも再び<code>_</code>を使うことができます(先ほどの例みたいに<code>_1</code>みたいな変な名前を作らなくて済む)。</p>
<p>また、2つ目の例のように、「型名 変数名」みたいに書くべき場所でも、<code>var _</code>ではなく、<code>_</code>だけでOKです。</p>
<p>同様に、出力変数宣言でも<code>_</code>を破棄の意味で使えます。</p>
<pre class="source" title="out 引数で、_ で値を破棄">
<code><span class="comment">// 欲しいのは戻り値だけであって、out 引数で受け取った値は要らない</span>
<span class="reserved">static</span> <span class="reserved">bool</span> CanParse(<span class="reserved">string</span> s) =&gt; <span class="reserved">int</span>.TryParse(s, <span class="reserved">out</span> _);
</code></pre>
<p>型スイッチでも同様です。</p>
<pre class="source" title="型スイッチで、_ で値を破棄">
<code><span class="reserved">static</span> <span class="reserved">int</span> TypeSwitch(<span class="reserved">object</span> obj)
{
    <span class="reserved">switch</span> (obj)
    {
        <span class="reserved">case</span> <span class="reserved">int</span>[] x: <span class="reserved">return</span> x.Length;
        <span class="reserved">case</span> <span class="reserved">long</span>[] x: <span class="reserved">return</span> 2 * x.Length;
        <span class="comment">// int でさえあれば値は問わない</span>
        <span class="reserved">case</span> <span class="reserved">int</span> <span class="reserved">_</span>: <span class="reserved">return</span> 1;
        <span class="comment">// 同、long</span>
        <span class="reserved">case</span> <span class="reserved">long</span> <span class="reserved">_</span>: <span class="reserved">return</span> 2;
        <span class="reserved">case</span> <span class="reserved">null</span>: <span class="reserved">return</span> 0;
        <span class="comment">// 以下の行をコメントアウトするとエラーに</span>
        <span class="comment">// 今のところ、case _ は未実装(将来的に予定はあり)</span>
        <span class="comment">//case _:</span>
        <span class="reserved">default</span>: <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentOutOfRangeException</span>();
    }
}
</code></pre>
<h2><a id="underscore">_ が破棄の意味になる場合</h2>
<p><code>_</code>という記号は、元々のC#では<a href="http://ufcpp.net/study/csharp/misc_identifier.html">識別子</a>として有効な名前です。
すなわち、以下のコードは有効なC#コードです。</p>
<pre class="source" title="_ は有効な識別子">
<code><span class="reserved">var</span> _ = 10;
<span class="type">Console</span>.WriteLine(_); <span class="comment">// 10 が表示される</span>
</code></pre>
<p><code>_</code>を破棄の意味で使うということは、<code>_</code>の使い方を変えるということになります。
なので、以下のように、文脈によって <code>_</code> の意味が変わります。</p>
<ul>
<li>C# 7から導入される新しい構文の中では、<code>_</code>が常に破棄の意味になる</li>
<li>それ以前の構文では、1つも参照がなかった場合だけ<code>_</code>を破棄の意味で扱う(予定)</li>
</ul>
<p>分解、出力引数宣言、型スイッチなど、C# 7から導入された構文の中では、
<code>_</code>が常に破棄の意味になります。
<code>_</code>という名前の変数は作られません。</p>
<pre class="source" title="新構文における _">
<code><span class="reserved">static</span> <span class="reserved">void</span> Deconstruct1()
{
    <span class="comment">// 要らないので適当な変数 x とかで受ける</span>
    <span class="reserved">var</span> (q, x) = DivRem(123, 11);

    <span class="comment">// 要らないと言いつつ、参照できてしまう</span>
    <span class="type">Console</span>.WriteLine(x);

    <span class="comment">// 要らないものは _ で破棄</span>
    <span class="reserved">var</span> (<span class="reserved">_</span>, r) = DivRem(123, 11);

    <span class="comment">// 分解の中に書いた _ は変数にはならない</span>
    <span class="comment">// 以下の行でコンパイル エラーになる(_ は存在しない)</span>
    <span class="type">Console</span>.WriteLine(_);
}
</code></pre>
<p>ちなみに、既存の構文に対しては破棄は使えません。
<code>_</code>は普通に変数扱いされます。</p>
<p>例えば、引数に対して <code>_</code> を使っても破棄の意味にはなりません。
以下のコードはコンパイル エラーになります。
(同名の引数が2つある状態。)</p>
<pre class="source" title="引数の _ は破棄の意味にならない">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">_</span>, <span class="reserved">int</span> <span class="variable"><span class="error">_</span></span>)
{
}
</code></pre>
<h3><a id="lambda-discard">ラムダ式の引数</h3>
<h5 class="version version9">Ver. 9</h5>
<p>既存の構文で破棄を使いたいものの代表例は、ラムダ式の引数でしょう。
C# 8.0 までは破棄の意味で<code>_</code>を使えず、「<code>_1</code>」みたいな名前が必要でした。</p>
<pre class="source" title="C# 8.0時点では使えない _ 破棄">
<code><span class="reserved">static</span> <span class="reserved">void</span> Subscribe(<span class="type">INotifyPropertyChanged</span> source)
{
    <span class="comment">// C# 8.0 以前、2個目の _ が「同じ名前被ってる」エラーになる</span>
    source.PropertyChanged += (_, <span class="error">_</span>) =&gt; <span class="type">Console</span>.WriteLine(<span class="string">"property changed"</span>);
}
</code></pre>
<p>C# 9.0 でこの場合に対応しました。
ただし、既存コードを壊さないように、2個以上の引数を <code>_</code> にした時だけ破棄の意味になるようにしています。</p>
<p>すなわち、以下のようなコードが書ける予定です。</p>
<pre class="source" title="ラムダ式の引数で _ を破棄扱い">
<code><span class="reserved">static</span> <span class="reserved">void</span> Subscribe(<span class="type">INotifyPropertyChanged</span> source)
{
    <span class="comment">// 2回以上 _ を使かったら破棄扱い</span>
    source.PropertyChanged += (<span class="reserved">_</span>, <span class="reserved">_</span>) =&gt; { };

    <span class="comment">// _ が1回だけの場合は引数扱い。この場合普通に変数参照できる</span>
    source.PropertyChanged += (<span class="variable">_</span>, <span class="variable">_1</span>) =&gt; <span class="type">Console</span>.WriteLine(<span class="variable">_</span>);
}
</code></pre> ]]></description>
				<pubDate>Tue, 12 May 2020 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 8.0 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver8/</link>
				<description><![CDATA[ <div class="version version8">Ver. 8.0</div>
<table>
<tr>
<th>リリース時期</th>
<td>2019/9</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>Visual Studio 2019 16.3</li>
<li>.NET Core 3.0</li>
<li>.NET Standard 2.1</li>
</td>
</tr>
<tr>
<th>要約・目玉機能</ht>
<td>
<ul>
<li>堅牢性向上</li>
</ul>
</td>
</tr>
</table>
<p>C# 8.0 にはいろいろな新機能が含まれていますが、
主要なものは堅牢性向上を目的としたものになります。
プログラマーの人的ミスを避け、より堅牢なプログラムを書けるようにしたいというものです。</p>
<h2><a id="">補足</h2>
<h3><a id="langversion">バージョン指定</h3>
<p>ちなみに、C# 8.0 世代の C# コンパイラーから、<a href="/study/csharp/cheatsheet/langversionoption/#langversion">バージョンの指定方法</a>に <code>preview</code> というオプションが追加されました。
このオプションを指定することで、正式リリース前の機能をある程度先取りして試してみることができます。
例えば、C# 8.0 がデフォルトで有効になるのは Visual Studio 2019 16.3 からですが、
<code>preview</code> 指定であれば 16.0 の頃から使えました。
(名前通りプレビュー状態なので、正式リリースまでに変更が掛かる可能性が高いので注意は必要です。)</p>
<h3><a id="targetframework">ターゲット フレームワーク</h3>
<p>C# 8.0 の全ての機能を一切の小細工なしで満足に使えるのは .NET Core 3.0/.NET Standard 2.1 以降です。
古いターゲット フレームワークで C# 8.0 を使うには<a href="/study/csharp/cheatsheet/langversionoption/#new-options">バージョンの明示的な指定</a>が必要です。</p>
<p>ちなみに、以下の機能にはライブラリ依存があって、古いターゲット フレームワーク上で素では動きません。</p>
<ul>
<li><a href="#async-stream">非同期ストリーム</a></li>
<li><a href="#range">範囲アクセス</a></li>
<li><a href="#nullable-reference-type">null許容参照型</a>の一部(<a href="/study/csharp/resource/nullablereferencetype/?p=4#annotation-attributes">アノテーション属性</a>)</li>
</ul>
<p>ただし、このうち、非同期ストリームは <a href="https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces/">Microsoft.Bcl.AsyncInterfaces</a> という NuGet パッケージを参照することで、.NET Framework 4.6.1/.NET Core 2.0/.NET Standard 2.0 以降でも使えます。</p>
<p>また、<a href="#default-imeplementation-of-interface">インターフェイスのデフォルト実装</a>は実行環境に手を入れないと実現できない機能で、
.NET Core 3.0/.NET Standard 2.1 以降でなければどうやっても動かすことができません。</p>
<h2><a id="nullable-reference-type">null 許容参照型</h2>
<p>参照型でも単に型 <code>T</code> と書くと null を受け付けず、<code>T?</code> と書いて初めて null 許容になる機能が追加されました。
null 許容参照型と呼びます。
ただ、これまでと型 <code>T</code> の意味を変えてしまうので、opt-in (オプションを明示しないと有効にならない)方式になっています。</p>
<pre class="source" title="null 許容参照型の例">
<code><span class="comment">// 有効化のためのディレクティブ</span>
<span class="inactive">#nullable</span> <span class="inactive">enable</span>
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// 参照型でも ? の有無で null を許容するかどうかが変わる。</span>
    <span class="reserved">string</span> <span class="method">NotNull</span>() =&gt; <span class="string">&quot;&quot;</span>;
    <span class="reserved">string</span>? <span class="method">MaybeNull</span>() =&gt; <span class="reserved">null</span>;
 
    <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">s</span>)
    {
        <span class="reserved">var</span> <span class="variable">s1</span> = <span class="method">NotNull</span>();
        <span class="reserved">var</span> <span class="variable">s2</span> = <span class="method">MaybeNull</span>();
 
        <span class="comment">// null チェックをしていないので、以下の行の s2 のところに警告が出る。</span>
        <span class="control">return</span> <span class="variable">s</span>.Length + <span class="variable">s1</span>.Length + <span class="warning"><span class="variable">s2</span></span>.Length;
    }
}
</code></pre>
<p>「ぬるぽ」がなぜかネットスラングとして定着するくらい、「意図しない null によるバグ」は多くていらだたしいものです。
コンパイラーによるフロー解析によってこの手のバグを事前に避けれるようになることで、プログラムの堅牢性が増します。</p>
<p>詳しくは「<a href="/study/csharp/resource/nullablereferencetype/">null 許容参照型</a>」で説明します。</p>
<h2><a id="recursive-pattern">再帰パターン</h2>
<p>C# 7.0 で部分的に<a href="/study/csharp/datatype/patterns/">パターン マッチング</a>が実装されていましたが、C# 8.0 で完全版になります。
C# 8.0 で追加されるパターンは再帰的なマッチングが可能で、「再帰パターン」(recursive pattern)と呼ばれたりもします。</p>
<p>例えば以下のような感じです(new! と書いている行が再帰パターン)。</p>
<pre class="source" title="再帰パターンの例">
<code><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="method">Point</span>(<span class="reserved">int</span> <span class="variable">x</span> = 0, <span class="reserved">int</span> <span class="variable">y</span> = 0) =&gt; (X, Y) = (<span class="variable">x</span>, <span class="variable">y</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">y</span>) =&gt; (<span class="variable">x</span>, <span class="variable">y</span>) = (X, Y);
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>)
        =&gt; <span class="variable">obj</span> <span class="reserved">switch</span>
    {
        0 =&gt; 1,
        <span class="reserved">int</span> <span class="variable">i</span> =&gt; 2,
        <em><span class="type">Point</span> (1, <span class="reserved">_</span>)</em> =&gt; 4, <span class="comment">// new! 位置パターン。</span>
        <em><span class="type">Point</span> { X: 2, Y: <span class="reserved">var</span> y }</em> =&gt; <span class="variable">y</span>, <span class="comment">// new! プロパティ パターン。</span>
        <span class="reserved">_</span> =&gt; 0
    };
}
</code></pre>
<p>単に短く書けるというだけではなく、以下のように、
コンパイラーによるチェックが掛かりやすく、人的ミスの回避にも貢献します。</p>
<pre class="source" title="再帰パターンはコンパイラーによるチェックがちょっと賢い">
<code><span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>)
{
    <span class="control">switch</span> (<span class="variable">obj</span>)
    {
        <span class="control">case</span> <span class="reserved">string</span> <span class="variable">s</span> <span class="control">when</span> <span class="variable">s</span>.Length == 0:
            <span class="control">break</span>;
        <span class="comment">// これまでの switch だと、間違えて同じ case を書いていてもエラーにならない。</span>
        <span class="control">case</span> <span class="reserved">string</span> <span class="variable">s</span> <span class="control">when</span> <span class="variable">s</span>.Length == 0:
            <span class="control">break</span>;
    }
 
    <span class="control">switch</span> (<span class="variable">obj</span>)
    {
        <span class="control">case</span> <span class="reserved">string</span> { Length: 0 }:
            <span class="control">break</span>;
        <span class="comment">// 再帰パターンだと同じ条件があるとコンパイル エラーになる。</span>
        <span class="control">case</span> <span class="error"><span class="reserved">string</span> { Length: 0 }</span>:
            <span class="control">break</span>;
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/datatype/patterns/?p=2">再帰パターン</a>」で説明します。</p>
<h2><a id="switch-expression">switch 式</h2>
<p><code>switch</code>を式として書けるようになりました。
また、従来の <code>switch</code> ステートメントは C# の前身となるC言語のものの名残を強く残し過ぎていて使いにくいものでしたが、その辺りも解消されて使いやすくなりました。</p>
<p>以下のような書き方ができます。</p>
<pre class="source" title="switch 式の例">
<code><span class="reserved">public</span> <span class="reserved">int</span> <span class="method">Compare</span>(<span class="reserved">int</span>? <span class="variable">x</span>, <span class="reserved">int</span>? <span class="variable">y</span>)
    =&gt; (<span class="variable">x</span>, <span class="variable">y</span>) <em><span class="control">switch</span></em>
    {
        (<span class="reserved">int</span> <span class="variable">i</span>, <span class="reserved">int</span> <span class="variable">j</span>) =&gt; <span class="variable">i</span>.<span class="method">CompareTo</span>(<span class="variable">j</span>),
        ({ }, <span class="reserved">null</span>) =&gt; 1,
        (<span class="reserved">null</span>, { }) =&gt; -1,
        (<span class="reserved">null</span>, <span class="reserved">null</span>) =&gt; 0
    };
</code></pre>
<p>後置きの <code>switch</code> キーワードに続けて、<code>{}</code> 内に<a href="/study/csharp/datatype/patterns/">パターン</a>と返したい値を並べます。</p>
<p>詳しくは「<a href="/study/csharp/datatype/typeswitch/?p=5#switch-expression"><code>switch</code> 式</a>」で説明します。</p>
<h2><a id="range">範囲アクセス</h2>
<p><code>a[i..j]</code> という書き方で「i番目からj番目の要素を取り出す」というような操作ができるようになりました。</p>
<pre class="source" title=".. 構文">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">a</span> = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 };
 
        <span class="comment">// 前後1要素ずつ削ったもの</span>
        <span class="reserved">var</span> <span class="variable">middle</span> = <span class="variable">a</span>[1..^1];
 
        <span class="comment">// 2, 3, 4 が表示される</span>
        <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">middle</span>)
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span>);
        }
    }
}
</code></pre>
<p>この手の範囲指定は、例えば <code>(a, b)</code> みたいに書いたときに、「<code>a</code> から <code>b</code> まで」なのか「<code>a</code> から始めて <code>b</code> 個」なのかで迷ったり、前者だとすると「<code>b</code> は含むのか含まないのか」でで迷ったりします。
言語構文として <code>a..b</code> を導入することでこういう不明瞭さを排除して、人的ミスを減らします。</p>
<p>この機能は、実際には以下の3つの機能の組み合わせになっています。</p>
<ul>
<li><code>^i</code> で「後ろからi番目」を表す <code>Index</code> 型の値を得る</li>
<li><code>i..j</code> で「i番目からj番目」を表す <code>Range</code> 型の値を得る</li>
<li>所定の条件を満たす型に対して <code>Index</code>/<code>Range</code> を渡すと、所定のパターンに展開する</li>
</ul>
<p>詳しくは「<a href="/study/csharp/data/dataranges/">インデックス/範囲処理</a>」で説明します。</p>
<h2><a id="default-imeplementation-of-interface">インターフェイスのデフォルト実装</h2>
<p>C# 8.0 (.NET Core 3.0)で、インターフェイスの制限が緩和されました。
以下のようになります。</p>
<ul>
<li>メソッド、<a href="/study/csharp/oo_property.html">プロパティ</a>、<a href="/study/csharp/oo_indexer.html">インデクサー</a>、<a href="/study/csharp/sp_event.html">イベント</a>のアクセサーの実装を持てるようになった</li>
<li><a href="/study/csharp/oo_conceal.html#level">アクセシビリティ</a>を明示的に指定できるようになった</li>
<li><a href="/study/csharp/oo_static.html">静的メンバー</a>を持てるようになった</li>
</ul>
<p>これら指して「インターフェイスのデフォルト実装」(default implementations of interfaces)と呼びます。</p>
<pre class="source" title="デフォルト実装">
<code><span class="reserved">using</span> System;
 
<span class="reserved">interface</span> <span class="type">I</span>
{
    <span class="reserved">void</span> <span class="method">X</span>();
 
    <span class="comment">// 後から追加しても、デフォルト実装を持っているので平気</span>
    <span class="reserved">void</span> <span class="method">Y</span>() { }
}
 
<span class="reserved">class</span> <span class="type">A</span> : <span class="type">I</span>
{
    <span class="comment">// X だけ実装していればとりあえず大丈夫</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">X</span>() { }
}
 
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">I</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">X</span>() { }
 
    <span class="comment">// Y も実装。I 越しでもちゃんとこれが呼ばれる。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Y</span>() =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;B&quot;</span>);
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>() =&gt; <span class="method">M</span>(<span class="reserved">new</span> <span class="type">B</span>());
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">I</span> <span class="variable">i</span>) =&gt; <span class="variable">i</span>.<span class="method">Y</span>();
}
</code></pre>
<pre class="console" title="デフォルト実装">
<code>B
</code></pre>
<p>機能面で言うと、クラス(特に<a href="/study/csharp/oo_abstract.html#abclass">抽象クラス</a>)との差は「フィールドを持てない代わりに多重継承できる」というくらいに縮まりました。
ただ、
既存機能・既存コードへの影響を最小限にとどめるためであったり、
いくつかの理由からクラスの場合と既定動作などに差があるため注意が必要です。</p>
<p>詳しくは「<a href="/study/csharp/oo_interface.html?p=5#dim">インターフェイスのデフォルト実装</a>」で説明します。</p>
<p>ただし、インターフェイスのデフォルト実装は C# コンパイラー上のトリックだけでは実装できず、 .NET ランタイム側の対応が必要な機能です。
C# 8.0 以降を使っていても、ターゲットとなるランタイム(TargetFramework)が古いと使えません。
詳しくは以前書いたブログ「<a href="/blog/2018/12/runtimefeature/">RuntimeFeature クラス</a>」で説明しています。</p>
<h2><a id="async-stream">非同期ストリーム</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 では非同期メソッドが大幅に拡張されました。</p>
<ul>
<li>非同期<code>foreach</code>: <code>await foreach</code>という書き方で、非同期なデータ列挙ができる(<a href="/study/csharp/data/sp_foreach/"><code>foreach</code>ステートメント</a>の非同期版)</li>
<li>非同期<code>using</code>: <code>await using</code>という書き方で、非同期なリソース破棄ができる(<a href="/study/csharp/oo_dispose.html#using"><code>using</code>ステートメント</a>の非同期版)</li>
<li>非同期イテレーター: 非同期メソッド内に<code>yield</code>を書けるようになる(<a href="/study/csharp/sp2_iterator.html">イテレーター</a>の非同期版)</li>
</ul>
<p>例えば以下のように書けます。</p>
<pre class="source" title="非同期イテレーターと非同期foreachの例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">await</span> <span class="method">WriteItems</span>(<span class="method">Select</span>(<span class="method">GetData</span>(), <span class="variable">x</span> =&gt; <span class="variable">x</span> * <span class="variable">x</span>));
    }
 
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="method">GetData</span>()
    {
        <em><span class="control">yield</span> <span class="control">return</span></em> 1;
        <span class="reserved">await</span> <span class="type">Task</span>.<span class="method">Delay</span>(1);
        <span class="control">yield</span> <span class="control">return</span> 2;
        <span class="reserved">await</span> <span class="type">Task</span>.<span class="method">Delay</span>(1);
        <span class="control">yield</span> <span class="control">return</span> 3;
    }
 
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="method">Select</span>(<span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">source</span>, <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">selector</span>)
    {
        <em><span class="reserved">await</span> <span class="control">foreach</span></em> (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable">source</span>)
        {
            <span class="control">yield</span> <span class="control">return</span> <span class="variable">selector</span>(<span class="variable">item</span>);
        }
    }
 
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">WriteItems</span>(<span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">source</span>)
    {
        <span class="reserved">await</span> <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable">source</span>)
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">item</span>);
        }
    }
}
</code></pre>
<p>一連のデータ(data stream)を、非同期に生成(イテレーター)して非同期に消費(foreach)する機能なので、これらを合わせて非同期ストリーム(async stream)と呼ばれます。</p>
<p>詳しくは「<a href="/study/csharp/async/asyncstream/">非同期ストリーム</a>」で説明します。</p>
<h2><a id="using">using ステートメントの改善</h2>
<h3><a id="using-declaration">using 変数宣言</h3>
<p>変数宣言に対して <code>using</code> 修飾を付けることで、
その変数のスコープに紐づいて <code>using</code> ステートメントと同じ効果を得られるようになりました。
これを <code>using</code> 変数宣言(using declaration)と呼びます。</p>
<pre class="source" title="using 変数宣言">
<code><span class="reserved">using</span> System;
 
<span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type">DeferredMessage</span> : <span class="type">IDisposable</span>
{
    <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="reserved">string</span> _message;
    <span class="reserved">public</span> <span class="type">DeferredMessage</span>(<span class="reserved">string</span> <span class="variable">message</span>) =&gt; _message = <span class="variable">message</span>;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(_message);
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// using var で、変数のスコープに紐づいた using になる。</span>
        <span class="comment">// スコープを抜けるときに Dispose が呼ばれる。</span>
        <span class="reserved">using</span> <span class="reserved">var</span> <span class="variable">a</span> = <span class="reserved">new</span> <span class="type">DeferredMessage</span>(<span class="string">&quot;a&quot;</span>);
        <span class="reserved">using</span> <span class="reserved">var</span> <span class="variable">b</span> = <span class="reserved">new</span> <span class="type">DeferredMessage</span>(<span class="string">&quot;b&quot;</span>);
 
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;c&quot;</span>);
 
        <span class="comment">// c, b, a の順でメッセージが表示される</span>
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/oo_dispose.html#using-declaration">using 変数宣言</a>」で説明します。</p>
<h3><a id="pattern-based-using">パターン ベースな using</h3>
<p><a href="/study/csharp/resource/refstruct/">ref 構造体</a>に限るんですが、
パターン ベース(別にインターフェイスを実装していなくても、<code>Dispose</code> メソッドさえ持っていればOK)で <a href="/study/csharp/oo_dispose.html#using"><code>using</code> ステートメント</a>を使えるようになりました。</p>
<pre class="source" title="パターン ベースな using ステートメント">
<code><span class="comment">// ref 構造体なので IDisposable インターフェイスは実装できない。</span>
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">RefDisposable</span>
{
    <span class="comment">// けど、Dispose メソッドだけ用意。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() { }
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// C# 7.3 まではコンパイル エラーになっていた。</span>
        <span class="comment">// C# 8.0 で OK に。</span>
        <span class="reserved">using</span> (<span class="reserved">new</span> <span class="type">RefDisposable</span>()) { }
    }
}
</code></pre>
<p>ref 構造体だけ対応したのは、需要が高く、既存コードを壊す心配が少ないからです
(既存コードの心配さえなければ任意の型で認めたかったそうです)。</p>
<p>詳しくは「<a href="/study/csharp/oo_dispose.html#pattern-based-using">パターン ベースな using</a>」で説明します。</p>
<h2><a id="others">その他</h2>
<p>こまごまとした修正がいくつかあります。</p>
<h3><a id="null-coalescing-assignment">null 合体代入 (??=)</h3>
<p>C# 8.0 では、null合体演算子 (<code>??</code>)も複合代入に使えるようになりました(<code>??=</code>)。</p>
<pre class="source" title="null 合体代入">
<code><span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">string</span> s = <span class="reserved">null</span>)
{
    s <em>??=</em> <span class="string">"default string"</span>;
    Console.WriteLine(s);
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp2_nullable.html#null-coalescing-assignment">null 合体代入 (??=)</a>」で説明します。</p>
<h3><a id="static-local-function">静的ローカル関数</h3>
<p>C# 8.0 から、外部の変数を捕獲しないことを明示するため、
ローカル関数に <code>static</code> 修飾を付けれるようになりました。
この機能を<strong id="key-static-local-function" class="keyword">静的ローカル関数</strong>(static local function)と呼びます。</p>
<pre class="source" title="静的ローカル関数の例">
<code><span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">a</span>)
{
    <span class="comment">// 外部の変数(引数)を捕獲(クロージャ化)。</span>
    <span class="reserved">int</span> <span class="method">f</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">a</span> * <span class="variable">x</span>;
 
    <span class="comment">// static を付けて、クロージャ化を禁止。</span>
    <span class="comment">// a を使っているところでコンパイル エラーになる。</span>
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">g</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="error"><span class="variable">a</span></span> * <span class="variable">x</span>;
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/functional/fun_localfunctions/#static-local-function">静的ローカル関数</a>」で説明します。
同時に、変数の<a href="/study/csharp/functional/fun_localfunctions/#shadowing">シャドーイング</a>も認められるようになりました。</p>
<h3><a id="at-dollar">@$</h3>
<p>C# 7.0 では、文字列リテラル<code>&quot;&quot;</code>の前に<code>$@</code>と付けることで、複数行に渡る<a href="/study/csharp/st_string.html#multi-line">文字列補間</a>ができましたが、<code>$</code>と<code>@</code>の順序は<code>$@</code>しか認められていませんでした。</p>
<p>C# 8.0では<code>@$</code>の順でも認められるようになりました。</p>
<h3><a id="unmanaged-generic-struct">アンマネージなジェネリック構造体</h3>
<p>C# 8.0 では、ジェネックな構造体に対して再帰的にアンマネージ型かどうかの判定するようになりました。
型引数全てがアンマネージであれば、その構造体もアンマネージ扱いを受けるようになります。</p>
<pre class="source" title="ジェネリックな構造体に対するポインター">
<code><span class="reserved">using</span> System.Collections.Generic;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">unsafe</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">kv</span> = <span class="reserved">new</span> <span class="type">KeyValuePair</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(1, 2);
        <em><span class="type">KeyValuePair</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;* <span class="variable">pkv</span> = &amp;<span class="variable">kv</span>;</em>
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp_unsafe.html#unmanaged-generic-struct">アンマネージなジェネリック構造体</a>」で説明します。</p>
<h3><a id="readonly-member">readonly 関数メンバー</h3>
<p>C# 8.0 で、<a href="/study/csharp/st_function.html#sec-function-member">関数メンバー</a>単位で「フィールドを書き換えてない」ということを保証できるようになりました。</p>
<pre class="source" title="プロパティを readonly 修飾する例">
<code><span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">float</span> X;
    <span class="reserved">public</span> <span class="reserved">float</span> Y;
 
    <span class="comment">// readonly 修飾でフィールドを書き換えないことを明示</span>
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">float</span> LengthSquared =&gt; X * X + Y * Y;
}
</code></pre>
<p>「<a href="/study/csharp/resource/readonlyness/#struct-readonly">隠れたコピー</a>」問題を避けやすくなります。</p>
<p>詳しくは「<a href="/study/csharp/resource/readonlyness/#readonly-member">readonly 関数メンバー</a>」で説明します。</p>
<h3><a id="nested-stackalloc">式中の stackalloc</h3>
<p>式中の任意の場所に <code>stackalloc</code> を書けるようになりました。
例えば以下のような書き方ができます。</p>
<pre class="source" title="式中での stackalloc">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// Span を受け取る適当なメソッドを用意。</span>
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">buf</span>) =&gt; 0;
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">len</span>)
    {
        <span class="control">if</span> (<span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1] <span class="method">==</span> <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1]) ;
        <span class="method">M</span>(<span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1]);
        <span class="method">M</span>(<span class="variable">len</span> &gt; 512 ? <span class="reserved">new</span> <span class="reserved">byte</span>[<span class="variable">len</span>] : <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[<span class="variable">len</span>]);
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/resource/span/#nested-stackalloc">式中の stackalloc</a>」で説明します。</p>
<h3><a id="generic-is-null">ジェネリック型に対する is null</h3>
<p>ほぼ「バグ修正」レベルですが、
以下のコードがコンパイルできるようになりました。</p>
<pre class="source" title="ジェネリック型に対する is null">
<code><span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">null</span>;
</code></pre>
<p>元々 <code>x == null</code> であればコンパイルできていたのに、<code>x is null</code> がコンパイルできないのは変だということで修正されました。
型引数 <code>T</code> が<a href="/study/csharp/sp2_nullable.html#non-nullable">非 null 値型</a>の時には常に false になります。</p>
<h3><a id="obsolete-accessor">プロパティのアクセサーに Obsolete 指定</h3>
<p>プロパティの get/set アクセサーに対して、どちらか片方にだけ <code>Obsolete</code> 属性(<code>System</code>名前空間)を指定できるようになりました。
以下のコードは C# 7.3 以前ではエラーになっていました。</p>
<pre class="source" title="set にだけ Obsolete">
<code><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X
    {
        <span class="reserved">get</span>;
        [<span class="type">Obsolete</span>] <span class="reserved">set</span>;
    }
}
</code></pre> ]]></description>
				<pubDate>Tue, 22 Oct 2019 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>非同期ストリーム</title>
				<link>http://www.ufcpp.net/study/csharp/async/asyncstream/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 で、<a href="/study/csharp/sp5_async.html">非同期メソッド</a>が大幅に拡張されます。</p>
<p>一連のデータ(data stream)を、非同期に生成(イテレーター)して非同期に消費(<code>foreach</code>)する機能なので、これらを合わせて非同期ストリーム(async stream)と呼ばれます。</p>
<p>同期的な処理であれば、これまでも<a href="/study/csharp/sp2_iterator.html">イテレーター</a>と<a href="/study/csharp/sp_foreach.html"><code>foreach</code></a>という機能がありました。
非同期ストリームはこれらの非同期版(<a href="/study/csharp/sp5_awaitable.html">非同期メソッド</a>との混在)になります。</p>
<h2><a id="iasyncenumerable">IAsyncEnumerable</h2>
<p><a href="/study/csharp/sp2_iterator.html">イテレーター</a>と<a href="/study/csharp/sp_foreach.html"><code>foreach</code></a>では、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.ienumerable-1"><code>IEnumerable&lt;T&gt;</code></a>インターフェイス(<code>System.Collections.Generic</code>名前空間)が中心的な役割を担います。</p>
<ul>
<li>イテレーターの戻り値は<code>IEnumerable&lt;T&gt;</code>もしくは<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.ienumerator-1"><code>IEnumerator&lt;T&gt;</code></a>である必要がある</li>
<li><code>foreach</code>は<a href="/study/csharp/misc/miscpatternbased/">パターン ベース</a>で、
「<code>IEnumerable&lt;T&gt;</code>と同じメソッドを持つ」というのが満たすべきパターン</li>
</ul>
<p>C# 8.0 ではこれらの非同期版が入るわけですが、
同期版と同じく中心的な役割を担うインターフェイスがあり、
それが<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.iasyncenumerable-1"><code>IAsyncEnumerable&lt;T&gt;</code></a>インターフェイス(<code>System.Collections.Generic</code>名前空間)です。
以下のような構造になっています。</p>
<pre class="source" title="IAsyncEnumerable の構造">
<code><span class="reserved">public</span> <span class="reserved">interface</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">out</span> <span class="type">T</span>&gt;
{
    <span class="type">IAsyncEnumerator</span>&lt;<span class="type">T</span>&gt; <span class="method">GetAsyncEnumerator</span>(<span class="type">CancellationToken</span> <span class="variable">cancellationToken</span> = <span class="reserved">default</span>);
}
 
<span class="reserved">public</span> <span class="reserved">interface</span> <span class="type">IAsyncEnumerator</span>&lt;<span class="reserved">out</span> <span class="type">T</span>&gt; : <span class="type">IAsyncDisposable</span>
{
    <span class="type">T</span> Current { <span class="reserved">get</span>; }
    <span class="type">ValueTask</span>&lt;<span class="reserved">bool</span>&gt; <span class="method">MoveNextAsync</span>();
}
 
<span class="reserved">public</span> <span class="reserved">interface</span> <span class="type">IAsyncDisposable</span>
{
    <span class="type">ValueTask</span> <span class="method">DisposeAsync</span>();
}
</code></pre>
<p>インターフェイス名とメソッド名に<code>Async</code>が付いたのと、一部のメソッドの戻り値が<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.valuetask-1"><code>ValueTask&lt;T&gt;</code></a>になっているくらいで、ほとんど同期版と同じ構造です。</p>
<p>同期版と同じく、非同期ストリームと以下のような関わりがあります。</p>
<ul>
<li>非同期イテレーターの戻り値は<code>IAsyncEnumerable&lt;T&gt;</code>もしくは<code>IAsyncEnumerator&lt;T&gt;</code>である必要がある</li>
<li>非同期<code>foreach</code>は<a href="/study/csharp/misc/miscpatternbased/">パターン ベース</a>で、
「<code>IAsyncEnumerable&lt;T&gt;</code>と同じメソッドを持つ」というのが満たすべきパターン</li>
</ul>
<p>ちなみに、同期版とは違って、非ジェネリックな<code>IAsyncEnumerable</code>、<code>IAsyncEnumerator</code>インターフェイスはありません。
(非ジェネリックな<code>IEnumerable</code>は<a href="/study/csharp/sp2_generics.html">ジェネリクス</a>導入前の名残で、互換性のためだけに残されているものです。)</p>
<h2><a id="await-foreach">非同期foreach</h2>
<p>仕組みが単純なので、データの消費側(非同期<code>foreach</code>)の方を先に説明します。
以下のように、<code>await foreach</code> と書くことで、
<code>IAsyncEnumerable&lt;T&gt;</code> (と同じパターンを持つ型)の列挙ができます。</p>
<pre class="source" title="非同期 foreach">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">AsyncForeach</span>(<span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">items</span>)
{
    <em><span class="reserved">await</span> <span class="control">foreach</span></em> (<span class="reserved">var</span> <span class="variable">item</span> <span class="control">in</span> <span class="variable">items</span>)
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">item</span>);
    }
}
</code></pre>
<p><a href="/study/csharp/sp5_async.html#async"><code>await</code></a>演算子と同じく、
非同期メソッド(<code>async</code> 修飾が付いたメソッド)内でだけ使えます。</p>
<p>このコードは、同期版の<code>foreach</code>と似たような感じで、以下のように展開されます。 同期版と比べて、<code>MoveNext</code>と<code>Dispose</code>が非同期になっただけです。</p>
<pre class="source" title="非同期foreachの展開結果">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">AsyncForeach</span>(<span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">items</span>)
{
    <span class="reserved">var</span> <span class="variable">e</span> = <span class="variable">items</span>.<span class="method">GetAsyncEnumerator</span>();
    <span class="control">try</span>
    {
        <span class="control">while</span> (<span class="reserved">await</span> <span class="variable">e</span>.<span class="method">MoveNextAsync</span>())
        {
            <span class="reserved">int</span> <span class="variable">item</span> = <span class="variable">e</span>.Current;
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">item</span>);
        }
    }
    <span class="control">finally</span>
    {
        <span class="control">if</span> (<span class="variable">e</span> != <span class="reserved">null</span>)
        {
            <span class="reserved">await</span> <span class="variable">e</span>.<span class="method">DisposeAsync</span>();
        }
    }
}
</code></pre>
<p>同期版と同じく、<code>finally</code>内の処理にはいくつかバリエーションがあります。</p>
<ul>
<li>enumerator (上記の例で言う <code>e</code>)が構造体なら null チェックは挟まらない</li>
<li><code>DisposeAsync</code> を持っていない場合は<code>finally</code>内の処理自体消える</li>
</ul>
<h3><a id="pattern-based-await-foreach">パターン ベース</h3>
<p>パターン ベースなので、インターフェイスを実装していなくても、
所定のメソッドさえ持っていれば非同期<code>foreach</code>で使えます。
以下はその一例です。</p>
<pre class="source" title="パターン ベースで非同期foreachに対応する型の例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">struct</span> <span class="type">A</span>
{
    <span class="comment">// このメソッドが「Enumerable」の必須要件。</span>
    <span class="comment">// この例では自分自身を返している(それでもOK)ものの、通常は別の型を作って返す。</span>
    <span class="reserved">public</span> <span class="type">A</span> <span class="method">GetAsyncEnumerator</span>() =&gt; <span class="reserved">this</span>;
 
    <span class="comment">// 以下の2つが「Enumerator」の必須要件。</span>
    <span class="reserved">public</span> <span class="reserved">int</span> Current =&gt; 0;
    <span class="reserved">public</span> <span class="type">ValueTask</span>&lt;<span class="reserved">bool</span>&gt; <span class="method">MoveNextAsync</span>()
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;MoveNextAsync&quot;</span>);
        <span class="control">return</span> <span class="reserved">new</span> <span class="type">ValueTask</span>&lt;<span class="reserved">bool</span>&gt;(<span class="reserved">false</span>);
    }
 
    <span class="comment">// DisposeAsync はなくてもいい。なければ呼ばれないだけ。</span>
    <span class="reserved">public</span> <span class="type">ValueTask</span> <span class="method">DisposeAsync</span>()
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;DisposeAsync&quot;</span>);
        <span class="control">return</span> <span class="reserved">default</span>;
    }
 
    <span class="comment">// 同期の Dispose は定義してあっても呼ばれないので注意。</span>
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">await</span> <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="reserved">new</span> <span class="type">A</span>()) ;
    }
}
</code></pre>
<p>この例では<code>ValueTask</code>型を使っていますが、これすらもパターン ベースで大丈夫です。
要は、<code>await</code>可能であれば型は問いません。
また、<a href="/study/csharp/sp_foreach.html#extension-getenumerator">通常の <code>foreach</code> と同じく</a>、C# 9.0 から拡張メソッドも受け付けるようになりました。</p>
<p>また、後から追加された構文だけあって、同期版の<code>foreach</code>よりもパターンの条件が緩いです。以下のように、オプション引数や可変長引数が付いていても平気です(同期版はダメ)。</p>
<pre class="source" title="非同期foreachは求められるパターンが緩い">
<code><span class="reserved">using</span> System.Threading;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">struct</span> <span class="type">A</span>
{
    <span class="comment">// 可変長引数があってもいい</span>
    <span class="reserved">public</span> <span class="type">A</span> <span class="method">GetAsyncEnumerator</span>(<span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable">dummy</span>) =&gt; <span class="reserved">this</span>;
 
    <span class="reserved">public</span> <span class="reserved">int</span> Current =&gt; 0;
 
    <span class="comment">// オプション引数があってもいい。</span>
    <span class="reserved">public</span> <span class="type">ValueTask</span>&lt;<span class="reserved">bool</span>&gt; <span class="method">MoveNextAsync</span>(<span class="type">CancellationToken</span> <span class="variable">token</span> = <span class="reserved">default</span>) =&gt; <span class="reserved">default</span>;
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">await</span> <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="reserved">new</span> <span class="type">A</span>()) ;
    }
}
</code></pre>
<h2><a id="await-using">非同期using</h2>
<p>前節の非同期<code>foreach</code>の展開結果には<code>DisposeAsync</code>の呼び出しが含まれていました。
また、<code>IAsyncEnumerator&lt;T&gt;</code>は<code>IAsyncDisposable</code>から派生しています。</p>
<p>これは同期版の頃(<a href="/study/csharp/sp_foreach.html#foreach"><code>foreach</code>の展開結果</a>)からある仕様で、同期版にも<code>Dispose</code>の呼び出しが含まれています。
この処理は、<a href="/study/csharp/oo_dispose.html#using"><code>using</code>ステートメント</a>がやっていることと同じです。
すなわち、<code>foreach</code>は<code>using</code>を兼ねています。</p>
<p>ということで、
非同期<code>foreach</code>が追加するのであれば、
同時に非同期<code>using</code>も追加するのが妥当です。
そこで実際、C# 8.0で非同期<code>using</code>が追加されています。</p>
<p>非同期<code>foreach</code>と同様<code>await using</code>という書き方をします。</p>
<pre class="source" title="非同期using">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">AsyncUsing</span>(<span class="type">IAsyncDisposable</span> <span class="variable">d</span>)
{
    <em><span class="reserved">await</span> <span class="reserved">using</span></em> (<span class="variable">d</span>)
    {
        <span class="comment">// d を破棄する前にやっておきたい処理</span>
    }
}
</code></pre>
<p>これも非同期<code>foreach</code>と同様に、非同期メソッド(async 修飾が付いたメソッド)内でだけ使えます。</p>
<p>展開結果は、同期版で<code>Dispose()</code>呼び出しだった部分が<code>await DisposeAsync()</code>に変わっているだけです。
上記のコードは以下のように展開されます。</p>
<pre class="source" title="非同期usingの展開結果">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">AsyncUsing</span>(<span class="type">IAsyncDisposable</span> <span class="variable">d</span>)
{
    <span class="control">try</span>
    {
        <span class="comment">// d を破棄する前にやっておきたい処理</span>
    }
    <span class="control">finally</span>
    {
        <span class="reserved">await</span> <span class="variable">d</span>.<span class="method">DisposeAsync</span>();
    }
}
</code></pre>
<h3><a id="pattern-based-await-using">パターン ベース</h3>
<p>「<a href="/study/csharp/misc/miscpatternbased/#converse">パターン ベースな構文</a>」で説明していますが、同期版の<code>using</code>は数少ない「インターフェイス実装が必須な構文」です。</p>
<p>一方、非同期<code>using</code>はパターン ベースになっています。
以下のように、<code>IAsyncDisposable</code>インターフェイスを実装せず、
単に<code>DisposeAsync</code>メソッドを持っていれば<code>await using</code>で使えます。</p>
<pre class="source" title="パターン ベースな非同期using">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.CompilerServices;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="comment">// 非同期 using は別に IAsyncDisposable インターフェイスの実装を求めない。</span>
<span class="reserved">class</span> <span class="type">AsyncDisposable</span>
{
    <span class="comment">// ちゃんと await using のブロックの最後で呼ばれる。</span>
    <span class="comment">// 戻り値の型が Task や ValueTask である必要もない。</span>
    <span class="reserved">public</span> <span class="type">MyAwaitable</span> <span class="method">DisposeAsync</span>()
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;disposed async&quot;</span>);
        <span class="control">return</span> <span class="reserved">default</span>;
    }
}
 
<span class="reserved">struct</span> <span class="type">MyAwaitable</span> { <span class="reserved">public</span> <span class="type">ValueTaskAwaiter</span> <span class="method">GetAwaiter</span>() =&gt; <span class="reserved">default</span>; }
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">await</span> <span class="reserved">using</span> (<span class="reserved">new</span> <span class="type">AsyncDisposable</span>())
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;inside using&quot;</span>);
        }
    }
}
</code></pre>
<p>見ての通り、<code>DisposeAsync</code>の戻り値は<code>await</code>可能でさえあれば何でも構いません。</p>
<p>また、オプション引数や可変長引数があっても構いません。</p>
<pre class="source" title="オプション引数などがあってもawait using可能">
<code><span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">struct</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="type">ValueTask</span> <span class="method">DisposeAsync</span>(<span class="reserved">int</span> <span class="variable">dummy</span> = 0) =&gt; <span class="reserved">default</span>;
}
 
<span class="reserved">struct</span> <span class="type">B</span>
{
    <span class="reserved">public</span> <span class="type">ValueTask</span> <span class="method">DisposeAsync</span>(<span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable">dummy</span>) =&gt; <span class="reserved">default</span>;
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">await</span> <span class="reserved">using</span> (<span class="reserved">new</span> <span class="type">A</span>()) { }
        <span class="reserved">await</span> <span class="reserved">using</span> (<span class="reserved">new</span> <span class="type">B</span>()) { }
    }
}
</code></pre>
<p>制限と言えば、インスタンス メソッドしか受け付けない(拡張メソッドは使えない)くらいです。</p>
<p>一方で、同期版と違って、<a href="/study/csharp/misc_as.html"><code>as</code>演算子</a>を使った動的な型チェックはしません。
以下のように、直接的には<code>IAsyncDisposable</code>インターフェイスを実装していなくて、
パターンも満たさない型に対して<code>await using</code>を使うとコンパイル エラーになります。</p>
<pre class="source" title="">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">class</span> <span class="type">A</span> { }
 
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">A</span>, <span class="type">IAsyncDisposable</span>
{
    <span class="reserved">public</span> <span class="type">ValueTask</span> <span class="method">DisposeAsync</span>() =&gt; <span class="reserved">default</span>;
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="comment">// A は IAsyncDisposable じゃないけど、</span>
        <span class="comment">// 派生クラスの B は IAsyncDisposable を実装。</span>
        <span class="reserved">await</span> <span class="method">AsyncUsing</span>(<span class="reserved">new</span> <span class="type">B</span>());
    }
 
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">AsyncUsing</span>(<span class="type">A</span> <span class="variable">a</span>)
    {
        <span class="comment">// これはコンパイル エラーになる。</span>
        <span class="comment">// A が直接 IAsyncDisposable を実装しているか、パターンを満たしている必要がある。</span>
        <span class="reserved">await</span> <span class="reserved">using</span> (<span class="error"><span class="variable">a</span></span>) { }
    }
}
</code></pre>
<p>ジェネリック型引数に対して使う場合にも、<code>IAsyncDisposable</code>制約が必要になります。</p>
<pre class="source" title="IAsyncDisposable 制約が必須">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">x</span>)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">IAsyncDisposable</span> <span class="comment">// この制約がないと await using の行でコンパイル エラーに。</span>
{
    <span class="reserved">await</span> <span class="reserved">using</span> (<span class="variable">x</span>) { }
}

</code></pre>
<h3><a id="await-using-declaration">using変数宣言との併用</h3>
<p><a href="/study/csharp/oo_dispose.html#using-declaration"><code>using</code>変数宣言</a>との併用も可能です。
以下のような書き方ができます。</p>
<pre class="source" title="非同期using変数宣言の例">
<code><span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">struct</span> <span class="type">AsyncDisposable</span>
{
    <span class="reserved">public</span> <span class="type">ValueTask</span> <span class="method">DisposeAsync</span>() =&gt; <span class="reserved">default</span>;
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">await</span> <span class="reserved">using</span> <span class="reserved">var</span> <span class="variable">x</span> = <span class="reserved">new</span> <span class="type">AsyncDisposable</span>();
 
        <span class="comment">// このメソッドを抜けるタイミングで DisposeAsync が呼ばれる</span>
    }
}
</code></pre>
<h3><a id="sync-and-async">DisposeとDisposeAsyncの混在</h3>
<p>ちなみに、<code>Dispose</code>(<code>IDisposable</code>インターフェイス)と<code>DisposeAsync</code>(<code>IAsyncDisposable</code>インターフェイス)の両方を実装をしている場合、それぞれ同期版<code>using</code>、非同期<code>using</code>でしか呼ばれません。
非同期版が同期版を兼ねたりはしませんし、その逆もまたしかり。</p>
<p>以下の例では、<code>using</code>の行では<code>Dispose</code>だけが呼ばれますし、
<code>await using</code>の行では<code>DisposeAsync</code>だけが呼ばれます。</p>
<pre class="source" title="usingとawait usingは独立">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">struct</span> <span class="type">Disposable</span> : <span class="type">IDisposable</span>, <span class="type">IAsyncDisposable</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() =&gt; <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;同期 Dispose&quot;</span>);
    <span class="reserved">public</span> <span class="type">ValueTask</span> <span class="method">DisposeAsync</span>()
    {
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;非同期 Dispose&quot;</span>);
        <span class="control">return</span> <span class="reserved">default</span>;
    }
}
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">d</span> = <span class="reserved">new</span> <span class="type">Disposable</span>();
 
        <span class="comment">// Dispose だけが呼ばれる</span>
        <span class="reserved">using</span> (<span class="variable">d</span>) { }
 
        <span class="comment">// DisposeAsync だけが呼ばれる</span>
        <span class="reserved">await</span> <span class="reserved">using</span> (<span class="variable">d</span>) { }
    }
}
</code></pre>
<h2><a id="async-iterator">非同期イテレーター</h2>
<p><a href="#await-foreach">非同期<code>foreach</code></a>とは逆の、データの生成側の機能が非同期イテレーターです。
簡単に言うと、<a href="/study/csharp/sp2_iterator.html#block"><code>yield</code></a>と<a href="/study/csharp/sp5_async.html#async"><code>await</code></a>の混在ができるようになりました。</p>
<p>例えば以下のような書き方で、1秒に1回、整数値を生成するイテレーターになります。</p>
<pre class="source" title="非同期イテレーターの例">
<code><span class="reserved">static</span> <em><span class="reserved">async</span></em> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="method">GenerateAsync</span>()
{
    <span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; ; <span class="variable">i</span>++)
    {
        <em><span class="control">yield</span> <span class="control">return</span></em> <span class="variable">i</span>;
        <em><span class="reserved">await</span></em> <span class="type">Task</span>.<span class="method">Delay</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(1));
    }
}
</code></pre>
<p>同期版のイテレーター(<code>yield</code>)は以下のような条件を満たすものでした。</p>
<ul>
<li>関数(メソッドなど)の本体の中に<code>yield return</code>もしくは<code>yield break</code>を含む</li>
<li>戻り値の型は <code>IEnumerable</code>、<code>IEnumerator</code>(<code>System.Collection</code>名前空間)、もしくは、<code>IEnumerable&lt;T&gt;</code>、<code>IEnumerator&lt;T&gt;</code>(<code>System.Collection.Generic</code>名前空間)のいずれか</li>
</ul>
<p>また、非同期メソッドは以下のようなものです。</p>
<ul>
<li>
メソッドに<code>async</code>修飾子が付いている
<ul>
<li>この場合に限り、メソッド内に<code>await</code>演算子を書ける</li>
</ul>
</li>
</ul>
<p>非同期イテレーターはこれらの組み合わせなので、以下のようなものになります。</p>
<ul>
<li>関数(メソッドなど)の本体の中に<code>yield return</code>もしくは<code>yield break</code>を含む</li>
<li>戻り値の型は <code>IAsyncEnumerable&lt;T&gt;</code>、<code>IAsyncEnumerator&lt;T&gt;</code>(<code>System.Collection.Generic</code>名前空間)のいずれか</li>
<li>
メソッドに<code>async</code>修飾子が付いている
<ul>
<li>メソッド内に<code>await</code>演算子を書ける</li>
</ul>
</li>
</ul>
<h3><a id="compiled">非同期イテレーターのコンパイル結果</h3>
<p>非同期イテレーターの仕組みは、同期版のイテレーターや非同期メソッドの延長線上にあります。
それぞれについては以下のページで説明しています。</p>
<ul>
<li><a href="/study/csharp/sp2_iterator.html#complied">イテレーターのコンパイル結果</a></li>
<li><a href="/study/csharp/sp5_awaitable.html#statemachine">非同期メソッドの内部実装</a></li>
</ul>
<p>これら2つは原理的には非常に似ています。
というより、非同期メソッド自体、イテレーターから着想を得て作られた機能です。
なので、パフォーマンス チューニングなど細かい点を除けば、組み合わせることはそれほど難しくはありません。
(ただ、いずれも元々相当複雑なコード生成になるので、
組み合わせた上でパフォーマンスにも配慮すると結構難解なコード生成になります。)</p>
<p>原理だけ簡単に説明すると、非同期イテレーター中に<code>yield return x</code>と書くと、
概ね以下のようなコードが生成されます。</p>
<pre class="source" title="yield return の置き換え">
<code>_state = State1;             <span class="comment">// 次に復帰するときのための状態の記録</span>
Current = x;                 <span class="comment">// 戻り値を Current に保持</span>
_taskSource.<span class="method">SetResult</span>(<span class="reserved">true</span>); <span class="comment">// MoveNextAsync の戻り値で返した Task を完了させる</span>
<span class="control">return</span>;                      <span class="comment">// 一旦処理終了</span>
<span class="reserved">case</span>: State1:                <span class="comment">// 時宜に呼ばれたときに続きから処理するためのラベル</span>
</code></pre>
<p>(<a href="(/study/csharp/sp2_iterator.html#complied)">同期版での説明</a>と同様、疑似コードです。実際の C# では case に変数は使えないので、 「これに相当する goto が生成される」くらいのものだと思って読んでください。)</p>
<p><code>_taskSource</code>は、現状の実装では<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.sources.manualresetvaluetasksourcecore-1"><code>ManualResetValueTaskSourceCore</code></a>という型を使っています。
既存の型で言うと<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.taskcompletionsource-1"><code>TaskCompletionSource&lt;T&gt;</code></a>と似た型というか、用途的には完全に同じで、
パフォーマンス最適化のために導入された構造体です。
(パフォーマンスはいいですが、使い勝手は少し煩雑になります。)</p>
<h3><a id="contextual-keyword">余談: 文脈キーワード</h3>
<p><a href="/study/csharp/ap_compatibility.html">C# は後方互換性を非常に重要視する言語</a>なので、
<code>yield</code>や<code>await</code>は<a href="/study/csharp/ap_compatibility.html#contextual-keyword">文脈キーワード</a>になっています。
例えば、以下のようなコードでは<code>yield</code>や<code>await</code>がキーワード扱いされず、
普通に変数として使えています。</p>
<pre class="source" title="yield変数とawait変数">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>()
{
    <span class="reserved">var</span> <span class="variable">yield</span> = 2;
    <span class="reserved">var</span> <span class="variable">await</span> = 3;
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">yield</span> * <span class="variable">await</span>);
}
</code></pre>
<p>ただ、この2つは文脈の作り方が異なります。</p>
<ul>
<li>
<code>yield</code>は、<code>yield return</code>もしくは<code>yield break</code>というように、2単語が並んだ場合だけキーワード扱いされる
<ul>
<li>このキーワードを含んだ時点でイテレーター扱いされる</li>
</ul>
</li>
<li>
<code>await</code>は、メソッド自体に<code>async</code>修飾子が付いているときだけキーワード扱いされる
<ul>
<li><code>async</code>修飾子は「<code>await</code>がキーワードになるかどうか」の目印的な意味しかない</li>
</ul>
</li>
</ul>
<p>非同期イテレーターの導入にあたって、
方式が異なる2つのものを混ぜることに対する懸念もありました。
<code>yield</code>の「含んだ時点でイテレーターになる」というのはコンパイラーにとって結構負担があるらしく、<a href="/study/csharp/functional/fun_localfunctions/#anonymous-function">匿名関数</a>をイテレーターに出来ないという問題があったりもします。
そのため、「イテレーターにも<code>iterator</code>修飾子みたいなものを足そうか」という話が出たこともあります。
しかし、「同じ用途の別文法」を作ってしまう混乱を起こしてまで実現する課題ではないという判断になり、結局2方式の混在が採用されました。</p>
<h3><a id="EnumeratorCancellation">キャンセル</h3>
<p><code>IAsyncEnumerable&lt;T&gt;</code>インターフェイスの<code>GetAsyncEnumerator</code>メソッドには<code>CancellationToken</code>を渡せるようになっていて、これを使って非同期処理の途中キャンセルをする想定になっています。</p>
<p>非同期イテレーターでは、以下のように、引数に<code>EnumeratorCancellation</code>属性(<code>System.Runtime.CompilerServices</code>名前空間)を付けることでこの<code>CancellationToken</code>を受け取れるようになります。</p>
<pre class="source" title="非同期イテレーターへのCancellationTokenの渡し方">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Runtime.CompilerServices;
<span class="reserved">using</span> System.Threading;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">cts</span> = <span class="reserved">new</span> <span class="type">CancellationTokenSource</span>();
 
        <span class="reserved">var</span> <span class="variable">enumerable</span> = <span class="method">GenerateAsync</span>();
 
        <span class="comment">// ここで引数に渡したトークンが、GenerateAsync の ct 引数にわたる。</span>
        <span class="reserved">var</span> <span class="variable">enumerator</span> = <span class="variable">enumerable</span>.<span class="method">GetAsyncEnumerator</span>(<em><span class="variable">cts</span>.Token</em>);
 
        <span class="comment">// キャンセル前なので値が取れるはず。</span>
        <span class="reserved">await</span> <span class="variable">enumerator</span>.<span class="method">MoveNextAsync</span>();
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">enumerator</span>.Current);
 
        <span class="variable">cts</span>.<span class="method">Cancel</span>();
 
        <span class="comment">// キャンセルしたので止まるはず。</span>
        <span class="control">if</span> (!<span class="reserved">await</span> <span class="variable">enumerator</span>.<span class="method">MoveNextAsync</span>())
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;終了&quot;</span>);
    }
 
    <span class="comment">// キャンセルが掛かるまでずっと、1秒に1個値を生成。</span>
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="method">GenerateAsync</span>([<span class="type">EnumeratorCancellation</span>] <span class="type">CancellationToken</span> <span class="variable">ct</span> = <span class="reserved">default</span>)
    {
        <span class="reserved">var</span> <span class="variable">i</span> = 0;
        <span class="control">while</span> (!<span class="variable">ct</span>.IsCancellationRequested)
        {
            <span class="control">yield</span> <span class="control">return</span> <span class="variable">i</span>;
            <span class="reserved">await</span> <span class="type">Task</span>.<span class="method">Delay</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(1));
            ++<span class="variable">i</span>;
        }
    }
}
</code></pre>
<p>ちなみに、非同期<code>foreach</code>で使いたい場合、<code>WithCancellation</code>拡張メソッドが使えます。
<code>WithCancellation</code> の引数で渡した<code>CancellationToken</code>が<code>GetAsyncEnumerator</code>に伝搬し、
最終的に<code>GenerateAsync</code>の<code>ct</code>引数に渡ります。</p>
<pre class="source" title="WithCancellation での CancellationToken 伝搬">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Runtime.CompilerServices;
<span class="reserved">using</span> System.Threading;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">Main</span>()
    {
        <span class="comment">// 5秒後にキャンセルが掛かる。</span>
        <span class="reserved">var</span> <span class="variable">cts</span> = <span class="reserved">new</span> <span class="type">CancellationTokenSource</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(5));
 
        <span class="comment">// WithCancellation に渡したトークンが GenerateAsync まで伝搬する。</span>
        <span class="reserved">await</span> <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">i</span> <span class="control">in</span> <span class="method">GenerateAsync</span>().<span class="method">WithCancellation</span>(<span class="variable">cts</span>.Token))
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">i</span>);
        }
    }
 
    <span class="comment">// キャンセルが掛かるまでずっと、1秒に1個値を生成。</span>
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="method">GenerateAsync</span>([<span class="type">EnumeratorCancellation</span>] <span class="type">CancellationToken</span> <span class="variable">ct</span> = <span class="reserved">default</span>)
    {
        <span class="reserved">var</span> <span class="variable">i</span> = 0;
        <span class="control">while</span> (!<span class="variable">ct</span>.IsCancellationRequested)
        {
            <span class="control">yield</span> <span class="control">return</span> <span class="variable">i</span>;
            <span class="reserved">await</span> <span class="type">Task</span>.<span class="method">Delay</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(1));
            ++<span class="variable">i</span>;
        }
    }
}
</code></pre>
<p>引数越しに受け取る仕様なので、
以下のように、呼び出し側で引数に直接渡すのと、<code>WithCancellation</code>越しに渡すので、
2重に<code>CancellationToken</code>を渡せます。
この場合、2個のうちどちらか片方でも<code>Cancel</code>が掛かった時点でキャンセル扱いになります。
(正確に言うと、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.cancellationtokensource.createlinkedtokensource">CreateLinkedTokenSource </a>を使って新たに作った<code>CancellationToken</code>が渡ります。)</p>
<pre class="source" title="CancellationToken が2個渡る例">
<code><span class="comment">// CancellationToken を2個用意。</span>
<span class="reserved">var</span> <span class="variable">ct1</span> = <span class="reserved">new</span> <span class="type">CancellationTokenSource</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(3)).Token;
<span class="reserved">var</span> <span class="variable">ct2</span> = <span class="reserved">new</span> <span class="type">CancellationTokenSource</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(5)).Token;
 
<span class="comment">// 引数に直接渡せるし、WithCancellation でも渡せる。</span>
<span class="comment">// この場合、どちらか片方でも Cancel された時点でキャンセル扱い。</span>
<span class="comment">// (GenerateAsync には CreateLinkedTokenSource(ct1, ct2) した新しいトークンが渡る。)</span>
<span class="reserved">await</span> <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">i</span> <span class="control">in</span> <span class="method">GenerateAsync</span>(<span class="variable">ct1</span>).<span class="method">WithCancellation</span>(<span class="variable">ct2</span>))
{
    <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">i</span>);
}
</code></pre>
<!-- pageBreak -->
<h2><a id="usage">利用例</h2>
<p>(予定)</p>
<p>具体例いくつか挙げる</p>
<p><a href="https://github.com/dotnet/try/blob/master/Samples/csharp8/ExploreCsharpEight/AsyncStreams.cs">producer/consumer 的なの</a></p>
<pre class="source" title="">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="method">GenerateAsync</span>()
    {
        <span class="reserved">var</span> <span class="variable">r</span> = <span class="reserved">new</span> <span class="type">Random</span>();
 
        <span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; ; <span class="variable">i</span>++)
        {
            <span class="control">yield</span> <span class="control">return</span> <span class="variable">i</span>;
            <span class="reserved">await</span> <span class="type">Task</span>.<span class="method">Delay</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(<span class="variable">r</span>.<span class="method">NextDouble</span>()));
        }
    }
 
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">ConsumeAsync</span>(<span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable">source</span>)
    {
        <span class="reserved">var</span> <span class="variable">r</span> = <span class="reserved">new</span> <span class="type">Random</span>();
 
        <span class="reserved">await</span> <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">source</span>)
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span>);
            <span class="reserved">await</span> <span class="type">Task</span>.<span class="method">Delay</span>(<span class="type">TimeSpan</span>.<span class="method">FromSeconds</span>(<span class="variable">r</span>.<span class="method">NextDouble</span>()));
        }
    }
}

</code></pre>
<p>LINQ to Object 非同期版
(LINQ は今の実装だとパフォーマンス チューニングの結果イテレーター使わなくなったけど。
少なくとも初期実装はイテレーターだったし、
今でも「パフォーマンスよりもコードのきれいさ重視」だったらイテレーターを使うべき。)</p>
<pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="type">TResult</span>&gt; <span class="method">GenerateAsync</span>&lt;<span class="type">TSource</span>, <span class="type">TResult</span>&gt;(<span class="type">IAsyncEnumerable</span>&lt;<span class="type">TSource</span>&gt; <span class="variable">source</span>, <span class="type">Func</span>&lt;<span class="type">TSource</span>, <span class="type">TResult</span>&gt; <span class="variable">selector</span>)
{
    <span class="comment">// (お作法的には引数の null チェックすべき)</span>
    <span class="reserved">await</span> <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">source</span>)
    {
        <span class="control">yield</span> <span class="control">return</span> <span class="variable">selector</span>(<span class="variable">x</span>);
    }
}
</code></pre>
<p>非同期にまとまった単位のデータを読んで、データを1つ1つ列挙</p>
<pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">IAsyncEnumerable</span>&lt;<span class="reserved">string</span>&gt; <span class="method">ReadLinesAsync</span>(<span class="reserved">string</span> <span class="variable">directoryPath</span>)
{
    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">filePath</span> <span class="control">in</span> <span class="type">Directory</span>.<span class="method">GetFiles</span>(<span class="variable">directoryPath</span>, <span class="string">&quot;*.txt&quot;</span>))
    {
        <span class="reserved">var</span> <span class="variable">lines</span> = <span class="reserved">await</span> <span class="type">File</span>.<span class="method">ReadAllLinesAsync</span>(<span class="variable">filePath</span>);
 
        <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">line</span> <span class="control">in</span> <span class="variable">lines</span>)
        {
            <span class="control">yield</span> <span class="control">return</span> <span class="variable">line</span>;
        }
    }
}
</code></pre> ]]></description>
				<pubDate>Sun, 09 Jun 2019 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>パターン ベースな構文</title>
				<link>http://www.ufcpp.net/study/csharp/misc/miscpatternbased/</link>
				<description><![CDATA[ <h2><a id="abctract">概要</h2>
<p>C# の言語機能のいくつか(というか結構多くのもの)は、「所定のパターンを満たしている任意の型に使える」というものになっています。
そういう構文を指して「パターン ベース」(pattern-based)な構文と言ったりします。</p>
<p>本項では、パターン ベースにすることのメリットや、
実際にパターン ベースになっている構文について紹介します。</p>
<h2><a id="pattern-based">パターン ベース</h2>
<p>例えば C# 3.0 の<a href="/study/csharp/sp3_linq.html#query">クエリ式</a>がパターン ベースな構文の代表例です。
以下のような書き方をした場合、</p>
<pre class="source" title="クエリ式の例">
<code><span class="reserved">from</span> x <span class="reserved">in</span> <span class="variable">source</span>
<span class="reserved">where</span> x &lt; 10
<span class="reserved">select</span> x * x;
</code></pre>
<p>C# コンパイラーが以下のようなメソッド呼び出しに展開します。</p>
<pre class="source" title="クエリ式の展開結果の例">
<code><span class="variable">source</span>
    .<span class="method">Where</span>(<span class="variable">x</span> =&gt; <span class="variable">x</span> &lt; 10)
    .<span class="method">Select</span>(<span class="variable">x</span> =&gt; <span class="variable">x</span> * <span class="variable">x</span>);
</code></pre>
<p>C# コンパイラーは「<code>select</code>句を見たら<code>Select</code>メソッドに置き換える」というルールだけを提供していて、
<code>Select</code>メソッドをどう実装するかは自由にできます。</p>
<p>クエリ式に関しては本当にかなり自由度が高く、以下のように、だいぶ緩い条件で使えます。</p>
<ul>
<li>(<code>Select</code> メソッドなどを定義した)インターフェイス不要</li>
<li>戻り値の型には何の制約もない</li>
<li>インスタンス メソッドでも<a href="/study/csharp/sp3_extension.html">拡張メソッド</a>でもいい</li>
</ul>
<p>要するに、
「所定のパターンを満たしている任意の型に使える」ということです。
このこと、特に1番目の「インターフェイス不要」を指して、「<strong id="key-pattern-based" class="keyword">パターン ベース</strong>」(pattern-based)と言います。</p>
<p>(同じ単語が入っているのでちょっと紛らわしいですが、
<a href="/study/csharp/datatype/patterns/">パターン マッチング</a>とは無関係です。)</p>
<h3><a id="converse">パターン ベースな構文の対極</h3>
<p>逆に、インターフェイスの実装が必須の構文が1つだけあって、<a href="/study/csharp/oo_dispose.html#using"><code>using</code> ステートメント</a>がそうです。
(ただし、C# 8.0 で、<a href="/study/csharp/oo_dispose.html#pattern-based-using"><code>ref struct</code> に対してだけは緩和されています</a>。)</p>
<pre class="source" title="using ステートメントはインターフェイス必須">
<code><span class="reserved">using</span> System;
 
<span class="reserved">struct</span> <span class="type">Disposable</span>
    <span class="comment">// インターフェイス実装が必須。</span>
    <span class="comment">// 以下の行をコメントアウトするとコンパイル エラーになる。</span>
    : <span class="type">IDisposable</span>
{
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Dispose</span>() { }
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">using</span> (<span class="reserved">var</span> <span class="variable">d</span> = <span class="reserved">new</span> <span class="type">Disposable</span>()) ;
    }
}
</code></pre>
<p>また、パターン ベースの逆という意味では、
C# コンパイラーだけではできない言語機能もあります。
<a href="/study/csharp/sp2_generics.html">ジェネリクス</a>や<a href="/study/csharp/oo_interface.html?p=5#dim">インターフェイスのデフォルト実装</a>がそうで、
これらは新しい .NET ランタイム(ジェネリクスは .NET Framework 2.0 以降、インターフェイスのデフォルト実装は .NET Core 3.0 以降)が必要になります。</p>
<p>ただ、パターン ベースでは実現不可能でも、「.NET ランタイム的には昔から機能を持っていて、C# 上認められていなかっただけ」というものあります。
例えば C# 4.0 で<a href="/study/csharp/ap_ver4.html#optional">オプション引数</a>と<a href="/study/csharp/ap_ver4.html#variance">ジェネリクスの共変・反変性</a>という機能が入りましたが、
ランタイム側はもっと昔から(それぞれ .NET Framework 1.0、2.0 時点で)対応していました。
なので、C# コンパイラーだけの更新で実現可能でした。</p>
<h2><a id="advantage">パターン ベースの利点</h2>
<p>新しい構文をパターン ベースに実装するのには2つの利点があります。</p>
<ul>
<li>C# コンパイラーだけでできる/古い .NET ランタイム上でも動く</li>
<li><a href="/study/csharp/oo_vftable.html">仮想呼び出し</a>が挟まらない</li>
</ul>
<h3><a id="syntax-sugar">C# コンパイラーだけでできる</h3>
<p>パターン ベースな置き換えは C# コンパイラーだけでできる仕事になります。</p>
<p>「<a href="/study/csharp/st_compile.html#dotnet">.NET プログラム</a>」で説明しているように、
C# は、</p>
<ul>
<li>C# コンパイラーは、C# ソースコードを中間言語(IL)と呼ばれる汎用的な命令に翻訳する</li>
<li>.NET ランタイムが IL を CPU 依存で高速な命令に置き換える</li>
</ul>
<p>という2段階に分けてプログラムを実行しています。
C# コンパイラーがしている仕事の方が比較的楽で、
C# コンパイラーだけの修正で済むなら実装コストがだいぶ低いです。</p>
<p>実装コストの問題だけでなく、
古いランタイムでも動くというメリットもあります。
例えば、2017年リリースの C# 7.0 の機能(例えば<a href="/study/csharp/datatype/deconstruction/">分解</a>)を使ったプログラムが、
2002年 リリースの .NET Framework 1.0 上でも動かせたりします。</p>
<p>(.NET Framework 1.0  は 2017年時点ですでにサポートも切れています。
サポート外のランタイム上ですら、新しい言語機能を使えたりします。)</p>
<h3><a id="non-virtual">仮想呼び出しを避ける</h3>
<p>詳細は「<a href="/study/csharp/oo_vftable.html">[雑記] 仮想関数テーブル</a>」で説明していますが、
<a href="/study/csharp/oo_polymorphism.html#virtual"><code>virtual</code> なメソッド</a>には、一段階テーブルをはさむコストが発生します。</p>
<p>また、付随して以下のようなコストがかかる場合があります。</p>
<ul>
<li><a href="/study/csharp/structured/miscinlining/">インライン化</a>を阻害する</li>
<li><a href="/study/csharp/resource/oo_reference?key=valtype">値型</a>の場合、<a href="/study/csharp/RmBoxing.html">ボックス化</a>が発生することがある</li>
</ul>
<p>例えば以下のような型があったとします。</p>
<pre class="source" title="分解可能な型の例">
<code><span class="reserved">interface</span> <span class="type">IDeconstructibleTo2Ints</span>
{
    <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">y</span>);
}
 
<span class="reserved">struct</span> <span class="type">Point</span> : <span class="type">IDeconstructibleTo2Ints</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">Point</span>(<span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>) =&gt; (X, Y) = (<span class="variable">x</span>, <span class="variable">y</span>);
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Deconstruct</span>(<span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">out</span> <span class="reserved">int</span> <span class="variable">y</span>) =&gt; (<span class="variable">x</span>, <span class="variable">y</span>) = (X, Y);
}
</code></pre>
<p>この型は<a href="/study/csharp/datatype/deconstruction/">分解</a>構文を使えるように作ってあります。
(分解は <code>Deconstruct</code> メソッドの呼び出しに展開されます。)
分解もパターン ベースなので、インターフェイスは必須ではありません。</p>
<p>この型に対して、以下のような2つのメソッドを考えます。
どちらも <code>Deconstruct</code> メソッドに展開されますが、
<code>Sum1</code> はパターン ベース(<code>Point</code>構造体の<code>Deconstruct</code>が直接呼ばれる)、
<code>Sum2</code> はインターフェイスを介しています。</p>
<pre class="source" title="分解がインターフェイスを介するかどうか">
<code><span class="comment">// Point を直接分解。</span>
<span class="comment">// 最終的にインライン展開が働いて、単なる p.X + p.Y に展開される(ものすごく高速)。</span>
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">Sum1</span>(<span class="type">Point</span> <span class="variable">p</span>)
{
    <span class="reserved">var</span> (<span class="variable">x</span>, <span class="variable">y</span>) = <span class="variable">p</span>;
    <span class="control">return</span> <span class="variable">x</span> + <span class="variable">y</span>;
}
 
<span class="comment">// インターフェイスを介して分解。</span>
<span class="comment">// インライン展開が効かず、ボックス化も起きてるので遅い。</span>
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">Sum2</span>(<span class="type">IDeconstructibleTo2Ints</span> <span class="variable">p</span>)
{
    <span class="reserved">var</span> (<span class="variable">x</span>, <span class="variable">y</span>) = <span class="variable">p</span>;
    <span class="control">return</span> <span class="variable">x</span> + <span class="variable">y</span>;
}
</code></pre>
<p><a href="https://gist.github.com/ufcpp/a09030dd049f20d10e2504edf3711926">ベンチマークを取ってみれば</a>わかるんですが、
<code>Sum1</code>は最適化によってほとんど消えることすらあって、計測できない(誤差しか残らない)くらい高速です。
一方、<code>Sum2</code>はボックス化で24バイトのゴミが発生しますし、実行に数ミリ秒要します。</p>
<p>パターン ベースである(インターフェイスを要求しない)ことで、このくらいの速度差が生じます。</p>
<h2><a id="flexibility">パターンの自由度</h2>
<p>ということで、C# の構文の多くがパターン ベースな実装になっています。
ただ、実装された時期によってどのくらい自由が利くかに差があったりします。
(基本的には新しいものほど自由が利く。ただ、新しいものでも、他の構文との兼ね合いで制限が掛かる場合がある。)</p>
<p>一番自由が利くのはクエリ式です。
例えば、クエリ式(の<code>where</code>と<code>select</code>)を使える最低限のコードを書くと以下のようになります。
(意味のあることはしていません。単に、クエリ式で使えるというだけです。)</p>
<pre class="source" title="クエリ式を使うための最低限の型の例">
<code><span class="reserved">using</span> System;
 
<span class="reserved">struct</span> <span class="type">Queryable</span>
{
    <span class="reserved">public</span> <span class="type">Queryable</span> <span class="method">Where</span>(<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">bool</span>&gt; <span class="variable">f</span>) =&gt; <span class="reserved">this</span>;
    <span class="reserved">public</span> <span class="type">Queryable</span> <span class="method">Select</span>(<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span>) =&gt; <span class="reserved">this</span>;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">q</span> =
            <span class="reserved">from</span> x <span class="reserved">in</span> <span class="reserved">new</span> <span class="type">Queryable</span>()
            <span class="reserved">where</span> x &lt; 10
            <span class="reserved">select</span> x * x;
    }
}
</code></pre>
<p>これに対して、融通が利くポイントが2つあります。</p>
<ul>
<li><a href="/study/csharp/ap_ver4.html#optional">オプション引数</a>や<a href="/study/csharp/sp_params.html">可変長引数</a>が付いていてもいい</li>
<li><a href="/study/csharp/sp3_extension.html">拡張メソッド</a>でもいい</li>
</ul>
<p>例えば、上記のコードは以下のように書き換えてもコンパイルできます。</p>
<pre class="source" title="拡張メソッドやオプション引数の許容">
<code><span class="reserved">using</span> System;
 
<span class="reserved">struct</span> <span class="type">Queryable</span>
{
    <span class="reserved">public</span> <span class="type">Queryable</span> <span class="method">Where</span>(<span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">bool</span>&gt; <span class="variable">f</span>, <em><span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable">dummy</span></em>) =&gt; <span class="reserved">this</span>;
}
 
<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">QueryableExtensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Queryable</span> <span class="method">Select</span>(<em><span class="reserved">this</span></em> <span class="type">Queryable</span> <span class="variable">q</span>, <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span>, <em><span class="reserved">int</span> <span class="variable">dummy</span> = 0</em>) =&gt; <span class="variable">q</span>;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">q</span> =
            <span class="reserved">from</span> x <span class="reserved">in</span> <span class="reserved">new</span> <span class="type">Queryable</span>()
            <span class="reserved">where</span> x &lt; 10
            <span class="reserved">select</span> x * x;
    }
}
</code></pre>
<h2><a id="index">パターン ベースな構文一覧</h2>
<p>以下に、パターン ベースになっている構文の一覧を示します。</p>
<table>
<thead>
<tr>
	<th>構文</th>
	<th>拡張メソッド可</th>
	<th>オプション引数可</th>
</tr>
</thead>
<tbody>
<tr>
	<td><a href="/csharp/sp3_stdquery.html">クエリ式</a></td>
	<td>〇</td>
	<td>〇</td>
</tr>
<tr>
	<td><a href="/study/csharp/sp3_lambda.html?key=collectioninit#collectioninit">コレクション初期化子</a></td>
	<td>〇<sup>※1</sup></td>
	<td>〇</td>
</tr>
<tr>
	<td><a href="/study/csharp/datatype/deconstruction/#arbitrary-types">分解</a></td>
	<td>〇</td>
	<td>×</td>
</tr>
<tr>
	<td><a href="/study/csharp/sp5_awaitable.html#awaiter">await</a></td>
	<td>〇</td>
	<td>×</td>
</tr>
<tr>
	<td><a href="/study/csharp/async/asyncstream#await-foreach">await foreach</a></td>
	<td>〇<sup>※4</sup></td>
	<td>〇</td>
</tr>
<tr>
	<td><a href="/study/csharp/async/asyncstream#await-using">await using</a></td>
	<td>×</td>
	<td>〇</td>
</tr>
<tr>
	<td><a href="/study/csharp/sp_foreach.html">foreach</a><sup>※2</sup></td>
	<td>〇<sup>※4</sup></td>
	<td>×</td>
</tr>
<tr>
	<td><a href="/study/csharp/sp_unsafe.html#custom-fixed">fixed</a></td>
	<td>×</td>
	<td>×</td>
</tr>
<tr>
	<td><a href="/study/csharp/oo_dispose.html#using">using</a><sup>※3</sup></td>
	<td>×</td>
	<td>×</td>
</tr>
</tbody>
</table>
<p><sup>※1</sup> <a href="/study/csharp/ap_ver6.html#add-extensions">拡張メソッド可になったのは C# 6.0 から</a></p>
<p><sup>※2</sup> ループの最後に <code>Dispose</code> が呼ばれるためにはインターフェイスの実装、もしくは、<a href="/study/csharp/oo_dispose.html#pattern-based-using"><code>ref struct</code> である必要があります</a>。</p>
<p><sup>※3</sup> <a href="/study/csharp/oo_dispose.html#pattern-based-using"><code>ref struct</code> 限定</a>でパターン ベース。クラスや通常の構造体の場合はインターフェイスの実装が必須。</p>
<p><sup>※4</sup> <a href="/study/csharp/sp_foreach.html#extension-getenumerator">拡張メソッド可になったのは C# 9.0 から</a></p>
<p><code>foreach</code> と <code>await foreach</code>、<code>using</code> と <code>await using</code> の差は実装時期の差によるものです。
非同期版(<code>await</code> 付き)の方が C# 8.0 での実装と新しく、制限が緩和されています。
C# 8.0 の計画段階では既存の(同期の) <code>foreach</code> や <code>using</code> の制限緩和も検討されましたが、
破壊的変更になりそうとのことで断念されました。
<a href="/study/csharp/resource/refstruct/"><code>ref struct</code></a>に対してだけは、
そもそも <code>ref struct</code> 自体が新しくて破壊的変更の影響が少ないことと、
ないと困るという理由で<a href="/study/csharp/oo_dispose.html#pattern-based-using">制限が緩和されています</a>。</p>
 ]]></description>
				<pubDate>Sun, 09 Jun 2019 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>インデックス/範囲処理</title>
				<link>http://www.ufcpp.net/study/csharp/data/dataranges/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 で、配列などに対して以下のような書き方をできるようになります。</p>
<ul>
<li><code>a[^i]</code> で「後ろからi番目の要素」を参照</li>
<li><code>a[i..j]</code> で「i番目からj番目の範囲」を参照</li>
</ul>
<p>例えば、以下のような書き方で配列の前後1要素ずつを削ったものを得ることができます。</p>
<pre class="source" title=".. 構文">
<code><span class="reserved">using</span> System;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">a</span> = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 };
 
        <span class="comment">// 前後1要素ずつ削ったもの</span>
        <span class="reserved">var</span> <span class="variable">middle</span> = <span class="variable">a</span>[1..^1];
 
        <span class="comment">// 2, 3, 4 が表示される</span>
        <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">middle</span>)
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">x</span>);
        }
    }
}
</code></pre>
<p>ちなみに、<code>i..j</code> は「iは含んでjは含まない」という範囲になります。
<code>for (var x = i; x &lt; j; ++x)</code> のイメージ。</p>
<p>より細かく言うと、以下のような機能の組み合わせになります。</p>
<ul>
<li><code>^i</code> で「後ろからi番目」を表す <code>Index</code> 型の値を得る</li>
<li><code>i..j</code> で「i番目からj番目」を表す <code>Range</code> 型の値を得る</li>
<li>所定の条件を満たす型に対して <code>Index</code>/<code>Range</code> を渡すと、所定のパターンに展開する</li>
</ul>
<p>いくつかのプログラミング言語で似たような構文があり、
多くの場合は range (範囲)構文と呼ばれます。
C# 8.0 で導入されたものは配列などのインデックス用途に特化していて、
<code>Index</code>型と<code>Range</code>型からなるので、index/range (インデックス/範囲)構文と言ったりもします。</p>
<h2><a id="background">背景</h2>
<h3><a id="span">Span</h3>
<p>C# 7.2 で、<a href="/study/csharp/resource/span/"><code>Span&lt;T&gt;</code> 構造体</a>が導入されました。
配列や文字列中の一定範囲を抜き出して効率的に読み書きするための型です。
(単純な機能なのでもっと昔からあってもよさそうなものですが、
<a href="/study/computer/MemoryManagement.html#garbage-collection">ガベージ コレクション</a>があっても<a href="/study/csharp/resource/span/#two-implementations">安全かつ高速に</a>動くようにするのが意外と大変で、C# 7.2 まで導入が見送られていました。)</p>
<p>「<a href="/blog/2018/12/arrayindexer/">配列のインデクサー</a>」というブログで書いたことがあるんですが、
<code>Span&lt;T&gt;</code> 構造体は特別な最適化の対象になっていて、非常に高速です。
例えば以下の2つのメソッドでは、<code>Span&lt;T&gt;</code> を使った <code>Sum2</code> の方が高速です。</p>
<pre class="source" title="Span を使うと速い">
<code><span class="comment">// i番目からj番目までの和。</span>
[<span class="type">MethodImpl</span>(<span class="type">MethodImplOptions</span>.NoInlining)]
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">Sum1</span>(<span class="reserved">int</span>[] <span class="variable">array</span>, <span class="reserved">int</span> <span class="variable">i</span>, <span class="reserved">int</span> <span class="variable">j</span>)
{
    <span class="reserved">var</span> <span class="variable">sum</span> = 0;
    <span class="control">for</span> (<span class="reserved">int</span> <span class="variable">x</span> = <span class="variable">i</span>; <span class="variable">x</span> &lt; <span class="variable">j</span>; <span class="variable">x</span>++) <span class="variable">sum</span> += <span class="variable">array</span>[<span class="variable">x</span>];
    <span class="control">return</span> <span class="variable">sum</span>;
}
 
<span class="comment">// Sum1 と同じ処理を Span を使って書く。</span>
<span class="comment">// Sum1 よりこっちの方が速い。</span>
[<span class="type">MethodImpl</span>(<span class="type">MethodImplOptions</span>.NoInlining)]
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">Sum2</span>(<span class="reserved">int</span>[] <span class="variable">array</span>, <span class="reserved">int</span> <span class="variable">i</span>, <span class="reserved">int</span> <span class="variable">j</span>)
{
    <span class="reserved">var</span> <span class="variable">sum</span> = 0;
    <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable">array</span>.<span class="method">AsSpan</span>()[<span class="variable">i</span>..<span class="variable">j</span>]) <span class="variable">sum</span> += <span class="variable">x</span>;
    <span class="control">return</span> <span class="variable">sum</span>;
}
</code></pre>
<h3><a id="unification">範囲のルール統一</h3>
<p>配列の一定範囲を抜き出すという処理は、<code>array.AsSpan(x, y)</code> というように、単なるメソッド呼び出しでもできます。
ただ、ここで問題となるのは、引数の意味がメソッドによってぶれている点です。
<code>x</code>、<code>y</code> にそれぞれ3、5を渡した場合、どういう意味になるでしょう。
例えば、以下のようなパターンが考えられます。</p>
<ul>
<li>(1) 3, 4, 5 (3から5まで、3も5も含む)</li>
<li>(2) 3, 4 (3から5まで、5は含まない)</li>
<li>(3) 3, 4, 5, 6, 7 (3から5要素)</li>
</ul>
<p>実際、 .NET の標準ライブラリ中でもぶれています。
例えば、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.parallel.for?view=netstandard-2.1#System_Threading_Tasks_Parallel_For_System_Int32_System_Int32_System_Action_System_Int32__">Parallel.For</a>や<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.random.next?view=netframework-4.8#System_Random_Next_System_Int32_System_Int32_"><code>Random.Next</code></a> は (2) の意味ですが、<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.string.substring?view=netstandard-2.1#System_String_Substring_System_Int32_System_Int32_"><code>Substring</code></a>や<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.memoryextensions.asspan?view=netstandard-2.1#System_MemoryExtensions_AsSpan__1___0___System_Int32_System_Int32_"><code>AsSpan</code></a>は (3) の意味です。</p>
<pre class="source" title="範囲指定の引数のぶれ">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="comment">// この2つは 1から3 (3は含まない) = 1, 2の意味</span>
        <span class="type">Parallel</span>.<span class="method">For</span>(1, 3, <span class="variable">i</span> =&gt; { });
        <span class="reserved">var</span> <span class="variable">v</span> = <span class="reserved">new</span> <span class="type">Random</span>().<span class="method">Next</span>(1, 3);
 
        <span class="comment">// この2つは 1から3要素 = 1, 2, 3 の意味</span>
        <span class="reserved">var</span> <span class="variable">span</span> = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 }.<span class="method">AsSpan</span>(1, 3);
        <span class="reserved">var</span> <span class="variable">substr</span> = <span class="string">&quot;abcde&quot;</span>.<span class="method">Substring</span>(1, 3);
    }
}
</code></pre>
<p>名前付き引数を使えば、多少混乱を予防することはできます。</p>
<pre class="source" title="名前付き引数で混乱を予防">
<code><span class="type">Parallel</span>.<span class="method">For</span>(<span class="variable">fromInclusive</span>: 1, <span class="variable">toExclusive</span>: 3, <span class="variable">i</span> =&gt; { });
<span class="reserved">var</span> <span class="variable">v</span> = <span class="reserved">new</span> <span class="type">Random</span>().<span class="method">Next</span>(<span class="variable">minValue</span>: 1, <span class="variable">maxValue</span>: 3);
<span class="reserved">var</span> <span class="variable">span</span> = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 }.<span class="method">AsSpan</span>(<span class="variable">start</span>: 1, <span class="variable">length</span>: 3);
<span class="reserved">var</span> <span class="variable">substr</span> = <span class="string">&quot;abcde&quot;</span>.<span class="method">Substring</span>(<span class="variable">startIndex</span>: 1, <span class="variable">length</span>: 3);
</code></pre>
<p>ただ、名前付き引数を使っても以下の問題があります。</p>
<ul>
<li>コードがとにかく長くなる</li>
<li><code>Random.Next</code> のように「含むか含まないか」を明示していないやつがいる</li>
<li>あくまで実装者の良心頼みになっている</li>
<li>多次元データだと <code>matrix[1, 3, 1, 3]</code> みたいにさらにわかりにくい</li>
</ul>
<p>そこで、範囲を表す専用の構文が欲しいわけです。
構文になっていれば意味がぶれることがなくなります。
C# では、<code>i..j</code> で「i番目からj番目(j は含まない)」となる構文を採用しました。</p>
<h3><a id="index-usage">インデックス用途</h3>
<p><code>i..j</code> と書いたとき、j を含むかどうかは難しい問題です。
実際、あるプログラミング言語では j を含みますし、別のある言語では含みません。
<code>..=</code> や <code>..&lt;</code> などで含む・含まないを選ぶようになっている言語もありますが、
<code>..</code> だけを書く構文もあったりして、その <code>..</code> の意味は言語ごとにまちまちです。</p>
<p>用途次第でもあります。
「この範囲に入っているかどうかを判定」みたいな用途(要するに<a href="/study/csharp/datatype/patterns">パターン マッチング</a>)だと、末尾も含んでくれている方がわかりやすいです。
一方で、<code>Span</code>や<code>Substring</code>のように、配列や文字列から一定範囲を抜き出す用途(インデックス用途)では、末尾を含まない方が使いやすかったりします。</p>
<p>インデックス用途での「末尾を含まない」には以下のようなメリットがあります。</p>
<ul>
<li><code>j - i</code> だけで長さを計算できる</li>
<li>
ループで使いやすい
<ul>
<li>ループでは <code>for (int x = i; x &lt; j; ++x)</code> というように <code>&lt;</code> で条件判定することが多い</li>
</ul>
</li>
<li>
<code>i..i</code> (先頭と末尾が同じ)が不正にならない(単に長さ0の範囲になる)
<ul>
<li>逆に「j を含む」を採用する場合、長さ0の範囲は <code>i..(i-1)</code> と書く必要がある</li>
</ul>
</li>
</ul>
<p>C# の <code>i..j</code> で「j は含まない」の方を採用したのは、明確にインデックス用途を意図したものです。</p>
<h2><a id="index">Index</h2>
<p>配列や文字列からの一定範囲の抜き出しではよく「末尾から i 番目」という場所を取りたいことがあります。
C# 8.0 では、そのために単項 <code>^</code> 演算子を使います。</p>
<pre class="source" title="^ 演算子">
<code><span class="reserved">var</span> <span class="variable">i</span> = ^1; <span class="comment">// Length - 1 の場所</span>
 
<span class="reserved">var</span> <span class="variable">value</span> = 1;
<span class="reserved">var</span> <span class="variable">j</span> = ^<span class="variable">value</span>; <span class="comment">// 変数に対しても ^ を使える</span>
</code></pre>
<p>単項 <code>^</code> 演算子はオペランドに <code>int</code> (か <code>int</code> に暗黙に変換できる型)しか受け付けません。
また、戻り値は <code>Index</code> 構造体(<code>System</code> 名前空間)になります。
<code>Index</code> は、以下のようなプロパティ・メソッドを持つ構造体です。</p>
<pre class="source" title="Index 構造体">
<code><span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type">Index</span>
{
    <span class="reserved">public</span> <span class="type">Index</span>(<span class="reserved">int</span> <span class="variable">value</span>, <span class="reserved">bool</span> <span class="variable">fromEnd</span> = <span class="reserved">false</span>);
    <span class="reserved">public</span> <span class="reserved">bool</span> IsFromEnd { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Value { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="method">GetOffset</span>(<span class="reserved">int</span> <span class="variable">length</span>);
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="type">Index</span>(<span class="reserved">int</span> <span class="variable">value</span>)
}
</code></pre>
<p><code>^i</code> は <code>new Index(i, true)</code> に展開されます
(第2引数の <code>true</code> が「末尾から」の意味です)。
<code>int</code> からの暗黙的な変換もあって、それは素直に「先頭から i 番目」の意味になります。</p>
<h3><a id="non-negative">補足: インデックスは0以上の整数</h3>
<p>C# では、<a href="/blog/2018/12/arrayindex/">配列のインデックスは0以上(非負)という前提</a>があります。
なので、<code>Index</code> 構造体も以下のような作りになっています。</p>
<ul>
<li>
コンストラクターに負の整数を渡すと <code>IndexOutOfRange</code> 例外が発生する
<ul>
<li><code>^-1</code> みたいな書き方は文法的には認められるものの、実行時に例外発生</li>
</ul>
</li>
<li>
内部的には <code>int</code> 1つだけ持っていて、負の数を「末尾から」の意味で使っている
<ul>
<li>構造体のサイズは <code>int</code> と同じ4バイト</li>
</ul>
</li>
</ul>
<h2><a id="range">Range</h2>
<p>C# 8.0 で <code>..</code> という新しい構文が追加されました。</p>
<pre class="source" title=".. 構文">
<code><span class="reserved">var</span> <span class="variable">r1</span> = 1..^1;
<span class="reserved">var</span> <span class="variable">r2</span> = 1..;
<span class="reserved">var</span> <span class="variable">r3</span> = ..^1;
<span class="reserved">var</span> <span class="variable">r4</span> = ..;
 
<span class="reserved">var</span> <span class="variable">i</span> = 1;
<span class="reserved">var</span> <span class="variable">j</span> = ^1;
<span class="reserved">var</span> <span class="variable">r</span> = <span class="variable">i</span>..<span class="variable">j</span>;
</code></pre>
<p>他の2項演算子と違って、<code>i..</code> や <code>..j</code>、<code>..</code> というようにオペランドを省略できます。
オペランドは <code>Index</code> 型か、(<code>int</code> を含む) <code>Index</code> 型に暗黙的に変換できる型である必要があります。
戻り値は <code>Range</code> 型(<code>System</code> 名前空間)になります。
<code>Range</code> は、以下のようなプロパティ・メソッドを持つ構造体です。</p>
<pre class="source" title="Range 構造体">
<code><span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type">Range</span>
{
    <span class="reserved">public</span> <span class="type">Range</span>(<span class="type">Index</span> <span class="variable">start</span>, <span class="type">Index</span> <span class="variable">end</span>);
    <span class="reserved">public</span> <span class="type">Index</span> Start { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">Index</span> End { <span class="reserved">get</span>; }
    <span class="reserved">public</span> (<span class="reserved">int</span> Offset, <span class="reserved">int</span> Length) <span class="method">GetOffsetAndLength</span>(<span class="reserved">int</span> <span class="variable">length</span>);
}
</code></pre>
<p>左オペランドの省略時は先頭から、右オペランドの省略時は末尾までの意味になります。
すなわち、<code>i..</code> は <code>i..^0</code> と、<code>..j</code> は <code>0..j</code> と、<code>..</code> は <code>0..^0</code> と同じ意味です。
また、<code>i..j</code> は <code>new Range(i, j)</code> に展開されます。</p>
<p>名前通り、<code>Start</code> が開始位置で、<code>End</code> が末尾位置です。
コンストラクターの引数は、第1、第2引数がそれぞれ <code>Start</code>、<code>End</code> と対応しています。
これまでの説明通り、<code>Start</code> は「含む」、<code>End</code>は「含まない」という扱いです。</p>
<p>この辺りは言葉で説明してもわかりにくいと思うので、以下の図を参考にしてください。</p>
<p><img src="/media/1174/ranges.png" alt="Index/Range の意味" /></p>
<p><code>i..^j</code> で、先頭からi要素、末尾からj要素を削った範囲になります。</p>
<p>ちなみに、演算子の優先順位は結構高いです。
2項演算(乗除算含む)や <a href="/study/csharp/datatype/typeswitch/?p=5#switch-expression"><code>switch</code> 式</a>よりも上になります。</p>
<pre class="source" title=".. の優先順位">
<code>_ = <span class="error">2 * 3..4</span>; <span class="comment">// 2 * (3..4) の意味。そんな掛け算はできないのでコンパイル エラーに。</span>
_ = 2..3 <span class="control">switch</span> <span class="comment">// 2..3 という Range が switch 式の引数になる</span>
{
    <span class="type">Range</span> <span class="reserved">_</span> =&gt; 4,
};
_ = (1 + 2)..(3 + 4); <span class="comment">// 足し算とかを優先したければ () 必須</span>
</code></pre>
<h2><a id="indexer">Index/Range とインデクサー</h2>
<p><code>Index</code>/<code>Range</code>型に対するインデクサーは、
以下で説明するように、
一定のパターンで <code>int</code> に対するインデクサーや<code>Slice</code>メソッドに展開されます。</p>
<p>(当初予定では、<code>^i</code>から<code>Index</code>型を、<code>i..j</code>から<code>Range</code>型を作るところまでだけが C# コンパイラーの仕事で、それを使ったインデクサーは使う側(配列や <code>List&lt;T&gt;</code>などのコレクションの側)の仕事にする予定でした。
それだとあらゆるコレクションに対して1個1個インデクサーのオーバーロードを追加する作業が大変なのと、最適化が掛けにくいという理由で、現状のパターン ベースな方式に変更されました。)</p>
<p><code>Index</code>型の <code>i</code> に対するインデクサー <code>a[i]</code> は基本的に以下のように展開されます。</p>
<pre class="source" title="Index 型インデクサーの展開結果">
<code><span class="reserved">int</span> <span class="variable">offset</span> = <span class="variable">i</span>.<span class="method">GetOffset</span>(<span class="variable">a</span>.Length);
<span class="variable">a</span>[<span class="variable">offset</span>];
</code></pre>
<p>また、<code>Range</code> 型の <code>r</code> に対するインデクサー <code>a[r]</code> は基本的に以下のように展開されます。</p>
<pre class="source" title="Range 型インデクサーの展開結果">
<code><span class="reserved">var</span> <span class="variable">offset1</span> = <span class="variable">r</span>.Start.<span class="method">GetOffset</span>(<span class="variable">a</span>.Length);
<span class="reserved">var</span> <span class="variable">offset2</span> = <span class="variable">r</span>.End.<span class="method">GetOffset</span>(<span class="variable">a</span>.Length);
<span class="variable">a</span>.Slice(<span class="variable">offset1</span>, <span class="variable">offset2</span> - <span class="variable">offset1</span>);
</code></pre>
<p><code>a</code> の型によって多少バリエーションがあります。
C# のコレクションは長さを <code>Length</code> で取るものと <code>Count</code> で取るものの両方あるので、
そのどちらにも対応しています。<code>Length</code> がなくて <code>Count</code> がある場合それを使います
(<code>Length</code> があるならそっちが優先)。</p>
<pre class="source" title="Index 型インデクサーの展開結果(Count)">
<code><span class="reserved">int</span> <span class="variable">offset</span> = <span class="variable">i</span>.<span class="method">GetOffset</span>(<span class="variable">a</span>.<em>Count</em>);
<span class="variable">a</span>[<span class="variable">offset</span>];
</code></pre>
<pre class="source" title="Range 型インデクサーの展開結果(Count)">
<code><span class="reserved">var</span> <span class="variable">offset1</span> = <span class="variable">r</span>.Start.<span class="method">GetOffset</span>(<span class="variable">a</span>.<em>Count</em>);
<span class="reserved">var</span> <span class="variable">offset2</span> = <span class="variable">r</span>.End.<span class="method">GetOffset</span>(<span class="variable">a</span>.<em>Count</em>);
<span class="variable">a</span>.Slice(<span class="variable">offset1</span>, <span class="variable">offset2</span> - <span class="variable">offset1</span>);
</code></pre>
<p>また、<code>Range</code> 型インデクサーには、配列と文字列の場合だけ特別扱いがあります。
<code>Slice</code> メソッドではなく、それぞれ <code>GetSubArray</code>、<code>Substring</code> メソッドが呼ばれます
(<code>GetSubArray</code>は<code>RuntimeHelpers</code>クラス(<code>System.Runtime.CompilerServices</code> 名前空間)の静的メソッド)。</p>
<h3><a id="avoid-copy">コピーの回避</h3>
<p>配列と文字列に対する <code>Range</code>型インデクサー <code>a[i..j]</code> 
(展開結果的には <code>GetSubArray</code> と <code>Substring</code>)は、
それぞれ配列、文字列を返します。
この際、新しい配列・文字列を確保してコピーするコストが発生します。</p>
<pre class="source" title="Range型インデクサーでコピー発生">
<code><span class="reserved">var</span> <span class="variable">array</span> = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 };
<span class="reserved">var</span> <span class="variable">str</span> = <span class="string">&quot;abcde&quot;</span>;
 
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 100; <span class="variable">i</span>++)
{
    <span class="comment">// こういう書き方をすると、ループのたびに new int[], new string が発生。</span>
    <span class="comment">// だいぶ重たい。</span>
    <span class="reserved">var</span> <span class="variable">subarray</span> = <span class="variable">array</span>[1..^1];
    <span class="reserved">var</span> <span class="variable">substr</span> = <span class="variable">str</span>[1..^1];
}
</code></pre>
<p>これらはそれなりに重たい処理なので、パフォーマンスにシビアな状況での利用には注意が必要です。</p>
<p>コピーを発生させたくない場合、<a href="/study/csharp/resource/span/"><code>Span&lt;T&gt;</code></a>を経由します。
要するに、<code>AsSpan()</code> や <code>AsMemory()</code> を挟めばコピーを回避できます。</p>
<pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">array</span> = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 };
<span class="reserved">var</span> <span class="variable">str</span> = <span class="string">&quot;abcde&quot;</span>;
 
<span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; 100; <span class="variable">i</span>++)
{
    <span class="comment">// 以下の書き方をすれば Span&lt;int&gt;/ReadOnlySpan&lt;char&gt; の Slice が呼ばれるようになる。</span>
    <span class="comment">// これならコピーは発生せず、軽い。</span>
    <span class="reserved">var</span> <span class="variable">subarray</span> = <span class="variable">array</span><em>.<span class="method">AsSpan</span>()</em>[1..^1];
    <span class="reserved">var</span> <span class="variable">substr</span> = <span class="variable">str</span><em>.<span class="method">AsSpan</span>()</em>[1..^1];
}
</code></pre>
<h5>サンプル</h5>
<p>「一定範囲を抜き出す」という処理は、テキスト処理でよく使います。</p>
<p>例として、書式が決まっているテキストの中から一部分を取り出してみましょう。
今回は「1行1項目で、<code>:</code> 区切りでキーと値が並んでいる」というような書式を考えます。
この書式のテキストの中からキーだけを取り出すようなコードを以下のように書けます。</p>
<pre class="source" title="書式が決まったテキストから一部分を抜き出す例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">testData</span> = <span class="string">@&quot;longitude: 139.8803943
latitude: 35.6328964
postal code: 279-0031
&quot;</span>;
 
        <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">key</span> <span class="control">in</span> <span class="method">GetKeys</span>(<span class="variable">testData</span>))
        {
            <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">key</span>);
        }
    }
 
    <span class="comment">// 行頭から : までの間の文字列だけを抜き出す</span>
    <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="type">ReadOnlyMemory</span>&lt;<span class="reserved">char</span>&gt;&gt; <span class="method">GetKeys</span>(<span class="reserved">string</span> <span class="variable">content</span>)
    {
        <span class="reserved">var</span> <span class="variable">start</span> = 0;
        <span class="control">for</span> (<span class="reserved">int</span> <span class="variable">i</span> = 0; <span class="variable">i</span> &lt; <span class="variable">content</span>.Length; <span class="variable">i</span>++)
        {
            <span class="reserved">var</span> <span class="variable">c</span> = <span class="variable">content</span>[<span class="variable">i</span>];
            <span class="control">if</span> (<span class="variable">c</span> == <span class="string">&#39;:&#39;</span>)
            {
                <span class="control">yield</span> <span class="control">return</span> <span class="variable">content</span>.<span class="method">AsMemory</span>()[<span class="variable">start</span>..<span class="variable">i</span>];
            }
            <span class="control">else</span> <span class="control">if</span> (<span class="variable">c</span> == <span class="string">&#39;\n&#39;</span>)
            {
                <span class="variable">start</span> = <span class="variable">i</span> + 1;
            }
        }
    }
}
</code></pre>
<pre class="console" title="書式が決まったテキストから一部分を抜き出す例">
<code>longitude
latitude
postal code
</code></pre>
<p>例なのでシンプルな書式にしましたが、もうちょっと実用的な、例えば JSON 形式からのキーの取り出しなども、こういうコードの延長線上になります。</p>
 ]]></description>
				<pubDate>Sun, 02 Jun 2019 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>is、switch の拡張 (型スイッチ)</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/typeswitch/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version7">Ver. 7</h5>
<p>C# 7.0で、<a href="http://ufcpp.net/study/csharp/oo_polymorphism.html?sec=downcast#is-operator"><code>is</code>演算子</a>や<a href="http://ufcpp.net/study/csharp/st_branch.html#switch"><code>switch</code>ステートメント</a>の<code>case</code>が拡張されました。</p>
<p>C# 6.0 以前では以下のような仕様でした。</p>
<ul>
<li><code>is</code>演算子 … <code>x is T</code> と言うように、型の判定だけができた</li>
<li><code>switch</code>ステートメントの<code>case</code> … <code>case</code> の後ろには定数だけが指定で来た</li>
</ul>
<p>これに対して、C# 7.0 以降では、<code>is</code>、<code>case</code>の後ろに「パターン」を指定できます。
「パターン」の詳細については<a href="/study/csharp/datatype/patterns/">次項</a>で別途説明する予定ですが、
簡単に概要だけ表にすると以下のようなものがあります。</p>
<table>
<thead>
<tr>
	<th>パターン</th>
	<th>バージョン</th>
	<th>概要</th>
	<th>例</th>
</tr>
</thead>
<tbody>
<tr>
	<td>型パターン</td>
	<td>C# 7.0</td>
	<td>型の判定</td>
	<td><code>int i</code>、<code>string s</code></td>
</tr>
<tr>
	<td>定数パターン</td>
	<td>C# 7.0</td>
	<td>定数との比較</td>
	<td><code>null</code>、<code>1</code></td>
</tr>
<tr>
	<td>var パターン</td>
	<td>C# 7.0</td>
	<td>何にでもマッチ・変数で受け取り</td>
	<td><code>var x</code></td>
</tr>
<tr>
	<td>破棄パターン</td>
	<td>C# 8.0</td>
	<td>何にでもマッチ・無視</td>
	<td><code>_</code></td>
</tr>
<tr>
	<td>位置パターン</td>
	<td>C# 8.0</td>
	<td><a href="/study/csharp/datatype/deconstruction/">分解</a>と同じ要領で、再帰的にマッチングする</td>
	<td><code>(1, var i, _)</code></td>
</tr>
<tr>
	<td>プロパティ パターン</td>
	<td>C# 8.0</td>
	<td>プロパティに対して再帰的にマッチングする</td>
	<td><code>{ A: 1, B: var i }</code></td>
</tr>
</tbody>
</table>
<p>C# 7.0 時点では「型パターン」が主だった機能だったため、
<code>is</code>や<code>switch</code>の拡張を指して「型スイッチ」(type switch)と呼ばれたりもしました。</p>
<p>本項では、まずは<code>is</code>や<code>switch</code>がC# 6.0以前と比べてどう変わったかについて焦点を当てます。
例なども、主に型パターン(C# 7.0)で説明していきます。
パターン自体の詳細については次項の「<a href="/study/csharp/datatype/patterns/">パターン マッチング</a>」を参照してください。</p>
<h2><a id="is">is演算子の拡張</h2>
<p>C# 7では、<code>is</code>演算子で以下のような書き方ができるようになりました。</p>
<pre class="source" title="is = 型判定">
<code><span class="input">型を調べたい変数</span> <span class="reserved">is</span> <span class="input">型</span> <span class="input">新しい変数</span>
</code></pre>
<p>(正確に言うと<code>is</code>の後ろに新たに書けるようになったのは「パターン」で、
これはそのうちの「型パターン」と呼ばれるものです。)</p>
<p>C# 6以前の<code>is</code>演算子は少し使い勝手が悪い面がありました。型の一致を判定するだけならいいんですが、
型変換も絡むといまいちです。</p>
<p>例えば、以下のように型を判定するだけなら<code>is</code>演算子の出番です。</p>
<pre class="source" title="is = 型判定">
<code><span class="comment">// 型判定のみなら、これまでの is 演算子でも十分</span>
<span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">string</span>) <span class="type">Console</span>.WriteLine(<span class="string">"string"</span>);
</code></pre>
<p>ところが、型を判定したうえでダウンキャストしたいという場面では、以下のように、「2度手間」になって、コード量的にも実行効率的にもよくないです。</p>
<pre class="source" title="ダウンキャストしたい場合、is はいまいち">
<code><span class="comment">// 型変換もしたい</span>
<span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">string</span>)
{
    <span class="reserved">var</span> s = (<span class="reserved">string</span>)obj;
    <span class="comment">//↑ isとキャストで2つの別命令を使う。二重処理になってるだけで無駄</span>
    <span class="type">Console</span>.WriteLine(<span class="string">"string #"</span> + s.Length);
}
</code></pre>
<p>結局、以下のように、<code>as</code>演算子を使うことが推奨されます。</p>
<pre class="source" title="ダウンキャストにはasを使う">
<code><span class="comment">// 結局、as 演算子 + null チェックを使うことになる</span>
<span class="reserved">var</span> s = obj <span class="reserved">as</span> <span class="reserved">string</span>;
<span class="reserved">if</span> (s != <span class="reserved">null</span>)
{
    <span class="type">Console</span>.WriteLine(<span class="string">"string #"</span> + s.Length);
}
</code></pre>
<p>これに対して、C# 7では、<code>is</code>演算子で以下のような書き方ができるようになりました。</p>
<pre class="source" title="">
<code><span class="comment">// C# 7での新しい書き方</span>
<span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">string</span> <em>s</em>)
{
    <span class="type">Console</span>.WriteLine(<span class="string">"string #"</span> + s.Length);
}
</code></pre>
<p>挙動的には、先ほどの<code>as</code>演算子を使ったものとまったく同じ挙動になります。
<code>is</code>演算子で型を判定しつつ(<code>bool</code>の戻り値を返しつつ)、その型への変換結果を新しい変数で受け取れます。</p>
<h3><a id="scope">is演算子で宣言された変数のスコープ</h3>
<p><code>is</code>演算子の拡張によって、式の中で変数宣言ができるようになりました。
そこで問題になるのはこの変数のスコープです。</p>
<p>概ね、「その式を含むブロック内」と考えていいんですが、<code>if</code>や<code>while</code>などの中で使ったときなど、いくつか特殊な場合があります。
詳細については「<a href="http://ufcpp.net/study/csharp/start/st_scope/?p=3#declaration-expressions">式の中で変数宣言</a>」を参照してください。</p>
<h3><a id="null-check">is演算子によるnullチェック</h3>
<p>元々の<code>is</code>演算子の仕様でもあるんですが、<code>null</code>には型がなくて常に<code>is</code>に失敗します(<code>false</code>を返す)。</p>
<pre class="source" title="nullは型を持たない">
<code><span class="reserved">string</span> x = <span class="reserved">null</span>;

<span class="reserved">if</span> (x <span class="reserved">is</span> <span class="reserved">string</span>)
{
    <span class="comment">// x の変数の型は string なのに、is string は false</span>
    <span class="comment">// is 演算子は変数の実行時の中身を見る ＆ null には型がない</span>
    <span class="type">Console</span>.WriteLine(<span class="string">"ここは絶対通らない"</span>);
}
</code></pre>
<p>この仕様は、C# 7からの新しい構文でも引き継いでいて、<code>null</code>じゃないときだけだけ何かの処理をしたいときに使えます。
と言っても、参照型の場合にはあまり使い道はありませんが、以下のような書き方ができます。</p>
<pre class="source" title="is演算子でnullチェック">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">string</span> nullable)
{
    <span class="reserved">if</span> (nullable <span class="reserved">is</span> <span class="reserved">string</span> nonNull)
    {
        <span class="comment">// nonNull には絶対に null が入らない</span>
        <span class="comment">// nullable をそのまま使っても、if の結果、null じゃない保証があるのであまり意味はないけども</span>
        <span class="type">Console</span>.WriteLine(nonNull.Length);
    }
}
</code></pre>
<p>この書き方が役に立つのは、値型と<a href="http://ufcpp.net/study/csharp/sp2_nullable.html">null許容型</a>を使う場合でしょう。
例えばC# 6以前だと、以下のような書き方になります。</p>
<pre class="source" title="C# 6以前のnull許容型のnullチェック">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">int</span>? x)
{
    <span class="comment">// C# 6以前の書き方</span>
    <span class="reserved">if</span> (x.HasValue)
    {
        <span class="comment">// この「.GetValueOrDefault()」をいちいち書くのが結構うっとおしい</span>
        <span class="comment">// x * x だと、(x.HasValue & x.HasValue) ? (int?)(x.GetValueOrDefault() * x.GetValueOrDefault()) : null みたいなコードに展開されてしまう</span>
        <span class="reserved">int</span> n = x.GetValueOrDefault();
        <span class="type">Console</span>.WriteLine(n * n);
    }
}
</code></pre>
<p>これが、C# 7で以下のように書けるようになります。</p>
<pre class="source" title="C# 7からのnull許容型のnullチェック">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">int</span>? x)
{
    <span class="reserved">if</span> (x <span class="reserved">is</span> <span class="reserved">int</span> <em>n</em>)
    {
        <span class="type">Console</span>.WriteLine(n * n);
    }
}
</code></pre>
<p>ただ、1つ注意が必要なのは、<code>is var</code> という似て非なる構文がある点です。
<code>is var</code> (<a href="/study/csharp/datatype/patterns/#var"><code>var</code>パターン</a>と言って、<a href="/study/csharp/datatype/patterns/#declaration"><code>is T</code></a> とは別扱い)を使った場合、nullチェックはされません。
<code>var</code> は何でも受け取れる構文で、null も受け付けます。</p>
<p>ちなみに、C# 8.0 では、<a href="/study/csharp/datatype/patterns/?p=2#recursive">再帰パターン</a>が暗黙的に null チェックも含んでいることを使って、手短に null チェックもできます
(参考: <a href="/study/csharp/datatype/patterns/?p=2#non-null">非 null マッチング</a>)。</p>
<pre class="source" title="パターンを使って非 null チェック">
<code><span class="reserved">string</span> <span class="variable">s</span> = <span class="reserved">null</span>;
 
<span class="comment">// 型を明示した場合、null にマッチしない</span>
<span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> <span class="reserved">string</span>) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;ここは通らない&quot;</span>);
 
<span class="comment">// var パターンは何にでも(null 含む)マッチする</span>
<span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> <span class="reserved">var</span> <span class="reserved">_</span>) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;ここは通る&quot;</span>);
 
<span class="comment">// 再帰パターンで型を省略すると null チェックも含む</span>
<span class="control">if</span> (<span class="variable">s</span> <span class="reserved">is</span> { }) <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="string">&quot;ここは通らない&quot;</span>);
</code></pre>
<h3><a id="invariant-meaning">余談: 変数の意味を変えない</h3>
<p>プログラミング言語によっては、以下のように、<code>is</code>演算子で型を判定した後には、自動的にその型扱いしてくれる言語もあります。</p>
<pre class="source" title="is によって変数の意味を変える">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">object</span> obj)
{
    <span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">string</span>)
    {
        <span class="comment">// この中では obj を string 扱いできる言語がある</span>
        <span class="comment">// C# ではコンパイル エラー</span>
        <span class="type">Console</span>.WriteLine(<span class="string">"string #"</span> + obj.Length);
    }
    <span class="reserved">else</span> <span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">int</span>)
    {
        <span class="comment">// 同上、int 扱いできる言語がある</span>
        <span class="comment">// C# ではコンパイル エラー</span>
        <span class="type">Console</span>.WriteLine(<span class="string">"int "</span> + (obj * obj));
    }
}
</code></pre>
<p>C# では、こういう、「<code>object</code>だと思っていたものが一定範囲でだけ別の型になる」というようなことはやらない方針です。</p>
<p>また、以下のように、同名の別変数を導入できる言語もありますが、こちらもC#では認めていません。</p>
<pre class="source" title="is 演算子で同名の別変数を導入">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">object</span> x)
{
    <span class="reserved">if</span> (x <span class="reserved">is</span> <span class="reserved">string</span> x)
    {
        <span class="comment">// 引数の x とは別に、is 演算子で別の「x」を導入できる言語もある</span>
        <span class="comment">// C# ではコンパイル エラー</span>
        <span class="type">Console</span>.WriteLine(<span class="string">"string #"</span> + x.Length);
    }
}
</code></pre>
<p>C#では、変数はスコープ内で意味不変(invariant meaning)であるべきという方針を持っています。
上記の2つの例では、<code>obj</code>や<code>x</code>が部分的に(<code>if</code>の中でだけ)別の意味になるので、C#としては認めたくないものになります。</p>
<!-- pageBreak -->
<h2><a id="switch"> switchステートメントの拡張</h2>
<p>C# 7では、<code>switch</code>ステートメントの<code>case</code>句に、値だけでなく、パターンを書けるようになりました。
パターンの書き方は、前節の<code>is</code>演算子と同様です。
また、型による条件に加えて、<code>when</code>句というものを付けて追加の条件式を書くこともできます。</p>
<pre class="source" title="switchステートメントの拡張" lang="">
<code><span class="reserved">switch</span>(<span class="input">変数</span>)
{
    <span class="reserved">case</span> <span class="input">型</span> <span class="input">変数</span>:
        <span class="comment">// 型が一致しているときにここに来る</span>
        <span class="comment">// その型に変換した結果が変数に入っている</span>
        <span class="reserved">break</span>;
    <span class="reserved">case</span> <span class="input">型</span> <span class="input">変数</span> <span class="reserved">when</span> <span class="input">条件式</span>:
        <span class="comment">// 型が一致していて、かつ、条件式満たしているときにここに来る</span>
        <span class="reserved">break</span>;
    <span class="reserved">case</span> <span class="input">値</span>:
        <span class="comment">// 通常の値による条件との混在も可能</span>
        <span class="reserved">break</span>;
      ・
      ・
      ・
    <span class="reserved">default</span>:
        <span class="comment">// どの条件も満たさない時に実行される</span>
        <span class="reserved">break</span>;
}
</code></pre>
<p>例えば以下のような書き方ができます。</p>
<pre class="source" title="型を見て分岐する switch ステートメントの例">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">object</span> obj)
{
    <span class="reserved">switch</span> (obj)
    {
        <span class="reserved">case</span> <span class="reserved">string</span> s:
            <span class="type">Console</span>.WriteLine(<span class="string">"string #"</span> + s.Length);
            <span class="reserved">break</span>;
        <span class="reserved">case</span> 7:
            <span class="type">Console</span>.WriteLine(<span class="string">"7の時だけここに来る"</span>);
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="reserved">int</span> n <span class="reserved">when</span> n &gt; 0:
            <span class="type">Console</span>.WriteLine(<span class="string">"正の数の時にここに来る "</span> + n);
            <span class="comment">// ただし、上から順に判定するので、7 の時には来なくなる</span>
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="reserved">int</span> n:
            <span class="type">Console</span>.WriteLine(<span class="string">"整数の時にここに来る"</span> + n);
            <span class="comment">// 同上、0 以下の時にしか来ない</span>
            <span class="reserved">break</span>;
        <span class="reserved">default</span>:
            <span class="type">Console</span>.WriteLine(<span class="string">"その他"</span>);
            <span class="reserved">break</span>;
    }
}
</code></pre>
<h3><a id="sequential">上から逐次判定</h3>
<p>C# 6までの、値による分岐しかなかった<code>switch</code>ステートメントとはちょっと違う部分があります。
以下の点に気を付けてください。</p>
<ul>
<li>
条件の範囲が被る場合がある
<ul>
<li>値による分岐の場合は、各 <code>case</code> がそれぞれ排他だった</li>
<li>型による分岐が入ったことで、上記の例でいう <code>7</code> ⊃ <code>int</code>かつ正の数 ⊃ <code>int</code> のように、被りが起こり得る</li>
</ul>
</li>
<li>
条件は上から順に判定する
<ul>
<li>
被りがない場合なら順序を気にする必要はなかった
<ul>
<li>なので、「ジャンプ テーブル化」(後述)という最適化手法が使えていた</li>
</ul>
</li>
<li>型による分岐を1つでも含むと、この前提が崩れて、ジャンプ テーブル化できない(逐次判定しかしない)</li>
</ul>
</li>
</ul>
<p>ジャンプ テーブル化の説明のために、以下のような<code>switch</code>を考えましょう。</p>
<pre class="source" title="値による条件のみのswitchの例">
<code><span class="reserved">switch</span>(n)
{
    <span class="reserved">case</span> 0: <span class="reserved">return</span> <span class="string">"zero"</span>;
    <span class="reserved">case</span> 1: <span class="reserved">return</span> <span class="string">"one"</span>;
    <span class="reserved">case</span> 2: <span class="reserved">return</span> <span class="string">"two"</span>;
    <span class="reserved">case</span> 3: <span class="reserved">return</span> <span class="string">"three"</span>;
    <span class="reserved">case</span> 4: <span class="reserved">return</span> <span class="string">"four"</span>;
    <span class="reserved">case</span> 5: <span class="reserved">return</span> <span class="string">"five"</span>;
    <span class="reserved">case</span> 6: <span class="reserved">return</span> <span class="string">"six"</span>;
    <span class="reserved">case</span> 7: <span class="reserved">return</span> <span class="string">"seven"</span>;
    <span class="reserved">case</span> 8: <span class="reserved">return</span> <span class="string">"eight"</span>;
    <span class="reserved">case</span> 9: <span class="reserved">return</span> <span class="string">"nine"</span>;
    <span class="reserved">default</span>: <span class="reserved">return</span> <span class="string">"other"</span>;
}
</code></pre>
<p>こういう<code>switch</code>であれば、以下のように、辞書を引いて結果を得ることもできるはずです。</p>
<pre class="source" title="switchの辞書化">
<code><span class="reserved">var</span> map = <span class="reserved">new</span> <span class="type">Dictionary</span>&lt;<span class="reserved">int</span>, <span class="reserved">string</span>&gt;
{
    { 0, <span class="string">"zero"</span> },
    { 1, <span class="string">"one"</span> },
    { 2, <span class="string">"two"</span> },
    { 3, <span class="string">"three"</span> },
    { 4, <span class="string">"four"</span> },
    { 5, <span class="string">"five"</span> },
    { 6, <span class="string">"six"</span> },
    { 7, <span class="string">"seven"</span> },
    { 8, <span class="string">"eight"</span> },
    { 9, <span class="string">"nine"</span> },
};

<span class="reserved">string</span> s;
<span class="reserved">if</span> (map.TryGetValue(n, <span class="reserved">out</span> s)) <span class="reserved">return</span> s;
<span class="reserved">else</span> <span class="reserved">return</span> <span class="string">"other"</span>;
</code></pre>
<p><code>case</code>の個数が少ないうちは普通に上から順に等値判定していく方が軽いんですが、
<code>case</code>数が増えれば増えるほど、辞書化した方が有利になります。</p>
<p>そこで、C# の<code>switch</code>ステートメント(というか、.NETの中間言語の<code>switch</code>命令)では、<code>case</code>の数が多い場合にこういう辞書を使った最適化を行うようになっています。
正確にいうと、辞書の値は条件分岐によるジャンプ先が入っていて、<code>goto</code>的な命令との組み合わせで実現されます。
そこで、「ジャンプ先のテーブルを引く」という意味で「ジャンプ テーブル化」と呼ばれます。</p>
<p>繰り返しになりますが、<code>case</code>に型による条件を書いてしまうと、こういうジャンプ テーブル化ができなくなります。
というより、コンパイル結果的には<code>switch</code>命令が使えず、<code>if-else</code>を繰り返すようなコードにコンパイルされます。
上から順に逐次判定になるので、<code>case</code>数があまりにも多いと実行性能的にあまりよくないので注意してください。</p>
<p>また、上の方の<code>case</code>にあるほど判定が速いことになります。
以下のように、一番上の<code>case</code>と一番下の<code>case</code>では、かなりパフォーマンスに差が出ます。
(なので、パフォーマンスが気になるなら、発生頻度が高いものほど上の方に書く必要があります。)</p>
<pre class="source" title="逐次判定によるパフォーマンスの変化">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Diagnostics;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> sw = <span class="reserved">new</span> <span class="type">Stopwatch</span>();

        <span class="comment">// bool 型は一番先頭 = 速い</span>
        <span class="reserved">object</span> t = <span class="reserved">true</span>;
        sw.Start();
        <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 100000; i++) TypeSwitch(t);
        sw.Stop();
        <span class="type">Console</span>.WriteLine(<span class="string">"bool   "</span> + sw.Elapsed); <span class="comment">// かなり速いはず</span>

        <span class="comment">// double 型は一番末尾 = 遅い</span>
        <span class="reserved">object</span> d = 1.1;
        sw.Restart();
        <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 100000; i++) TypeSwitch(d);
        sw.Stop();
        <span class="type">Console</span>.WriteLine(<span class="string">"string "</span> + sw.Elapsed); <span class="comment">// 手元の環境では5倍くらい遅かった</span>

        <span class="comment">// どの case にもない型。default 句に行く</span>
        <span class="reserved">var</span> s = <span class="type">DateTime</span>.UtcNow;
        sw.Restart();
        <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 100000; i++) TypeSwitch(s);
        sw.Stop();
        <span class="type">Console</span>.WriteLine(<span class="string">"string "</span> + sw.Elapsed); <span class="comment">// 一番最後まで判定するので遅い</span>
    }

    <span class="reserved">static</span> <span class="reserved">int</span> TypeSwitch(<span class="reserved">object</span> x)
    {
        <span class="reserved">switch</span> (x)
        {
            <span class="reserved">default</span>: <span class="reserved">return</span> -1; <span class="comment">// ちなみに、default 句はどこに書こうと必ず一番最後</span>
            <span class="reserved">case</span> <span class="reserved">bool</span> <span class="reserved">_</span>: <span class="reserved">return</span> 0; <span class="comment">// 前から順に判定ということは、bool の時が一番早い</span>
            <span class="reserved">case</span> <span class="reserved">sbyte</span> <span class="reserved">_</span>: <span class="reserved">return</span> 1;
            <span class="reserved">case</span> <span class="reserved">byte</span> <span class="reserved">_</span>: <span class="reserved">return</span> 2;
            <span class="reserved">case</span> <span class="reserved">short</span> <span class="reserved">_</span>: <span class="reserved">return</span> 3;
            <span class="reserved">case</span> <span class="reserved">ushort</span> <span class="reserved">_</span>: <span class="reserved">return</span> 4;
            <span class="reserved">case</span> <span class="reserved">int</span> <span class="reserved">_</span>: <span class="reserved">return</span> 5;
            <span class="reserved">case</span> <span class="reserved">uint</span> <span class="reserved">_</span>: <span class="reserved">return</span> 6;
            <span class="reserved">case</span> <span class="reserved">long</span> <span class="reserved">_</span>: <span class="reserved">return</span> 7;
            <span class="reserved">case</span> <span class="reserved">ulong</span> <span class="reserved">_</span>: <span class="reserved">return</span> 8;
            <span class="reserved">case</span> <span class="reserved">float</span> <span class="reserved">_</span>: <span class="reserved">return</span> 9;
            <span class="reserved">case</span> <span class="reserved">double</span> <span class="reserved">_</span>: <span class="reserved">return</span> 10; <span class="comment">// 逆に double の時は凄く遅い</span>
        }
    }
}
</code></pre>
<p>ちなみに、この例でも書いてありますが、逐次判定になっていたとしても<code>default</code>句にたどり着くのは必ず一番最後です。</p>
<!-- pageBreak -->
<h2><a id="usage">型スイッチ(switch を使ったパターン マッチング)の用途</h2>
<p>型によって分岐する方法としては、<a href="http://ufcpp.net/study/csharp/oo_polymorphism.html#virtual">仮想メソッド</a>を使う方法があります。
オブジェクト指向プログラミング言語としては、仮想メソッドが相当に便利で、実行性能もよく、こちらが好まれます。
極端な意見では、「型を調べたら負け」、「<a href="http://ufcpp.net/study/csharp/oo_polymorphism.html#downcast">ダウンキャスト</a>が必要なのは筋が悪い」という人すらいます。</p>
<p>ここでは、この仮想メソッドと、本稿の主題である型スイッチの使い分けについて説明します。</p>
<p>例として、以下のようなクラス階層を考えます。</p>
<pre class="source" title="式ノード">
<code><span class="reserved">public abstract class</span> <span class="type">Node</span> { }

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Var</span> : <span class="type">Node</span> { }

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Const</span> : <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> Value { <span class="reserved">get</span>; }
    <span class="reserved">public</span> Const(<span class="reserved">int</span> value) { Value = value; }
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Add</span> : <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="type">Node</span> Left { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">Node</span> Right { <span class="reserved">get</span>; }
    <span class="reserved">public</span> Add(<span class="type">Node</span> left, <span class="type">Node</span> right)
    {
        Left = left;
        Right = right;
    }
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Mul</span> : <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="type">Node</span> Left { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="type">Node</span> Right { <span class="reserved">get</span>; }
    <span class="reserved">public</span> Mul(<span class="type">Node</span> left, <span class="type">Node</span> right)
    {
        Left = left;
        Right = right;
    }
}
</code></pre>
<p>説明都合で簡素化していますが、数式を扱うようなクラスです。
要するに、例えば、「<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>×</mo><mi>x</mi><mo>+</mo><mn>1</mn></math>」というような式を、以下のようなコードで表すためのクラスです。</p>
<pre class="source" title="x × x + 1">
<code><span class="reserved">var</span> expression = <span class="reserved">new</span> <span class="type">Add</span>(
    <span class="reserved">new</span> <span class="type">Mul</span>(
        <span class="reserved">new</span> <span class="type">Var</span>(),
        <span class="reserved">new</span> <span class="type">Var</span>()),
    <span class="reserved">new</span> <span class="type">Const</span>(1));
</code></pre>
<p><img src="/media/1094/expressions.png" alt="式を扱いためのクラス" /></p>
<p>これに対して、「変数<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>の値を与えて、式の計算結果を得る」というようなメソッドを、仮想メソッドと型スイッチの両方で作ってみましょう。</p>
<p>まず、仮想メソッドなら以下のようになるでしょう(必要な部分だけを抜き出してあります)。</p>
<pre class="source" title="仮想メソッドで実装する例">
<code><span class="reserved">abstract</span> <span class="reserved">class</span> <span class="type">Node</span>
{
    <span class="reserved">public</span> <span class="reserved">abstract</span> <span class="reserved">int</span> Calculate(<span class="reserved">int</span> x);
}

<span class="reserved">class</span> <span class="type">Var</span>
{
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">int</span> Calculate(<span class="reserved">int</span> x) =&gt; x;
}

<span class="reserved">class</span> <span class="type">Const</span>
{
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">int</span> Calculate(<span class="reserved">int</span> x) =&gt; Value;
}

<span class="reserved">class</span> <span class="type">Add</span>
{
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">int</span> Calculate(<span class="reserved">int</span> x) =&gt; Left.Calculate(x) + Right.Calculate(x);
}

<span class="reserved">class</span> <span class="type">Mul</span>
{
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">int</span> Calculate(<span class="reserved">int</span> x) =&gt; Left.Calculate(x) * Right.Calculate(x);
}
</code></pre>
<p>一方、型スイッチを使って書くなら以下のようになります。</p>
<pre class="source" title="型スイッチで実装する例">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">NodeExtensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> Calculate(<span class="reserved">this</span> <span class="type">Node</span> n, <span class="reserved">int</span> x)
    {
        <span class="reserved">switch</span> (n)
        {
            <span class="reserved">case</span> <span class="type">Var</span> v: <span class="reserved">return</span> x;
            <span class="reserved">case</span> <span class="type">Const</span> c: <span class="reserved">return</span> c.Value;
            <span class="reserved">case</span> <span class="type">Add</span> a: <span class="reserved">return</span> Calculate(a.Left, x) + Calculate(a.Right, x);
            <span class="reserved">case</span> <span class="type">Mul</span> m: <span class="reserved">return</span> Calculate(m.Left, x) * Calculate(m.Right, x);
        }
        <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentOutOfRangeException</span>();
    }
}
</code></pre>
<p>それぞれ、以下のような特徴があります。</p>
<ul>
<li>
性能:
<ul>
<li>〇 仮想メソッドはかなり実行性能がいい</li>
<li>× 型スイッチでは性能面はかなわない</li>
</ul>
</li>
<li>
実装の強制
<ul>
<li>〇 仮想メソッドなら、抽象メソッドにしておけば派生クラスでの実装漏れがあり得なくなる</li>
<li>× 型スイッチの場合、<code>case</code>への追加忘れがあり得る</li>
</ul>
</li>
<li>
実装を書ける場所
<ul>
<li>× 仮想メソッドはクラスの中にないとダメ</li>
<li>〇 型スイッチなら拡張メソッドなど、クラスの外でも使える</li>
</ul>
</li>
</ul>
<p>基本的にはやっぱり仮想メソッドの方が性能・使い勝手の面で良かったりします。
ただ、仮想メソッド最大の問題は、クラスの中に書くのが必須ということです。
どうしてもクラスの中には書けない(クラスの作者自身が書けず、第三者が書く必要がある)場合というのはあって、
この場合は型スイッチを使う必要があります。</p>
<p>クラスの中に書くということは、そのクラスを使いたい人なら誰でも使うような汎用的な機能なはずです。
仮想メソッドはそういう汎用的な機能にしか使えないということになります。</p>
<p>一方で、使う人それぞれの固有の事情であれば、使う人の側が自分で書くことになるでしょう。</p>
<p>例えば、表示要件を考えてみます。
あるアプリでは、「<code>x * x + 1</code>」というように、プログラミング言語によくあるように、掛け算を<code>*</code>で表して文字列化したいかもしれません。
またあるアプリでは、「<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>×</mo><mi>x</mi><mo>+</mo><mn>1</mn></math>」というように、ちゃんと数式フォントで、掛け算には×記号を使って表示したいかもしれません。
数式表示のためには、自前でレンダリングを行うべきかもしれませんし、
「<code>&lt;math&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/math&gt;</code>」というようなMathML文字列を作って、これを何らかのライブラリに解釈してもらうのがいいかもしれません。</p>
<p>数式データを使う用途もアプリごとに変わってくるでしょう。
あるアプリでは、数式を組版して表示すること自体が目的かもしれません。
またあるアプリでは、数式を微分したり方程式の解を求めたり、数学計算のために使うかもしれません。
あるいは、プログラミング言語を作っていて、式を計算するCPU命令を出力するための中間形式として使うかもしれません。</p>
<p>こういう、クラス作者側では用途が見えないものは、型スイッチを使って書くことになります。</p>
<h3><a id="performance">補足: 型スイッチの性能</h3>
<p>仮想メソッドと比べると遅いという話をしましたが、これは、仮想メソッドが性能よすぎるだけで、
型スイッチもそこまでひどい性能ではありません。
先ほどの<code>Calculate</code>の例でいうと、大まかに計測したところ4倍程度の差でした。</p>
<p>「型を見る」というと、<a href="http://ufcpp.net/study/csharp/sp_reflection.html">リフレクション</a>を想像する人がいるようです。
リフレクションを使う場合、確かに、2・3桁(2・3倍じゃなくて、桁が変わる)遅くなる場合があります。
しかし、型スイッチに必要なのは「その型に代入できるかどうか」だけで、これはそこそこ高速な処理です。
リフレクションで遅いのは、「ある型がどういうメンバーを持っているか調べる」であるとか、
「メソッド名を文字列で渡してメソッドを探して、そのメソッドを実行する」であるとかです。</p>
<p>要するに、リフレクションで取れる型情報や、それの使い方には何段階かあって、それぞれ負荷の度合いも変わります。</p>
<p><img src="/media/1095/typeinfo.png" alt="型情報の使い方と実行速度" /></p>
<p>型識別だけなら大したコストは掛かりません。そして、型スイッチが使うのはこの型識別情報だけです。</p>
<p>むしろ、型スイッチの遅さの原因は、
<a href="http://ufcpp.net/study/csharp/datatype/typeswitch/?p=2#sequential">前項</a>で説明したような、逐次判定のせいです。
上から1つ1つ<code>case</code>の条件判定しているので、平均的には<code>case</code>の数に比例した処理量が必要になります。</p>
<!-- pageBreak -->
<h2><a id="generic-type-switch">余談: ジェネリック型に対する型パターン</h2>
<h5 class="version version7_1">Ver. 7.1</h5>
<p>C# 7.0の時点では、<a href="http://ufcpp.net/study/csharp/sp2_generics.html">ジェネリクス</a>が絡む場合、
例えば以下のようなコードはコンパイル エラーになっていました。
(ジェネリックな型<code>T</code>の変数に対して<code>switch</code>できない。ちなみに、一度<code>object</code>にキャストすればできる。)</p>
<pre class="source" title="C# 7.0ではコンパイルできないswitchの例">
<code><span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x)
{
    <span class="reserved">switch</span> (x)
    {
        <span class="reserved">case</span> <span class="reserved">int</span> i:
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="reserved">string</span> s:
            <span class="reserved">break</span>;
    }
}
</code></pre>
<p>「<code>T</code>を<code>int</code>や<code>string</code>として処理できない」と言った旨のコンパイル エラーが出ます。</p>
<p>さらにいうと、以下のような需要が結構ありそうな場面でも、C# 7.0ではコンパイル エラーになりました。</p>
<pre class="source" title="C# 7.0ではコンパイルできないswitchの例(型制約付き)">
<code><span class="reserved">class</span> <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">Derived1</span> : <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">Derived2</span> : <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">Derived3</span> : <span class="type">Base</span> { }

<span class="comment">// こういう、型制約付きのやつですら 7.0 ではダメだった</span>
<span class="reserved">static</span> <span class="reserved">void</span> N&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">Base</span>
{
    <span class="reserved">switch</span> (x)
    {
        <span class="reserved">case</span> <span class="type">Derived1</span> d:
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="type">Derived2</span> d:
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="type">Derived3</span> d:
            <span class="reserved">break</span>;
    }
}
</code></pre>
<p>C# 7.0でも、以下のように、<code>as</code>演算子を使った場合にはちゃんとコンパイルできます。
型パターンは、内部的には<code>as</code>演算子に展開される機能で、<code>as</code>演算子にできて型パターンにできないことがあるのは不自然です。</p>
<pre class="source" title="as 演算子での置き換え">
<code><span class="reserved">static</span> <span class="reserved">void</span> N&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">Base</span>
{
    { <span class="reserved">var</span> d = x <span class="reserved">as</span> <span class="type">Derived1</span>; <span class="reserved">if</span> (d != <span class="reserved">null</span>) { <span class="reserved">return</span>; } }
    { <span class="reserved">var</span> d = x <span class="reserved">as</span> <span class="type">Derived2</span>; <span class="reserved">if</span> (d != <span class="reserved">null</span>) { <span class="reserved">return</span>; } }
    { <span class="reserved">var</span> d = x <span class="reserved">as</span> <span class="type">Derived3</span>; <span class="reserved">if</span> (d != <span class="reserved">null</span>) { <span class="reserved">return</span>; } }
}
</code></pre>
<p>そこで、C# 7.1では、上記コードのような、ジェネリックな型に対する型パターンを使えるようになりました。
(新機能というよりは、仕様漏れ・バグ修正の類です。)</p>
<h2><a id="generic-is-null">余談: ジェネリック型に対する is null</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 から、
以下のコードがコンパイルできるようになりました。</p>
<pre class="source" title="ジェネリック型に対する is null">
<code><span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">M</span>&lt;<span class="type">T</span>&gt;(<span class="type">T</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">null</span>;
</code></pre>
<p>元々 <code>x == null</code> であればコンパイルできていたのに、<code>x is null</code> がコンパイルできないのは変だということで修正されました。
型引数 <code>T</code> が<a href="/study/csharp/sp2_nullable.html#non-nullable">非 null 値型</a>の時には常に false になります。</p>
<!-- pageBreak -->
<h2><a id="switch-expression">switch 式</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 では、<code>switch</code> の<a href="/study/csharp/structured/miscexpressions/#term">式</a>版が追加されました。
式なので戻り値が必須ですが、どこにでも書けて便利です。
また、従来の <code>switch</code> ステートメントは C# の前身となるC言語のものの名残を強く残し過ぎていて使いにくいものでしたが、その辺りも解消されて使いやすくなりました。</p>
<p>例えば、以下のような列挙型を使った分岐を考えてみます。</p>
<pre class="source" title="例として使う列挙型(改元で困るやつ)">
<code><span class="reserved">using</span> <span class="reserved">static</span> <span class="type">年号</span>;
 
<span class="reserved">enum</span> <span class="type">年号</span>
{
    明治, 大正, 昭和, 平成
}
</code></pre>
<p>これまでだと、以下のような書き方をせざるを得ないことがあったかと思います。</p>
<pre class="source" title="switch ステートメントの例">
<code><span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">年号</span> <span class="variable">e</span>)
{
    <span class="reserved">int</span> <span class="variable">y</span>;
    <span class="control">switch</span> (<span class="variable">e</span>)
    {
        <span class="control">case</span> 明治:
            <span class="variable">y</span> = 45;
            <span class="control">break</span>;
        <span class="control">case</span> 大正:
            <span class="variable">y</span> = 15;
            <span class="control">break</span>;
        <span class="control">case</span> 昭和:
            <span class="variable">y</span> = 64;
            <span class="control">break</span>;
        <span class="control">case</span> 平成:
            <span class="variable">y</span> = 31;
            <span class="control">break</span>;
        <span class="control">default</span>: <span class="control">throw</span> <span class="reserved">new</span> <span class="type">InvalidOperationException</span>();
    }
    <span class="comment">// y を使って何か</span>
}
</code></pre>
<p>こういう書き方は結構しんどいわけですが、しんどい理由は以下のような点にあります。</p>
<ul>
<li>それぞれの条件で1つずつ値を返したいだけなのにステートメントを求められる</li>
<li><code>break</code> が必須</li>
<li><code>case</code> ラベルもうざい</li>
</ul>
<p>ちょこっとごまかす方法として、以下のように別メソッドを1段挟む方法もあるにはありますが、相変わらず<code>case</code>や<code>return</code>がうっとおしいです。</p>
<pre class="source" title="1段メソッドを挟んでごまかす">
<code><span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">年号</span> <span class="variable">e</span>)
{
    <span class="reserved">int</span> <span class="method">lastYear</span>()
    {
        <span class="control">switch</span> (<span class="variable">e</span>)
        {
            <span class="control">case</span> 明治: <span class="control">return</span> 45;
            <span class="control">case</span> 大正: <span class="control">return</span> 15;
            <span class="control">case</span> 昭和: <span class="control">return</span> 64;
            <span class="control">case</span> 平成: <span class="control">return</span> 31;
            <span class="control">default</span>: <span class="control">throw</span> <span class="reserved">new</span> <span class="type">InvalidOperationException</span>();
        }
    }
 
    <span class="reserved">var</span> <span class="variable">y</span> = <span class="method">lastYear</span>();
    <span class="comment">// y を使って何か</span>
}
</code></pre>
<p>これは、C# 8.0 の <code>switch</code> 式を使うと、以下のように書き直すことができます。</p>
<pre class="source" title="switch 式で書き直し">
<code><span class="reserved">public</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="type">年号</span> <span class="variable">e</span>)
{
    <span class="reserved">var</span> <span class="variable">y</span> = <span class="variable">e</span> <span class="control">switch</span>
    {
        明治 =&gt; 45,
        大正 =&gt; 15,
        昭和 =&gt; 64,
        平成 =&gt; 31,
        <span class="reserved">_</span> =&gt; <span class="control">throw</span> <span class="reserved">new</span> <span class="type">InvalidOperationException</span>()
    };
    <span class="comment">// y を使って何か</span>
}
</code></pre>
<p>文法的には以下のようになります。</p>
<pre class="source" title="switch式の書式">
<code><span class="input">変数</span> <span class="control">switch</span>
{
    <span class="input">パターン1</span> =&gt; <span class="input">式1</span>,
    <span class="input">パターン2</span> =&gt; <span class="input">式2</span>,
      ・
      ・
      ・
}
</code></pre>
<p>ステートメントの方の<code>switch</code>との弁別のために、<code>switch</code>キーワードは後置きになっています。</p>
<p>最後の1個のコンマはあってもなくてもかまいません。
<a href="/study/csharp/st_array.html">配列</a>や<a href="/study/csharp/sp3_lambda.html?sec=init#init">オブジェクト初期化子、コレクション初期化子</a>と同様です。</p>
<p>パターンの部分には「<a href="/study/csharp/datatype/patterns/">パターン マッチング</a>」で説明している任意のパターンを書けます。
また、<a href="/study/csharp/datatype/typeswitch/?p=2#switch"><code>when</code>句</a>を付けることもできます。</p>
<pre class="source" title="switch 式に型パターン、破棄パターン、when 句">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">obj</span>) =&gt; <span class="variable">obj</span> <span class="control">switch</span>
{
    <span class="reserved">int</span> <span class="variable">x</span> <span class="control">when</span> <span class="variable">x</span> &gt; 0 =&gt; 1,
    <span class="reserved">int</span> <span class="reserved">_</span> =&gt; 2,
    <span class="reserved">_</span> =&gt; 3,
};
</code></pre>
<h3><a id="switch-priority">switch 式の優先度</h3>
<p><code>switch</code> 式の優先度は単項演算の下、乗除演算の上になります。
<code>++x</code> や <code>await x</code> は <code>switch</code> 式よりも先に評価されて、
<code>x * y</code> や <code>x + y</code> は <code>switch</code> 式よりも後に評価されます。</p>
<pre class="source" title="switch 式の優先度の例">
<code><span class="comment">// これは (await b) switch { ... } の意味になって、</span>
<span class="comment">// bool を await できないのでコンパイル エラー。</span>
<span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">M1</span>(<span class="reserved">bool</span> <span class="variable">b</span>, <span class="type">Task</span> <span class="variable">x</span>, <span class="type">Task</span> <span class="variable">y</span>)
    =&gt; <span class="reserved">await</span> <span class="variable">b</span> <span class="control">switch</span> { <span class="reserved">true</span> =&gt; <span class="variable">x</span>, <span class="reserved">false</span> =&gt; <span class="variable">y</span> };
 
<span class="comment">// これは (++x) switch { ... } の意味で、</span>
<span class="comment">// x に -1 を渡した時だけ false に。</span>
<span class="reserved">static</span> <span class="reserved">bool</span> <span class="method">M2</span>(<span class="reserved">int</span> <span class="variable">x</span>)
    =&gt; ++<span class="variable">x</span> <span class="control">switch</span> { 0 =&gt; <span class="reserved">false</span>, <span class="reserved">_</span> =&gt; <span class="reserved">true</span> };
 
<span class="comment">// これは y * (switch { ... }) の意味で、</span>
<span class="comment">// 0 か y が返る。</span>
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M2</span>(<span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>)
    =&gt; <span class="variable">y</span> * <span class="variable">x</span> <span class="control">switch</span> { 0 =&gt; 0, <span class="reserved">_</span> =&gt; 1 };
</code></pre>
<h3><a id="exhaustive">網羅性</h3>
<p>式であるからには、<code>switch</code> 式は必ず値を返す必要があります。
なので、パターンには網羅性(exhaustiveness)が求められます。
すなわち、「どのパターンも満たさず<code>switch</code>式を抜けてしまう」みたいな状態は許容されません。
ちゃんと C# コンパイラーが網羅性をチェックしていて、抜けがあるとコンパイル エラーになります。</p>
<p>多くの場合、末尾に<a href="/study/csharp/datatype/patterns/#var"><code>var</code>パターン</a>か<a href="/study/csharp/datatype/patterns/#discard">破棄パターン</a>を書いて漏れを防ぎます。</p>
<pre class="source" title="var/破棄で「残り全部」を網羅">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    1 =&gt; 2,
    2 =&gt; 4,
    <span class="reserved">_</span> =&gt; 8, <span class="comment">// 破棄パターンで「残り全部」を受付</span>
};
 
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    <span class="reserved">int</span> <span class="variable">i</span> =&gt; <span class="variable">i</span>,
    <span class="reserved">string</span> <span class="variable">s</span> =&gt; <span class="variable">s</span>.Length,
    <span class="reserved">var</span> other =&gt; <span class="variable">other</span>.<span class="method">GetHashCode</span>(), <span class="comment">// var パターンで「残り全部」を受付</span>
};
</code></pre>
<p>今のところ、<code>bool</code>だけは網羅性を確実にチェックできます。</p>
<pre class="source" title="bool の網羅性チェック">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> <span class="control">switch</span>
{
    <span class="reserved">true</span> =&gt; 1,
    <span class="reserved">false</span> =&gt; 0,
    <span class="comment">// true/false で全パターン網羅できているので _ とかは不要</span>
};
 
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">x</span>, <span class="reserved">bool</span> <span class="variable">y</span>) =&gt; (<span class="variable">x</span>, <span class="variable">y</span>) <span class="control">switch</span>
{
    (<span class="reserved">false</span>, <span class="reserved">false</span>) =&gt; 0,
    (<span class="reserved">true</span>, <span class="reserved">false</span>) =&gt; 1,
    (<span class="reserved">false</span>, <span class="reserved">true</span>) =&gt; 2,
    (<span class="reserved">true</span>, <span class="reserved">true</span>) =&gt; 4,
    <span class="comment">// 上記4パターンしかありえないので _ とかは不要</span>
};
</code></pre>
<p>将来的には、<code>enum</code>型の網羅性や、派生クラスの網羅性もチェックしたいそうですが、
「後からのメンバー追加に弱くなる」など課題があるため、実装されるかどうかは不明瞭です。</p>
<h4><a id="bool-exhaustiveness">余談: bool の網羅性</h4>
<p>前節の<code>switch</code>式の網羅性チェックと関連して、ステートメントの方の<code>switch</code>でも、<code>bool</code>の網羅性チェックが働くようになりました。
C# 8.0 前後で挙動が変わるのでご注意ください。</p>
<p>すなわち、以下のような<code>switch</code>ステートメントを書いたとき、<code>default</code>句に関する扱いが変わります。</p>
<pre class="source" title="bool の網羅性">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">b</span>)
{
    <span class="control">switch</span> (<span class="variable">b</span>)
    {
        <span class="control">case</span> <span class="reserved">false</span>: <span class="control">return</span> 0;
        <span class="control">case</span> <span class="reserved">true</span>: <span class="control">return</span> 1;
        <span class="control">default</span>: <span class="control">return</span> -1;
    }
}
</code></pre>
<ul>
<li>C# 7.3 以前: <code>default</code> が必須</li>
<li>C# 8.0 以降: <code>default</code> が要らないというか、むしろ書くと警告(絶対に来ない条件があるという扱い)</li>
</ul>
<p>C# 7.3 以前がどうしてそうなっていたかは以前ブログを書いたのでそちらを参照してください: 「<a href="/blog/2019/1/falsetrueother/">bool 型の false, true, それ以外</a>」。</p>
<h3><a id="target-typed">ターゲットからの型決定</h3>
<p><code>switch</code> 式にはターゲットからの型推論が働きます。</p>
<p>ここでいうターゲットというのは結果を渡す先のことで、例えば以下のような書き方をした場合、
null を渡す先が <code>int?</code> 型の変数なので、この <code>int?</code> が「ターゲットの型」になります。</p>
<pre class="source" title="ターゲット(渡す先)の型(この場合は int?)">
<code><span class="reserved">int</span>? <span class="variable">x</span> = <span class="reserved">null</span>;
</code></pre>
<p><code>switch</code> 式では、いろいろな条件でいろいろな値を返すわけですが、
値から「共通の型」を決定できない場合があります。
例えば、以下のように、(例え同じクラスから派生していたとしても)異なる型 <code>A</code> と <code>B</code> の「共通の型」は判定できず、
コンパイル エラーを起こします。</p>
<pre class="source" title="共通の型を見つけられなくてエラーになる例">
<code><span class="reserved">class</span> <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">A</span> : <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">Base</span> { }
 
<span class="reserved">static</span> <span class="reserved">object</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">i</span>)
{
    <span class="comment">// 値が A と B で違う型なので、switch 式が返す型を決定できない。</span>
    <span class="comment">// コンパイル エラーになる。</span>
    <span class="reserved">var</span> <span class="variable">x</span> = <span class="variable">i</span> <span class="error"><span class="control">switch</span></span>
    {
        0 =&gt; <span class="reserved">new</span> <span class="type">A</span>(),
        <span class="reserved">_</span> =&gt; <span class="reserved">new</span> <span class="type">B</span>(),
    };
 
    <span class="control">return</span> <span class="variable">x</span>;
}
</code></pre>
<p>これくらいならば <code>Base</code> が共通の型だと判定してほしくも思いますが、
多段派生していたり、インターフェイスも実装していたり複雑な場合のことを考えるとそんなに簡単な話ではありません。</p>
<pre class="source" title="共通型の決定が難しい例">
<code><span class="comment">// 型 D と F の「共通型」といわれると何？</span>
<span class="comment">// インターフェイス J？ それともクラス A？</span>
<span class="reserved">interface</span> <span class="type">I</span> { }
<span class="reserved">interface</span> <span class="type">J</span> { }
<span class="reserved">class</span> <span class="type">A</span> { }
<span class="reserved">class</span> <span class="type">B</span> : <span class="type">A</span>, <span class="type">I</span> { }
<span class="reserved">class</span> <span class="type">C</span> : <span class="type">A</span> { }
<span class="reserved">class</span> <span class="type">D</span> : <span class="type">B</span>, <span class="type">J</span> { }
<span class="reserved">class</span> <span class="type">E</span> : <span class="type">B</span> { }
<span class="reserved">class</span> <span class="type">F</span> : <span class="type">C</span>, <span class="type">J</span> { }
</code></pre>
<p>この問題の回避策は2つあって、1つは特に難しいこともなく、「<a href="/study/csharp/st_cast.html#cast">キャスト</a>しろ」というものです。
C# コンパイラーが理解できるところまでかみ砕いたコードを書いてあげなきゃいけないということで、ちょっと煩雑なコードになります。</p>
<pre class="source" title="キャストで解決">
<code><span class="comment">// 片方を既定型にキャストしておくことで「共通型は Base」と判定できるようになる</span>
<span class="reserved">var</span> <span class="variable">x</span> = <span class="variable">i</span> <span class="control">switch</span>
{
    0 =&gt; (<span class="type">Base</span>)<span class="reserved">new</span> <span class="type">A</span>(),
    <span class="reserved">_</span> =&gt; <span class="reserved">new</span> <span class="type">B</span>(),
};
</code></pre>
<p>もう1つが本節の主題の「ターゲット型からの型決定」です。
先ほどの例では左辺が <code>var</code> (型推論)なのでコンパイルできませんが、
以下のように、ターゲット側の型を明示することで、<code>switch</code> 式の側の型を <code>Base</code> に決定できます。</p>
<pre class="source" title="ターゲットからの型決定">
<code><span class="comment">// 左辺(Base 型の変数)から switch 式の型を Base に決定。</span>
<span class="comment">// コンパイルできるようになる。</span>
<span class="type">Base</span> <span class="variable">x</span> = <span class="variable">i</span> <span class="control">switch</span>
{
    0 =&gt; <span class="reserved">new</span> <span class="type">A</span>(),
    <span class="reserved">_</span> =&gt; <span class="reserved">new</span> <span class="type">B</span>(),
};
</code></pre>
<p>特に役立つのは「1 と null」(<code>int?</code> になってほしい)とかでしょう。</p>
<pre class="source" title="1 と null の共通型を判定できないので代わりにターゲット型で解決">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">bool</span> <span class="variable">b</span>)
{
    <span class="comment">// これはコンパイル エラー。1 と null の共通型は C# 8.0 時点では決定できない。</span>
    <span class="reserved">var</span> <span class="variable">x</span> = <span class="variable">b</span> <span class="error"><span class="control">switch</span></span> { <span class="reserved">true</span> =&gt; 1, <span class="reserved">_</span> =&gt; <span class="reserved">null</span> };
 
    <span class="comment">// これはコンパイルできる。ターゲット型から int? に決定済みなので、1 も null も受け付ける。</span>
    <span class="reserved">int</span>? <span class="variable">y</span> = <span class="variable">b</span> <span class="control">switch</span> { <span class="reserved">true</span> =&gt; 1, <span class="reserved">_</span> =&gt; <span class="reserved">null</span> };
}
</code></pre> ]]></description>
				<pubDate>Mon, 11 Feb 2019 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>ファイナライザー</title>
				<link>http://www.ufcpp.net/study/csharp/resource/rm_destructor/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>(※本項で説明するファイナライザーは、かつてはデストラクター(destructor)と呼ばれていました。
うちのサイト内でもかつてはその表記だったため、今でも痕跡が残っている箇所があるかもしれません。
参考ブログ: <a href="https://ufcpp.net/blog/2025/5/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%8A%E3%83%A9%E3%82%A4%E3%82%B6%E3%83%BC/">ファイナライザー</a>)</p>
<p>ファイナライザーとは、オブジェクトが<a href="/study/computer/MemoryManagement.html?sec=garbage-collection#garbage-collection">ガベージ コレクション</a>に回収されるときに呼び出される特別なメソッドです。</p>
<p>「<a href="/study/csharp/oo_dispose.html">リソースの破棄</a>」で説明しているように、
基本的には、確保したリソースの後片付けは<code>Dispose</code>メソッドを<code>using</code>ステートメントを使って行います。
しかし、<code>using</code>ステートメントは呼び忘れる可能性があって、100%保証のある後片付けにはなりません。</p>
<p>一方で、ガベージ コレクションによって回収されるタイミングであれば、
呼び忘れの心配はありません。
そのため、確実に解放しなければならないリソースは、<code>Dispose</code>メソッドだけでなく、ファイナライザーでも後片付けを行います。
(もちろん、ガベージ コレクション自体を阻害するようなバグ(メモリ リーク)は起こり得て、
その場合はファイナライザーも呼ばれないため、かなりまずいです。)</p>
<h5>ポイント</h5>
<ul>
<li><code>~</code> + クラス名で、ファイナライザーと呼ばれる特殊なメソッドが定義できます</li>
<li>ファイナライザーはオブジェクトがガベージ コレクションで回収される際に呼ばれます</li>
<li>リソースの破棄を確実にするためには、<code>Dispose</code>メソッドに加えてファイナライザーも定義します</li>
</ul>
<h2><a id="dtor">ファイナライザー</h2>
<p><a href="/study/csharp/oo_construct.html">コンストラクター</a>とは逆に、インスタンスが破棄されるときに呼び出されるのがファイナライザーです。
ファイナライザーは以下のように、クラス名の前に <code>~</code> を付けた名前のメソッドを書くことで定義できます。</p>
<pre class="source" title="ファイナライザー例" lang="">
<code><span class="reserved">class</span> SampleClass
{
  <span class="comment">// ↓これがファイナライザー</span>
  ~SampleClass()
  {
    <span class="comment">// インスタンスの破棄用のコードを書く</span>
  }
}
</code></pre>
<p>ファイナライザーはコンストラクターと違って、引数を持つことができません。
また、<a href="/study/csharp/oo_conceal.html#level">アクセシビリティ</a>も指定できず、<a href="/study/csharp/oo_static.html"><code>static</code></a>にもできません。</p>
<h3><a id="when-to-destruct">注意: ファイナライザーの呼び出しタイミング</h3>
<p>.NET Framework では、インスタンスの寿命は .NET Framework 自体が管理していて、
いつインスタンスの破棄が行われるのかは分かりません。
（C++ 言語に慣れている人は注意が必要。）</p>
<pre class="source" title="ファイナライザーが呼び出されるタイミングは分からない" lang="">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> Test
{
  <span class="reserved">public</span> Test()
  {
    Console.Write(<span class="literal">"Test クラスのコンストラクターが呼ばれました\n"</span>);
  }

  ~Test()
  {
    Console.Write(<span class="literal">"Test クラスのファイナライザーが呼ばれました\n"</span>);
  }
}

<span class="reserved">class</span> DestructorSample
{
  <span class="reserved">static void</span> Main()
  {
    Console.Write(<span class="literal">"1\n"</span>);
    Test t = <span class="reserved">new</span> Test(); <span class="comment">// ここで Test のコンストラクターが呼ばれる</span>
    Console.Write(<span class="literal">"2\n"</span>);
    t = <span class="reserved">null</span>;            <span class="comment">// ↑で作成したインスタンスはもう利用されなくなる
                         // でも、ファイナライザーはまだ呼ばれない</span>
    Console.Write(<span class="literal">"3\n"</span>);
  }
}
</code></pre>
<pre class="console" title="">
1
Test クラスのコンストラクターが呼ばれました
2
3
Test クラスのファイナライザーが呼ばれました
</pre>
<p>この例では、ファイナライザーはプログラムの終了時に呼び出されます(「<a href="/study/csharp/resource/rm_gc?key=garbage-collection">ガベージ コレクション</a>」するときに呼ばれます)。
ガベージ コレクションのタイミングは、通常は制御できないので、ファイナライザーはいつ呼び出されるかわかりません。</p>
<p>このような性質を持っているため、通常、ファイナライザーはあまり利用されません。
ほぼ、非管理リソースの破棄漏れ防止用です(参考: 「<a href="/study/csharp/resource/rm_disposable?sec=idisposable">IDisposable インターフェイスの実装</a>」)。</p>
<p>破棄のタイミングを明示的に制御する必要がある場合
（例えば、何らかの外部リソース(ファイルやプリンタなど)の破棄(ファイルのバッファのフラッシュやプリンタの解放)を行う必要がある場合）、
後述する 「<a href="/study/csharp/resource/oo_dispose?key=using">using ステートメント</a>」というものを使った Dispose を行います。</p>
<h3><a id="finalize">注意: Finalize</h3>
<p>かつてのデストラクターという呼び名と、~ 記号を使う構文は C++ の構文を参考にしたものです。
しかし、C++ のデストラクター(変数のスコープを抜けたとき、もしくは、delete 演算子を呼んだタイミングで呼ばれる)とは呼び出されるタイミングが全然違うので注意してください。</p>
<p>C++ では、特定のスコープを抜けた時に確実に呼びたい処理のためにデストラクターを使うことがありますが、
こういう用途には、C# の場合、 「<a href="/study/csharp/resource/oo_dispose?key=using">using ステートメント</a>」 を使います。</p>
<p>C# のファイナライザー(旧称、デストラクター)は、動作的にはむしろ、Java の <code>finalize</code> メソッド(ガベージ コレクションに回収された時点で呼ばれる)と同じです。
実際、C# では「デストラクター」と呼んでいた頃も、.NET Framework の中間言語(＝ C#のコンパイル結果)的にはファイナライザーと呼んでいました。
呼び名の問題だけではなくて、中間言語にコンパイルした結果としては、(旧)デストラクターは <code>Finalize</code> という名前のメソッドになっています</p>
<p>ちなみに、通常、リソースの破棄処理は、 「<a href="/study/csharp/resource/oo_dispose?key=using">using ステートメント</a>」とファイナライザーでの2段構えで行います。
<code>using</code>ステートメントは高効率ですが確実性がなく、
ファイナライザーは確実ですがパフォーマンスが悪いです。
2段構えにすることで、忘れず<code>using</code>していればパフォーマンスがよく、忘れた場合でもファイナライザーでの確実な破棄ができます。
詳しくは「<a href="/study/csharp/rm_disposable.html#idisposable">IDisposable インターフェイスの実装</a>」で説明しています。</p>
 ]]></description>
				<pubDate>Sun, 21 Oct 2018 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[余談] 暗黙的な派生</title>
				<link>http://www.ufcpp.net/study/csharp/oop/miscimplictinherit/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>C# では「すべての<a href="/study/csharp/oo_reference.html#valtype">値型</a>は<code>ValueType</code>クラス(<code>System</code>名前空間)から派生する」というような、暗黙的な派生があります。</p>
<p>また、通常、値型(組み込み型や、構造体、列挙型)は他の型からの派生、他の型への派生ができませんが、
本項の「暗黙的な派生」だけは許されています。
ただ、内部的には、派生しているように見せかけるための特殊な変換処理が掛かっています。</p>
<h5>ポイント</h5>
<ul>
<li>全ての型は <code>Object</code> である</li>
<li>全ての値型は <code>ValueType</code> である</li>
<li>全ての列挙型は <code>Enum</code> である</li>
<li>全てのデリゲートは <code>Delegate</code> である</li>
<li>全ての配列は <code>Array</code> である</li>
</ul>
<h2><a id="special-types">特殊な型</h2>
<p>以下の型は、.NET/C# にとって特別な意味を持ちます。
いずれも <code>System</code> 名前空間中のクラスです。</p>
<table>
<thead>
<tr>
	<th>型名</th>
	<th>役割</th>
</tr>
</thead>
<tbody>
<tr>
	<td><code>Object</code></td>
	<td>全ての型の共通の最上位の基底クラス。C# のキーワードの <code>object</code> はこのクラスの別名になっている。</td>
</tr>
<tr>
	<td><code>ValueType</code></td>
	<td>全ての値型(<a href="/blog/2016/12/tipsprimitives/">プリミティブ型</a>、<a href="/study/csharp/resource/rm_struct/">構造体</a>、<a href="/study/csharp/st_enum.html">列挙型</a>)の共通基底クラス。</td>
</tr>
<tr>
	<td><code>Enum</code></td>
	<td>全ての<a href="/study/csharp/st_enum.html">列挙型</a>の共通基底クラス。<code>ValueType</code> クラスから派生。</td>
</tr>
<tr>
	<td><code>Delegate</code></td>
	<td>全ての<a href="/study/csharp/sp_delegate.html">デリゲート</a>の共通基底クラス。</td>
</tr>
<tr>
	<td><code>Array</code></td>
	<td>全ての<a href="/study/csharp/st_array.html">配列</a>の共通基底クラス。</td>
</tr>
</tbody>
</table>
<p>これらの型は「共通基底」として働きます。
基底クラスになっているので、派生しているどんな型でも受け取れる変数が作れます。</p>
<pre class="source" title="いろいろな型を受け付ける基底クラスの変数">
<code><span class="comment">// 整数でも DateTime 構造体でも UriKind 列挙型でも入る変数</span>
<span class="type">ValueType</span> x;
x = 1;
x = <span class="type">DateTime</span>.Now;
x = <span class="type">PlatformID</span>.Unix;

<span class="comment">// どんな型の配列でも入る変数</span>
<span class="type">Array</span> array;
array = <span class="reserved">new</span>[] { 1, 2, 3 };
array = <span class="reserved">new</span>[] { 1.2, 2.5, 3.9 };
array = <span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"b"</span>, <span class="string">"c"</span> };
</code></pre>
<p>また、これらのクラスのメンバーは、派生型から呼べます。
例えば、<code>Enum</code>クラスが持っている<code>HasFlag</code>メソッドは任意の列挙型に対して使えます。
(ただし、この<code>HasFlag</code>の利用には、後述するパフォーマンス上の注意点があります。)</p>
<pre class="source" title="">
<code><span class="reserved">using</span> System;

[<span class="type">Flags</span>]
<span class="reserved">enum</span> <span class="type">Flag</span>
{
    X = 1,
    Y = 2,
    Z = 4,
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="type">Flag</span> f = <span class="type">Flag</span>.X | <span class="type">Flag</span>.Y;
        <span class="reserved">if</span> (f.HasFlag(<span class="type">Flag</span>.X)) <span class="comment">// Flag 型に対して、Enum.HasFlag を呼んでる</span>
        {
            <span class="comment">// ...</span>
        }
    }
}
</code></pre>
<h2><a id="boxing"> ValueType, Enum とボックス化</h2>
<p>前述の <code>ValueType</code> や <code>Enum</code> はクラス(もちろん参照型)です。
これらに対して、値型である整数や列挙型の値を代入するとボックス化が起こります。</p>
<p>ボックス化については詳しくは「<a href="/study/csharp/RmBoxing.html">ボックス化</a>」で説明しているのでそちらをご覧ください。
簡単にいうと、本来値の持ち方が全然違う型に対して、内部的な変換処理が働いています。
この変換処理はそれなりに重たい処理で、パフォーマンス的には避けたいものです。
(元から参照型な<code>Array</code>(配列)や<code>Delegate</code>(デリゲート型)の場合は特に問題になりません。
<code>ValueType</code>と<code>Enum</code>だけの問題です。)</p>
<p>例えば以下のようなコードは、似たようなことに対して2つの書き方をしているだけですが、
パフォーマンス的にはだいぶ差があります。</p>
<pre class="source" title="ValueType への代入でボックス化">
<code><span class="comment">// 値型だけを受け付けたいとき、ValueType で引数を受け取るとボックス化が起きる</span>
<span class="reserved">static</span> <span class="reserved">void</span> A(ValueType value) { }

<span class="comment">// ボックス化を避けたければこう書く</span>
<span class="comment">// where T : struct 制約付きのジェネリック メソッドを用意</span>
<span class="reserved">static</span> <span class="reserved">void</span> B&lt;<span class="type">T</span>&gt;(T value) <span class="reserved">where</span> T : <span class="reserved">struct</span> { }

<span class="reserved">static</span> <span class="reserved">void</span> Main()
{
    <span class="comment">// 同じような呼び方をしていても、</span>
    <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 10000; i++)
    {
        <span class="comment">// こっちの方が倍は遅い</span>
        A(1);
        A(<span class="type">TimeSpan</span>.FromSeconds(1));
        A(<span class="type">PlatformID</span>.Unix);
    }

    <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 10000; i++)
    {
        B(1);
        B(<span class="type">TimeSpan</span>.FromSeconds(1));
        B(<span class="type">PlatformID</span>.Unix);
    }
}
</code></pre>
<p><a href="https://gist.github.com/ufcpp/0fd6fa47d05a21ad7fb559a615cd0460">単にこのメソッドを呼び出すだけのベンチマーク</a>を取ると、2倍～3倍程度の差が付きます。
(手元の環境では、<code>A</code>の方が167μ秒、<code>B</code>の方が66μ秒でした。)</p>
<p>できる限りはジェネリクスを使う方がいいでしょう。</p>
<h3><a id="enum-hasflag">Enum.HasFlag でのボックス化</h3>
<p>ちなみに、列挙型は、<code>Enum</code>型変数を経由しなくても、<code>HasFlag</code>メソッドを呼んだ時点でボックス化します。
なので長らく、このメソッドは「地雷」として有名だったんですが、
.NET Core 2.1では「<code>Enum.HasFlag</code>を見たら特別扱いして置き換える」と言うような最適化が掛かるようになったそうです。</p>
<p>例えば以下のようなコードは、<a href="https://gist.github.com/ufcpp/79283511d2a10afb34f8c5c837dce1a6">.NET Core 2.0以前と2.1以降で実行速度に20倍以上の差</a>があります。</p>
<pre class="source" title="">
<code>[<span class="type">Flags</span>]
<span class="reserved">enum</span> <span class="type">X</span>
{
    A = 1,
    B = 2,
    C = 4,
}

<span class="reserved">int</span> Count(<span class="type">X</span> x)
{
    <span class="reserved">var</span> count = 0;
    <span class="reserved">if</span> (x.HasFlag(<span class="type">X</span>.A)) count++;
    <span class="reserved">if</span> (x.HasFlag(<span class="type">X</span>.B)) count++;
    <span class="reserved">if</span> (x.HasFlag(<span class="type">X</span>.C)) count++;
    <span class="reserved">return</span> count;
}
</code></pre>
<h2><a id="constraints">Enum制約とDelegate制約</h2>
<h5 class="version version7">Ver. 7.3</h5>
<p>本項で紹介しているような「特殊な基底クラス」は、これまでジェネリクスの型制約には指定できませんでした。</p>
<pre class="source" title="Array は型制約には使えない">
<code><span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;()
    <span class="reserved">where</span> T : <span class="error">System.<span class="type">Array</span></span> <span class="comment">// エラーになる</span>
{ }
</code></pre>
<p>C# 7.3 からはこの制限が少しだけ緩和されて、<code>Enum</code>と<code>Delegate</code>の2つは制約にできるようになりました。</p>
<p><code>Enum</code>制約を付けると<a href="/study/csharp/st_enum.html">列挙型</a>だけを受け取れるジェネリック型・ジェネリック メソッドを作れます。</p>
<pre class="source" title="Enum制約">
<code>        <span class="reserved">static</span> <span class="reserved">void</span> EnumConstraint&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x, <span class="type">T</span> y)
            <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span>, <span class="type">Enum</span>
        {
            <span class="type">Console</span>.WriteLine(x.HasFlag(y));

            <span class="comment">// ちなみに、 == はダメ。Enum クラスに == はない。<span>
        }
</code></pre>
<p><a href="/study/csharp/oop/MiscImplictInherit#enum-hasflag">前述の.NET Core 2.1での最適化</a>の話と併せると、
.NET Core 2.1以降では有用な機能でしょう。</p>
<p>一方、<code>Delegate</code>制約の方は<a href="/study/csharp/sp_delegate.html">デリゲート</a>だけを受け取れます。
ちなみに、<code>Delegate</code>クラスにはさらに<code>MulticastDelegate</code>クラス(これも<code>System</code>名前空間)という派生クラスがいますが、この型も型制約として使えます。</p>
<pre class="source" title="Delegate/MulticastDelegate制約">
<code><span class="reserved">static</span> <span class="reserved">bool</span> M&lt;<span class="type">A</span>&gt;(<span class="type">A</span> a, <span class="type">A</span> b)
    <span class="reserved">where</span> <span class="type">A</span> : <span class="type">MulticastDelegate</span>
{
    <span class="comment">// Delegate は == 演算子を持ってる</span>
    <span class="reserved">return</span> a == b;
}

<span class="reserved">static</span> <span class="reserved">object</span> Invoke&lt;<span class="type">A</span>&gt;(<span class="type">A</span> a)
    <span class="reserved">where</span> <span class="type">A</span> : <span class="type">Delegate</span>
{
    <span class="comment">// Delegate.DynamicInvoke を呼ぶ</span>
    <span class="reserved">return</span> a.DynamicInvoke();
}
</code></pre>
<p>デリゲートの方は、<code>Enum.HasFlag</code>のような特殊な最適化が関わるわけではなく、
そこまで使い勝手は良くありません。
<a href="https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.expressions.expression.lambda?view=netframework-4.7.2#System_Linq_Expressions_Expression_Lambda_System_Linq_Expressions_Expression_System_Collections_Generic_IEnumerable_System_Linq_Expressions_ParameterExpression__"><code>Expression.Lambda&lt;TDelegate&gt;</code></a>のような一部のメソッドでのみ有効そうです。</p>
 ]]></description>
				<pubDate>Sat, 21 Apr 2018 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 7.3 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver7_3/</link>
				<description><![CDATA[ <div class="version version7_1">Ver. 7.3</div>
<table>
<tr>
<th>リリース時期</th>
<td>2018/5</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>Visual Studio 2017 15.7</li>
<li>.NET Core 2.1</li>
</td>
</tr>
<tr>
<th>要約・目玉機能</ht>
<td>
<ul>
<li>C# 7.0～7.2のちょっとした改善</li>
</ul>
</td>
</tr>
</table>
<p>C# 7.0 以降の「小数点リリース」も3つ目となりました。
これまでのC# 7系リリースで追加されてきた、
<a href="http://ufcpp.net/study/csharp/cheatsheet/ap_ver7/#tuple">タプル</a>や<a href="http://ufcpp.net/study/csharp/cheatsheet/ap_ver7_2/#ref">構造体と参照の活用</a>、<a href="http://ufcpp.net/study/csharp/cheatsheet/ap_ver7/#var-expressions">式中での変数宣言</a>になどに関する改善が含まれています。</p>
<h2><a id="tuple-equality">タプルの ==, != 比較</h2>
<p>タプル同士を <code>==</code>、<code>!=</code> 演算子で比較できるようになりました。
以下のように、メンバーごとの<code>==</code>を<a href="/study/csharp/st_operator.html#short-circuit"><code>&amp;&amp;</code></a>で繋いだものに展開されます。</p>
<pre class="source" title="タプル ==">
<code><span class="reserved">void</span> M((<span class="reserved">int</span> a, (<span class="reserved">int</span> x, <span class="reserved">int</span> y) b) t)
{
    <span class="comment">// このタプル == 比較は、</span>
    <span class="type">Console</span>.WriteLine(t == (1, (2, 3)));
    <span class="comment">// こんな感じで、メンバーごとの == を &amp;&amp; で繋いだものに展開される。</span>
    <span class="type">Console</span>.WriteLine(t.a == 1 &amp;&amp; t.b.x == 2 &amp;&amp; t.b.y == 3);
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/datatype/tuples/#equality">==、!= での比較</a>」で説明します。</p>
<h2><a id="ref-reassignment">ref 再代入</h2>
<p>参照引数、参照ローカル変数に対して、
参照先の値の書き換えではなく、「どこを参照しているか」自体を書き換えることができるようになりました。</p>
<pre class="source" title="ref 再代入">
<code><span class="reserved">int</span> x = 1;
<span class="reserved">int</span> y = 2;

<span class="comment">// x を参照。</span>
<span class="reserved">ref</span> var r = <span class="reserved">ref</span> x;

<span class="comment">// このとき、r に対する代入は x に反映される。</span>
r = 10; <span class="comment">// x が 10 になる。</span>

<span class="comment">// これが ref 再代入。</span>
<span class="comment">// r が y を参照するようになる。</span>
r = <span class="reserved"><em>ref</em></span> y;

<span class="comment">// 今度は、r に対する代入が y に反映される。</span>
r = 20; <span class="comment">// y が 20 になる。</span>

<span class="type">Console</span>.WriteLine((x, y)); <span class="comment">// (10, 20)</span>
</code></pre>
<p>また、同時に、<code>for</code>ステートメントと<code>foreach</code>ステートメントのループ変数を参照ローカル変数にできるようになりました。</p>
<p>詳しくは
「<a href="/study/csharp/sp_ref.html?p=2#ref-reassignment">ref再代入</a>」、
「<a href="/study/csharp/sp_ref.html?p=2#ref-for">for/foreach のループ変数を参照に</a>」で説明します。</p>
<h2><a id="var-expressions">式中での変数宣言(使える場所の拡充)</h2>
<p>C# 7.0から式中で、
<a href="/study/csharp/datatype/typeswitch/#is">is 演算子</a>や<a href="/study/csharp/sp_ref.html#out-var">出力変数宣言</a>を使って、
式中でも変数宣言できるようになりましたが、
いくつか制限がありました。
C# 7.3で、これまではできなかった以下の個所でも変数宣言ができるようにありました。</p>
<ul>
<li><a href="/study/csharp/start/st_scope/?p=3#query-expression">クエリ式</a></li>
<li><a href="/study/csharp/start/st_scope/?p=3#initializer">初期化子</a></li>
</ul>
<pre class="source" title="クエリ式中での変数宣言">
<code><span class="reserved">var</span> q =
    <span class="reserved">from</span> s <span class="reserved">in</span> <span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"abc"</span>, <span class="string">"112"</span>, <span class="string">"132"</span>, <span class="string">"451"</span>, <span class="reserved">null</span> }
    <span class="reserved">where</span> s <span class="reserved">is</span> <span class="reserved">string</span> <em>x</em> &amp;&amp; x.Length &gt; 1
    <span class="reserved">where</span> <span class="reserved">int</span>.TryParse(s, <span class="reserved">out var</span> <em>x</em>) &amp;&amp; (x % 3) == 0
    <span class="reserved">select</span> s;
</code></pre>
<pre class="source" title="初期化子内での変数宣言">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Derived</span> : <span class="type">base</span>
{
    <span class="reserved">public</span> Derived(<span class="reserved">string</span> s) : <span class="reserved">this</span>(<span class="reserved">int</span>.TryParse(s, <span class="reserved">out var</span> <em>x</em>) ? x : -1)
    {
        <span class="comment">// コンストラクター初期化子中で宣言した x は、コンストラクター本体内で利用可能。</span>
        <span class="type">Console</span>.WriteLine(x);
    }

    <span class="reserved">public</span> Derived(<span class="reserved">int</span> a) : <span class="reserved">base</span>(<span class="reserved">out var</span> <em>x</em>)
    {
        <span class="comment">// base の場合でも同様。</span>
        <span class="type">Console</span>.WriteLine(x);
    }

    <span class="comment">// フィールド初期化子、プロパティ初期化子中で宣言した x は、その初期化子内でのみ有効。</span>
    <span class="reserved">public</span> <span class="reserved">int</span> Field = <span class="reserved">int</span>.TryParse(<span class="string">"123"</span>, <span class="reserved">out var</span> <em>x</em>) ? x : -1;
    <span class="reserved">public</span> <span class="reserved">int</span> Property{ <span class="reserved">get</span>; <span class="reserved">set</span>; } = <span class="reserved">int</span>.TryParse(<span class="string">"123"</span>, <span class="reserved">out var</span> <em>x</em>) ? x : -1;
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/start/st_scope/?p=3#csharp7">C# 7での新しいスコープ ルール</a>」で説明します。</p>
<h2><a id="constraints">ジェネリック型引数に対する Enum、Delegate、unmanaged 制約</h2>
<p>3つほど指定できる制約が増えました。</p>
<table summary="型引数に対する制約条件(C# 7.2まで)">
	<caption>
		型引数に対する制約条件
	</caption>
	<tr>
		<th>制約の与え方</th>
		<th>説明</th>
	</tr>
	<tr>
		<td>
<code>where T : unmanaged</code>
</td>
		<td>
型<code>T</code>は「<a href="/study/csharp/sp_unsafe.html#unmanaged-types">アンマネージ型</a>」である
</td>
	</tr>
	<tr>
		<td>
<code>where T : Enum</code>
</td>
		<td>
型<code>T</code>は「<a href="/study/csharp/st_enum.html">列挙型</a>」である
</td>
	</tr>
	<tr>
		<td>
<code>where T : Delegate</code>
</td>
		<td>
型<code>T</code>は「<a href="/study/csharp/sp_delegate.html">デリゲート型</a>」である
</td>
	</tr>
</table>
<p>詳しくは「<a href="/study/csharp/sp2_generics.html#cs7.3">ジェネリック</a>」、
「<a href="/study/csharp/sp_unsafe.html#unmanaged-constraints">unsafe</a>」、
「<a href="/study/csharp/oop/MiscImplictInherit#constraints">[余談] 暗黙的な派生</a>」などで説明します。</p>
<h2><a id="overload-resolution">オーバーロード解決の改善</h2>
<p>オーバーロード解決が少し賢くなって、
これまでは呼び分けできなかったようなオーバーロードを呼び分けれるようになりました。</p>
<p>以下のようなものがあります。</p>
<ul>
<li>静的メソッドかインスタンス メソッドかの違いで解決できるようになった</li>
<li>ジェネリック型制約の違いで解決できるようになった</li>
<li>&nbsp; <a href="/study/csharp/st_function.html#key-method-group">メソッド グループ</a>を引数にするとき、メソッドの戻り値を見るようになった</li>
</ul>
<p>例えば、型制約だと、以下のような拡張メソッドの呼び分けができるようになりました。</p>
<pre class="source" title="class 制約と struct 制約の呼び分け">
<code><span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Linq;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">ClassExtensions</span>
{
    <span class="comment">// クラスの場合は LINQ の FirstOrDefault そのまま。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">T</span> FirstOrNull&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source)
        <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">class</span>
        =&gt; source.FirstOrDefault();
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">StructExtensions</span>
{
    <span class="comment">// 構造体の場合は null 許容型に変える必要がある。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">T</span>? FirstOrNull&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="type">T</span>&gt; source)
        <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">struct</span>
        =&gt; source.Select(x =&gt; (<span class="type">T</span>?)x).FirstOrDefault();
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// ClassExtensions の方のが呼ばれる。</span>
        <span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"b"</span>, <span class="string">"c"</span> }.FirstOrNull();

        <span class="comment">// StructExtensions の方のが呼ばれる。</span>
        <span class="reserved">new</span>[] { 1, 2, 3 }.FirstOrNull();
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/structured/miscoverloadresolution?p=2">[雑記]オーバーロード解決</a>」で説明します。</p>
<h2><a id="stackalloc-initializer">stackalloc 初期化子</h2>
<p><code>stackalloc</code>に対して、配列と同じような初期化子を使えるようになりました。
配列同様、初期化子中の要素の型からの推論も効きます。</p>
<pre class="source" title="">
<code><span class="comment">// 初期化子。{ } を使って初期値を与えられる。</span>
<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x1 = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[3] { 0xEF, 0xBB, 0xBF };

<span class="comment">// 初期化子があるとき、サイズは省略可能。</span>
<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x2 = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[] { 0xEF, 0xBB, 0xBF };

<span class="comment">// 初期化子から推論できるときは型名も省略可能。</span>
<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x3 = <span class="reserved">stackalloc</span>[] { 0xEF, 0xBB, 0xBF };
</code></pre>
<h2><a id="custom-fixed">ユーザー定義型の fixed ステートメント利用</h2>
<p>所定のパターンを満たす型に対して <code>fixed</code> ステートメントが使えるようになりました。
以下のように、<code>GetPinnableReference</code>という名前のメソッドを用意すれば使えます。</p>
<pre class="source" title="ユーザー定義型に対する fixed ステートメント">
<code><span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type">Array</span>&lt;<span class="type">T</span>&gt;
{
    <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="type">T</span>[] _array;
    <span class="reserved">public</span> Array(<span class="reserved">int</span> length) =&gt; _array = <span class="reserved">new</span> <span class="type">T</span>[length];
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="type">T</span> <span class="reserved">this</span>[<span class="reserved">int</span> index] =&gt; <span class="reserved">ref</span> _array[index];
    <span class="reserved">public</span> <span class="reserved">int</span> Length =&gt; _array.Length;

    <span class="comment">// このメソッドがあれば fixed ステートメントを使えるようになる</span>
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="type">T</span> GetPinnableReference() =&gt; <span class="reserved">ref</span> _array[0];
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
    {
        <span class="reserved">var</span> a = <span class="reserved">new</span> <span class="type">Array</span>&lt;<span class="reserved">int</span>&gt;(5);

        <span class="reserved">unsafe</span>
        {
            <span class="comment">// fixed (int* p = &amp;a.GetPinnableReference()) に展開される。</span>
            <span class="reserved">fixed</span> (<span class="reserved">int</span>* p = a)
            {
                <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 5; i++)
                    p[i] = i;
            }
        }

        <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 5; i++)
            System.<span class="type">Console</span>.WriteLine(a[i]);
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp_unsafe.html#custom-fixed">ユーザー定義型の fixed ステートメント利用</a>」で説明します。</p>
<h2><a id="others">その他</h2>
<p>その他、ほぼ「バグ修正」レベルの改善が2点あります。</p>
<h3><a id="field-attribute-on-auto-property">自動プロパティのバック フィールドに対する field 属性指定</h3>
<p>前者は、<a href="http://ufcpp.net/study/csharp/oo_property.html#auto">自動プロパティ</a>に対して <code>field</code> 指定の属性が付けられるようになりました。</p>
<pre class="source" title="自動プロパティが内部的に生成しているフィールドへの属性付け">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">XAttribute</span> : <span class="type">Attribute</span> { }

<span class="reserved">class</span> <span class="type">Sample</span>
{
    [<span class="reserved">field</span>:<span class="type">X</span>] <span class="comment">// 自動実装で生成されるフィールドに対する属性の指定</span>
    <span class="reserved">public</span> <span class="reserved">int</span> AutoProperty { <span class="reserved">get</span>; }
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp_attribute.html#auto-impl">プロパティ、イベントと属性の対象</a>」で説明します。</p>
<h3><a id="movable-fixed-buffer">固定長バッファーの読み書きで、fixed ステートメント不要に</h3>
<p><a href="/study/csharp/sp_unsafe.html#fixed-buffer">固定長バッファー</a>の読み書きをする際、
<a href="/study/csharp/sp_unsafe.html#fixed"><code>fixed</code>ステートメント</a>が不要になる場面が増えたそうです。</p>
<pre class="source" title="fixed なしで固定長バッファーの読み書き">
<code><span class="reserved">unsafe</span> <span class="reserved">struct</span> <span class="type">Buffer</span>
{
    <span class="reserved">public</span> <span class="reserved">fixed</span> <span class="reserved">byte</span> A[8];
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="type">Buffer</span> _buffer;

    <span class="reserved">unsafe</span> <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> buffer = <span class="reserved">new</span> <span class="type">Buffer</span>();
        buffer.A[0] = 1; <span class="comment">// 元々 OK</span>
        _buffer.A[0] = 2; <span class="comment">// C# 7.3 から OK</span>

        RefFixedBuffer(<span class="reserved">ref</span> buffer);

        System.<span class="type">Console</span>.WriteLine(buffer.A[0]);  <span class="comment">// 元々 OK</span>
        System.<span class="type">Console</span>.WriteLine(_buffer.A[0]); <span class="comment">// C# 7.3 から OK</span>
    }

    <span class="reserved">unsafe</span> <span class="reserved">static</span> <span class="reserved">void</span> RefFixedBuffer(<span class="reserved">ref</span> <span class="type">Buffer</span> buffer)
    {
        buffer.A[1] = 3; <span class="comment">// C# 7.3 から OK</span>
    }
}
</code></pre>
<p><a href="https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/indexing-movable-fixed-fields.md">提案文書</a>にすら、「言語仕様上どうしてこの条件緩和が許されるのかを説明するのが難しい」とか書かれる始末な機能です…</p>
<p>本来はポインター操作になるので<code>fixed</code>ステートメントが必須なんですが、
C# コンパイラー的には<a href="/study/csharp/sp_ref.html?p=2#ref-returns">参照ローカル変数</a>と同じようなコード生成するらしく、
だったら<code>fixed</code>がなくても平気なはず、と言うことらしいです。</p>
 ]]></description>
				<pubDate>Sat, 14 Apr 2018 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 7.2 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver7_2/</link>
				<description><![CDATA[ <h2><a id="ver7_2">C# 7.2</h2>
<div class="version version7_1">Ver. 7.2</div>
<table>
<tr>
<th>リリース時期</th>
<td>2017/12</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>Visual Studio 2017 15.5</li>
</td>
</tr>
<tr>
<th>要約・目玉機能</ht>
<td>
<ul>
<li>構造体と参照の活用</li>
</ul>
</td>
</tr>
</table>
<p>C# 7.2で追加された機能の多くは「構造体と参照の活用によってパフォーマンス改善」と言った感じのものです。
パフォーマンスが求められるようなライブラリの作者にとっては重要になりますが、
多くのC#開発者にとっては直接利用する機能ではないかもしれません。
ただし、そういった開発者にとっても、
「知らないうちに使っていた」とか「使っているライブラリがなんだか速くなった」というような、
間接的な恩恵が受けられるものです。</p>
<p>また、C# 7.1に引き続いての小さな更新がいくつかあります。</p>
<p>※C# 7.2 は、リリース時点ではバグが多く、その後の更新で修正されたものが結構な数あります。
バグが多いのは主に<a href="/study/csharp/cheatsheet/ap_ver7_2/#ref">参照がらみの機能</a>の辺りです。
(具体的なバグについては<a href="/blog/2017/12/%E3%83%90%E3%82%B0%E5%A0%B1%E5%91%8A%E7%A5%AD%E3%82%8A/">昔書いたブログ</a>があるのでそちらを参照。)
本サイト内で説明している機能がうまく動かなかったときには、一度コンパイラーやVisual Studioのバージョンを挙げてみてください。</p>
<h2><a id="leading-separator">先頭区切り文字</h2>
<p><code>0b</code>、<code>0x</code>の直後に区切り文字の <code>_</code> を入れることができるようになりました。</p>
<pre class="source" title="">
<code><span class="comment">// C# 7.0 から書ける</span>
<span class="reserved">var</span> b1 = 0b1111_0000;
<span class="reserved">var</span> x1 = 0x0001_F408;

<span class="comment">// C# 7.2 から書ける</span>
<span class="comment">// b, x の直後に _ 入れてもOKに</span>
<span class="reserved">var</span> b2 = 0b_1111_0000;
<span class="reserved">var</span> x2 = 0x_0001_F408;
</code></pre>
<p>区切り文字に関しては「<a href="http://ufcpp.net/study/csharp/start/stnumber/#digit-separator">数字区切り文字</a>」を参照してください。</p>
<h2><a id="non-trailing-named">非末尾名前付き引数</h2>
<h5 class="version version7_1">Ver. 7.2</h5>
<p>前の方の引数を名前付きにできるようになりました。
例えば、以下のような書き方が許されるようになりました。</p>
<pre class="source" title="1つ目の引数だけを名前付きにする">
<code><span class="comment">// C# 7.2</span>
<span class="comment">// 末尾以外でも名前を書けるように</span>
Sum(x: 1, 2, 3);
</code></pre>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/sp4_optional.html#non-trailing-named">オプション引数・名前付き引数</a>」で説明します。</p>
<h2><a id="private-protected">private protected</h2>
<p><code>private protected</code>というキーワード(語順は自由)で、「<code>protected</code>かつ<code>internal</code>」なアクセシビリティを指定できるようになりました。</p>
<p><img src="/media/1142/accessibilitycs72.png" alt="private protected" /></p>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/oo_conceal.html#protected-internal">実装の隠蔽</a>」で説明します。</p>
<h2><a id="ref">参照の活用</h2>
<p>ここから先が、C# 7.2 の大部分を占める「参照の活用」になります。
小さな機能の組み合わせになっているのでそれぞれについて説明します。</p>
<h3><a id="conditional-ref">条件演算子での ref 利用</h3>
<p><a href="/study/csharp/st_operator.html#condition">条件演算子</a>の2項目、3項目を参照にできるようになりました。
以下のような書き方ができます。</p>
<pre class="source" title="条件演算子の中で ref を利用">
<code>x &gt; y ? <span class="reserved">ref</span> x : <span class="reserved">ref</span> y
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp_ref.html?p=2#conditional-ref">条件演算子での ref 利用</a>」で説明します。</p>
<h3><a id="ref-readonly">ref readonly</h3>
<p>「参照渡しだけども読み取り専用」というような渡し方ができるようになりました。
読み取り専用参照(ref readonly)と呼ばれています。</p>
<p>引数の場合には<code>in</code>修飾子を使って以下のように書きます。</p>
<pre class="source" title="in 引数でコピーを避ける">
<code><span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">Quaternion</span>
{
    <span class="reserved">public</span> <span class="reserved">double</span> W;
    <span class="reserved">public</span> <span class="reserved">double</span> X;
    <span class="reserved">public</span> <span class="reserved">double</span> Y;
    <span class="reserved">public</span> <span class="reserved">double</span> Z;
    <span class="reserved">public</span> Quaternion(<span class="reserved">double</span> w, <span class="reserved">double</span> x, <span class="reserved">double</span> y, <span class="reserved">double</span> z) =&gt; (W, X, Y, Z) = (w, x, y, z);

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Quaternion</span> <span class="reserved">operator</span> *(<span class="reserved"><em>in</em></span> Quaternion a, <span class="reserved"><em>in</em></span> Quaternion b)
        =&gt; <span class="reserved">new</span> Quaternion(
            a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z,
            a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y,
            a.W * b.Y + a.Y * b.W + a.Z * b.X - a.X * b.Z,
            a.W * b.Z + a.Z * b.W + a.X * b.Y - a.Y * b.X);
}
</code></pre>
<p><code>ref</code>引数や<code>out</code>引数とは異なり、<code>in</code>引数は以下のような呼び出し方ができます。</p>
<ul>
<li><code>F(x)</code> というように、修飾なしで呼ぶ</li>
<li><code>F(10)</code> というように、リテラルを引数として渡す</li>
<li><code>F(x + y)</code> というように、右辺値(式の計算結果)を引数として渡す</li>
</ul>
<p>また、ローカル変数と戻り値の場合は<code>ref readonly</code>修飾子を使います。</p>
<pre class="source" title="ref readonly な戻り値、ローカル変数">
<code><span class="reserved">static</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> Max(<span class="reserved">in</span> <span class="reserved">int</span> x, <span class="reserved">in</span> <span class="reserved">int</span> y)
{
    <span class="reserved">ref</span> <span class="reserved">readonly</span> var t = <span class="reserved">ref</span> x;
    <span class="reserved">ref</span> <span class="reserved">readonly</span> var u = <span class="reserved">ref</span> y;

    <span class="reserved">if</span> (t &lt; u) <span class="reserved">return</span> <span class="reserved">ref</span> u;
    <span class="reserved">else</span> <span class="reserved">return</span> <span class="reserved">ref</span> t;
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp_ref.html#in">入力参照引数 (in 引数)</a>」、「<a href="/study/csharp/sp_ref.html?p=2#ref-readonly">ref readonly</a>」で説明します。</p>
<h4><a id="in-operator">演算子のin引数</h4>
<p>これまで、<a href="/study/csharp/oo_operator.html">演算子オーバーロード</a>の引数は値渡しである必要がありました。
C# 7.2では、<code>in</code>引数も演算子の引数にできるようになりました。</p>
<pre class="source" title="演算子の in 引数">
<code><span class="reserved">struct</span> <span class="type">Complex</span>
{
    <span class="reserved">public</span> <span class="reserved">double</span> X;
    <span class="reserved">public</span> <span class="reserved">double</span> Y;
    <span class="reserved">public</span> Complex(<span class="reserved">double</span> x, <span class="reserved">double</span> y) =&gt; (X, Y) = (x, y);

    <span class="comment">// これは OK</span>
    <span class="reserved">public</span> <span class="reserved">static</span> Complex <span class="reserved">operator</span> +(Complex a, Complex b)
        =&gt; <span class="reserved">new</span> Complex(a.X + b.X, a.Y + b.Y);

    <span class="comment">// これはコンパイル エラーになる</span>
    <span class="reserved">public</span> <span class="reserved">static</span> Complex <span class="reserved">operator</span> <span class="error">+</span>(<span class="reserved">ref</span> Complex a, <span class="reserved">ref</span> Complex b)
        =&gt; <span class="reserved">new</span> Complex(a.X + b.X, a.Y + b.Y);

    <span class="comment">// これなら OK</span>
    <span class="reserved">public</span> <span class="reserved">static</span> Complex <span class="reserved">operator</span> +(<span class="reserved"><em>in</em></span> Complex a, <span class="reserved"><em>in</em></span> Complex b)
        =&gt; <span class="reserved">new</span> Complex(a.X + b.X, a.Y + b.Y);
}
</code></pre>
<h3><a id="ref-extensions">参照渡しの拡張メソッド</h3>
<p>拡張メソッドの第1引数(<code>this</code>が付いている引数)を参照渡し(<a href="http://ufcpp.net/study/csharp/sp_ref.html#sec-byref"><code>ref</code></a>もしくは<a href="http://ufcpp.net/study/csharp/sp_ref.html#in"><code>in</code></a>)で渡せるようになりました。</p>
<pre class="source" title="参照渡しの拡張メソッドの例">
<code><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">QuaternionExtensions</span>
{
    <span class="comment">// 構造体の書き換えを拡張メソッドでやりたい場合に ref 引数が使える</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> Conjugate(<em><span class="reserved">ref</span> <span class="reserved">this</span></em> Quaternion q)
    {
        <span class="reserved">var</span> norm = q.W * q.W + q.X * q.X + q.Y * q.Y + q.Z * q.Z;
        q.W = q.W / norm;
        q.X = -q.X / norm;
        q.Y = -q.Y / norm;
        q.Z = -q.Z / norm;
    }

    <span class="comment">// コピーを避けたい場合に in 引数が使える</span>
    <span class="reserved">public</span> <span class="reserved">static</span> Quaternion Rotate(<em><span class="reserved">in</span> <span class="reserved">this</span></em> Quaternion p, <span class="reserved">in</span> Quaternion q)
    {
        <span class="reserved">var</span> qc = q;
        qc.Conjugate();
        <span class="reserved">return</span> q * p * qc;
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/sp3_extension.html#ref-extensions">参照渡しの拡張メソッド</a>」で説明します。</p>
<h3><a id="readonly-struct">readonly struct</h3>
<p>構造体に <code>readonly</code> 修飾子を付けることで、以下のような制約を掛けれるようになりました。</p>
<ul>
<li>すべてのフィールドに<code>readonly</code>を付けることが必須</li>
<li><code>this</code>参照も<code>readonly</code>扱いされて、構造体の書き換えが完全にできなくなる</li>
</ul>
<pre class="source" title="readonly struct の例">
<code><span class="comment">// 構造体自体に readonly を付ける</span>
<span class="reserved"><em>readonly</em></span> <span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="comment">// フィールドには readonly が必須</span>
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> Y;

    <span class="reserved">public</span> Point(<span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; (X, Y) = (x, y);

    <span class="comment">// readonly を付けない場合と違って、以下のような this 書き換えも不可</span>
    <span class="comment">//public void Set(int x, int y) =&gt; this = new Point(x, y);</span>
}
</code></pre>
<p>詳細は「<a href="/study/csharp/resource/readonlyness/#readonly-struct">readonly struct</a>」で説明します。</p>
<p>「参照」とは直接は関係ないですが、<a href="/study/csharp/sp_ref.html#in">in 引数</a>や、ref safety rule (今後追加予定)と関連して必要になった機能です。</p>
<h3><a id="safe-stackalloc">安全な stackalloc</h3>
<p><code>Span&lt;T&gt;</code>構造体と併用することで、unsafe なしで <a href="/study/csharp/sp_unsafe.html#stackalloc"><code>stackalloc</code></a> を使えるようになりました。</p>
<pre class="source" title="ファイル読み込みの一時バッファーに stackalloc を使う例">
<code><span class="reserved">const</span> <span class="reserved">int</span> BufferSize = 128;

<span class="reserved">using</span> (<span class="reserved">var</span> f = <span class="type">File</span>.OpenRead(<span class="string">"test.data"</span>))
{
    <span class="reserved">var</span> rest = (<span class="reserved">int</span>)f.Length;
    <span class="comment">// Span&lt;byte&gt; で受け取ることで、new (配列)を stackalloc (スタック確保)に変更できる</span>
    <em><span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; buffer = <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[BufferSize];</em>

    <span class="reserved">while</span> (<span class="reserved">true</span>)
    {
        <span class="comment">// Read(Span&lt;byte&gt;) が追加された</span>
        <span class="reserved">var</span> read = f.Read(buffer);
        rest -= read;
        <span class="reserved">if</span> (rest == 0) <span class="reserved">break</span>;

        <span class="comment">// buffer に対して何か処理する</span>
    }
}
</code></pre>
<p><code>stackalloc</code>を使っていますがポインターは不要で、ちゃんと範囲チェックも掛かって安全に扱えます。</p>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/resource/span/#safe-stackalloc"><code>Span&lt;T&gt;</code>構造体</a>」で説明します。</p>
<h3><a id="span-safety">ref 構造体</h3>
<p>C# 7.2 と深く関連する型に<a href="/study/csharp/resource/span/"><code>Span&lt;T&gt;</code></a>という構造体があります。
この <code>Span&lt;T&gt;</code> は、C#7.2 の主たる目的の「構造体と参照の活用によってパフォーマンス改善」の主役となる構造体です。</p>
<p>この型を安全に使うためにはいくつが制限が必要で、そのために<code>ref</code>構造体という構文と、それに対するフロー解析が実装されました。</p>
<pre class="source" title="ref構造体を持てるのはref構造体だけ">
<code><span class="comment">// Span&lt;T&gt; は ref 構造体になっている</span>
<span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">Span</span>&lt;<span class="type">T</span>&gt; { ... }

まず、`Span<T>`を持てるのは`ref`修飾子がついた構造体(`ref`構造体)だけです。

<span class="comment">// ref 構造体を持てるのは ref 構造体だけ</span>
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">RefStruct</span>
{
    <span class="reserved">private</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; _span; <span class="comment">//OK</span>
}
</code></pre>
<p><code>ref</code>構造体には参照ローカル変数・参照戻りと同じ制限がかかります。</p>
<pre class="source" title="戻り値に返せるかどうか">
<code><span class="comment">// 引数で受け取ったものは戻り値で返せる</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; Success(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x) =&gt; x;

<span class="comment">// ローカルで確保したもの変数はダメ</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; Error()
{
    <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; x = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[1];
    <span class="reserved">return</span> <span class="error">x</span>;
}
</code></pre>
<p>その他、<code>ref</code>構造体には「スタック上になければならない(stack-only)」という制限があり、
その結果、例えば以下のような制限がかかります(一部抜粋)。</p>
<pre class="source" title="ref構造体は stack-only">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;

<span class="comment">//❌ インターフェイス実装</span>
<span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">RefStruct</span> : <span class="type"><span class="error">IDisposable</span></span> { <span class="reserved">public</span> <span class="reserved">void</span> Dispose() { } }

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">//❌ 非同期メソッドの引数</span>
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> Async(<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; <span class="error">x</span>)
    {
        <span class="comment">//❌ 非同期メソッドのローカル変数</span>
        <span class="error"><span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;</span> local = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[10];
    }

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; local = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[1];

        <span class="comment">//❌ クロージャ</span>
        <span class="type">Func</span>&lt;<span class="reserved">int</span>&gt; a1 = () =&gt; <span class="error">local</span>[0];
        <span class="reserved">int</span> F() =&gt; <span class="error">local</span>[0];

        <span class="comment">//❌ 型引数にも渡せない</span>
        <span class="type">List</span>&lt;<span class="error"><span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;</span>&gt; list;
    }
}
</code></pre>
<p>詳しくは「<a href="/study/csharp/resource/refstruct/">ref構造体</a>」で説明します。</p>
<h2><a id="minor-change">マイナーな更新</h2>
<p>C# の<a href="https://www.nuget.org/packages/Microsoft.Net.Compilers/">コンパイラー</a>のバージョン 2.7 や、Visual Studio 15.6 というバージョン(2018/3リリース)で、
C# にちょっとした修正が入っています。
かなりマイナーな更新なので、「C# 7.3」とはせず「C# 7.2 fix」(バグ修正扱い、あるいは、バグ修正とまとめてリリースして差し支えない程度の更新)としています。</p>
<p>修正されたのは以下の2点です。</p>
<ul>
<li>
参照渡しの拡張メソッド
<ul>
<li>2.6 時点: <code>ref this</code>、<code>in this</code> の語順でないとダメ</li>
<li>2.7 から: <code>this ref</code>、<code>this in</code> の語順でも OK</li>
</ul>
</li>
<li>
<code>in</code>引数のメソッド呼び出し/値渡しのメソッドとの呼び分け
<ul>
<li><code>void M(T x)</code>と<code>void M(in T x)</code>の両方のメソッドがあるとき</li>
<li>2.6 時点: <code>M(x)</code> という呼び出しはエラーになる</li>
<li>2.7 から: <code>M(x)</code> だと<code>void M(T x)</code>の方が、<code>M(in x)</code> だと <code>void M(in T x)</code>の方が呼ばれる</li>
</ul>
</li>
</ul>
<p>あくまで「C# 7.2に対する修正」としてリリースされているので、
新しい(2.7以降の)コンパイラーで、昔の(2.6以前の)挙動にすることはできません。
「できてしかるべきことができていなかったのを、できるようにしただけなので問題は起きないはず」という判断です。</p>
 ]]></description>
				<pubDate>Sun, 25 Mar 2018 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] デリゲートの内部</title>
				<link>http://www.ufcpp.net/study/csharp/functional/miscdelegateinternal/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p><a href="/study/csharp/sp_delegate.html">デリゲート</a>は、内部実装的には「インスタンスと関数ポインターをペアで管理しているクラス」になっています。</p>
<p>ここではデリゲートの内部挙動と、
それを踏まえたパフォーマンス上の注意点を説明します。</p>
<h2><a id="delegate-internal">デリゲートの内部</h2>
<p>デリゲートは .NET ランタイム内で特殊な扱いをされていて、
デリゲート内部で起こっていることをそのまま C# で書くことはできないので、
ここでの説明は疑似コード的なものになります。</p>
<h3><a id="delegate-type">型定義</h3>
<p>例えば、以下のようなデリゲートがあったとします。</p>
<pre class="source" title="例として使うデリゲート">
<code><span class="reserved">delegate</span> <span class="reserved">int</span> <span class="type">F</span>(<span class="reserved">int</span> x);
</code></pre>
<p>これは内部的には以下のような扱いになっています。
概ね、インスタンスと関数ポインターのペアです。</p>
<pre class="source" title="デリゲートの内部的な扱い">
<code><span class="reserved">class</span> <span class="type">F</span> : System.<span class="type">Delegate</span>
{
    <span class="reserved">object</span> Target;
    IntPtr FunctionPointer;
    <span class="comment">// 実際には Delegate クラスのメンバー</span>
    <span class="comment">// あと、object がもう1個と、IntPtr がもう1個ある</span>

    <span class="reserved">public</span> F(<span class="reserved">object</span> target, <span class="type">IntPtr</span> fp) =&gt; (Target, FunctionPointer) = (target, fp);

    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="reserved">int</span> Invoke(<span class="reserved">int</span> x)
    {
        <span class="comment">// return FunctionPointer(Target, x); 的な処理</span>
    }
}
</code></pre>
<p>実際にはこの他に2つのフィールドがあると書いていますが、
1つは<a href="/study/csharp/sp_delegate.html#malticast">マルチキャスト</a>用、
もう1つは<a href="#static-method">後述</a>する静的メソッドのために使うフィールドです。</p>
<h3><a id="new-delegate"> デリゲートのインスタンス生成</h3>
<p>C# では(C# 2.0 以降)、以下のように、デリゲート型の変数に対してメソッドを直接渡すような形でデリゲートを作ります。</p>
<pre class="source" title="デリゲートの作り方(C# 2.0 以降)">
<code><span class="comment">// インスタンス メソッドから生成</span>
<span class="reserved">var</span> x = <span class="reserved">new</span> <span class="type">Sample</span>();
<span class="type">F</span> i = x.Instance;

<span class="comment">// 静的メソッドから生成</span>
<span class="type">F</span> s = <span class="type">Sample</span>.Static;
</code></pre>
<p>これは省略形で、省略せずに書くなら以下のように、デリゲート型のインスタンスを<code>new</code>します
(C# 1.0 時代はこの書き方しかできない)。</p>
<pre class="source" title="">
<code><span class="comment">// インスタンス メソッドから生成</span>
<span class="reserved">var</span> x = <span class="reserved">new</span> <span class="type">Sample</span>();
<span class="type">F</span> i = <span class="reserved">new</span> <span class="type">F</span>(x.Instance);

<span class="comment">// 静的メソッドから生成</span>
<span class="type">F</span> s = <span class="reserved">new</span> <span class="type">F</span>(<span class="type">Sample</span>.Static);
</code></pre>
<p>ここで、先ほど説明した通り、デリゲート<code>F</code>のコンストラクターは内部的には<code>F(object, IntPtr)</code>という形になっています。
そして、上記のコードは、実際にはこのコンストラクターを呼ぶように展開されます。</p>
<p>まずインスタンス メソッドの方は以下のような処理に展開されます。</p>
<ul>
<li>インスタンス<code>x</code> を読み込む</li>
<li>メソッド <code>Instance</code> の関数ポインターを読み込む(<a href="/study/il/">IL</a> にはそのための <code>ldftn</code> という命令がある。)</li>
<li><code>F</code>のコンストラクター<code>F(object, IntPtr)</code>を呼び出す</li>
</ul>
<p>静的メソッドの場合にも同じコンストラクターを呼びます。
<code>object target</code>には null が渡ります。
すなわち、以下のような処理に展開されます。</p>
<ul>
<li>nullを読み込む。</li>
<li>メソッド <code>Static</code> の関数ポインターを読み込む</li>
<li><code>F</code>のコンストラクター<code>F(object, IntPtr)</code>を呼び出す</li>
</ul>
<p>ただし、JIT 時の最適化でコンストラクター呼び出しの部分が書き換えられて、
最終的にはインスタンス メソッド・静的メソッドそれぞれ専用の別処理が呼ばれるようです。
静的メソッドの場合には、後述する「ちょっとしたトリック」のための追加の処理が掛かります。</p>
<h3><a id="invoke-delegate"> 呼び出し側(Invokeの中身)</h3>
<p>デリゲートの呼び出しは以下のように書きます。</p>
<pre class="source" title="デリゲートの呼び出し">
<code>i(10);
s(20);
</code></pre>
<p>これも省略形みたいもので、省略せずに書くと<code>Invoke</code>メソッドの呼び出しになっています。</p>
<pre class="source" title="デリゲートの呼び出し(Invoke を明示的に呼ぶ)">
<code>i.Invoke(10);
s.Invoke(20);
</code></pre>
<p>ただし、JIT 時の最適化で<code>Invoke</code>メソッド呼び出しの部分が書き換えられて、
最終的には以下のような処理が残ります。</p>
<ul>
<li>デリゲートの <code>Target</code> フィールドを読み込む</li>
<li>引数の<code>int</code> (上記の例の 10 や 20)を読み込む</li>
<li>デリゲートの <code>FunctionPointer</code> に格納してあるアドレスにジャンプ</li>
</ul>
<h2><a id="static-method">静的メソッドを渡すと遅い</h2>
<p>インスタンス メソッドと静的メソッドは、内部的には実のところだいぶ異なる引数の受け取り方をしています。
インスタンス メソッドは、以下のように、静的メソッドよりも暗黙的に1引数多く受け取っています。</p>
<pre class="source" title="インスタンス メソッドと静的メソッドの引数の受け取り方">
<code><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> StaticMethod(<span class="reserved">int</span> x)
    {
        <span class="comment">// 静的メソッドの場合は正真正銘、引数は x の1つだけ</span>
    }

    <span class="reserved">void</span> InstanceMethod(<span class="reserved">int</span> x)
    {
        <span class="comment">// 引数が1つだけに見えて…</span>

        <span class="comment">// 実は暗黙的に this を受け取っている</span>
        Console.WriteLine(<span class="reserved">this</span>);
    }

    <span class="comment">// ということで ↑の InstanceMethod は、以下のような静的メソッドと同じ引数の受け取り方をしてる</span>
    <span class="reserved">static</span> <span class="reserved">void</span> InstanceLikeMethod(Sample @this, <span class="reserved">int</span> x)
    {
        Console.WriteLine(@this);
    }
}
</code></pre>
<p>このことを踏まえた上で、
前節の最後で説明したデリゲート呼び出しの手順を改めてみてみます。</p>
<ol>
<li>デリゲートの <code>Target</code> フィールド(静的メソッドの時には null が入っている)を読み込む</li>
<li>引数の<code>int</code> を読み込む</li>
<li>デリゲートの <code>FunctionPointer</code> に格納してあるアドレスにジャンプ</li>
</ol>
<p>デリゲートはインスタンス メソッドを参照していることもあれば、
静的メソッドを参照していることもあります。
しかし、呼び出し側では(インスタンス/静的によらず)常にこの手順で引数を渡しています。
すなわち、インスタンス メソッドの場合には素直に呼び出せるんですが、
静的メソッドの場合には内部的にちょっとしたトリックが働いています。</p>
<p>デリゲートに対して静的メソッドを渡すと、<code>FunctionPointer</code>には以下のような処理をする別のメソッドが入ります。</p>
<ul>
<li>1. で読み込んだインスタンスを無視して、引数の <code>int</code> だけを並べ直す</li>
<li>改めて、本来の静的メソッドにジャンプする</li>
</ul>
<p>この処理は意外と負担が高くて、デリゲートに対して静的メソッドを渡した場合、その呼び出しはかなり遅いです
(参考: <a href="https://gist.github.com/ufcpp/b2e64d8e0165746effbd98b8aa955f7e">計測コード</a>)。</p>
<p>要するに、デリゲートはインスタンス メソッドの時に処理が単純で高速になるように作られていて、
その代わりに静的メソッドが低速です。
C# ではインスタンス メソッドの方が圧倒的に利用頻度が高いので、
インスタンス メソッドに対して最適化した方が、全体としてのパフォーマンスは上がります。</p>
<h2><a id="curried-delegate">カリー化デリゲート</h2>
<p>前節の「静的メソッドに対するトリック」を回避して、
デリゲート越しの静的メソッドの呼び出しを速くする方法が1つあります。
「<a href="/study/csharp/sp3_extension.html#delegate">拡張メソッドのデリゲートへの代入</a>」で説明しているカリー化デリゲートという手段を使うと、インスタンス メソッドと同じコストで静的メソッドを呼べます。</p>
<p>拡張メソッドは、実体としては以下のように、第1引数でインスタンスを受け取る構造になっていて、
これがインスタンス メソッドの暗黙的な <code>this</code> 引数と同じ受け取り方になります。</p>
<pre class="source" title="インスタンス メソッドと拡張メソッドの引数の受け取り方">
<code><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public void</span> InstanceMethod(<span class="reserved">int</span> x)
    {
        <span class="comment">// 引数が1つだけに見えて、実は暗黙的に this を受け取っている</span>
    }

    <span class="comment">// ということで ↑の InstanceMethod は、以下のような静的メソッドと同じ引数の受け取り方をしてる</span>
    <span class="reserved">static</span> <span class="reserved">void</span> InstanceLikeMethod(<span class="type">Sample</span> @this, <span class="reserved">int</span> x)
    {
    }
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">SampleExtensions</span>
{
    <span class="comment">// であれば、こういう拡張メソッドも InstanceMethod と同じ引数の受け取り方になる</span>
    <span class="reserved">public static</span> <span class="reserved">void</span> ExtensionMethod(<span class="reserved">this</span> <span class="type">Sample</span> @this, <span class="reserved">int</span> x)
    {
    }
}
</code></pre>
<p>そこで、C# では、以下のように拡張メソッドに対して、インスタンス メソッドと同じようなデリゲートの作り方を認めています
(<code>x.E</code> のような書き方を、カリー化デリゲートと呼びます)。</p>
<pre class="source" title="拡張メソッドからデリゲートを作る">
<code><span class="reserved">var</span> x = <span class="reserved">new</span> <span class="type">Sample</span>();

<span class="type">Action</span>&lt;<span class="reserved">int</span>&gt; i = x.InstanceMethod;

<span class="comment">// 拡張メソッドに対して、インスタンス メソッドと同じようなデリゲートの作り方を認めてる</span>
<span class="type">Action</span>&lt;<span class="reserved">int</span>&gt; e = x.ExtensionMethod;
</code></pre>
<p><code>i</code>の方も<code>e</code>の方のどちらも、以下のように扱われます。</p>
<ul>
<li>インスタンス<code>x</code> を読み込む</li>
<li>メソッド <code>InstanceMethod</code>/<code>ExtensionMethod</code> の関数ポインターを読み込む</li>
<li><code>Action&lt;int&gt;</code>のコンストラクター<code>Action&lt;int&gt;(object, IntPtr)</code>を呼び出す</li>
</ul>
<p>通常の静的メソッドの場合と違って前述のトリックのための別処理への分岐も掛からず、
内部的にも完全に同じ処理になります。
呼び出しの際にもインスタンス メソッドと同じ処理になるため、
カリー化デリゲートは呼び出しは高速になっています。</p>
<h3><a id="optimization-static">(最適化手法1) 普通の静的メソッドを拡張メソッドに置き換え</h3>
<p>ちなみに、こういう内部挙動の結果、
以下のように、静的メソッドに対してダミー引数を1つ増やしてわざわざ拡張メソッド化する高速化手法が使えたりします。</p>
<pre class="source" title="カリー化デリゲートにすることで静的メソッドのデリゲートを高速化する例">
<code><span class="reserved">using</span> System;

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// 普通の静的メソッド</span>
    <span class="reserved">static</span> <span class="reserved">int</span> F(<span class="reserved">int</span> x) =&gt; 2 * x;

    <span class="comment">// わざわざ使いもしない第1引数を増やして、拡張メソッドに変更</span>
    <span class="reserved">static</span> <span class="reserved">int</span> F(<span class="reserved">this</span> <span class="reserved">object</span> dummy, <span class="reserved">int</span> x) =&gt; 2 * x;

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// 静的メソッドからデリゲート作成</span>
        <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; s = F;

        <span class="comment">// わざわざ null を使ってカリー化デリゲートにする</span>
        <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; e = <span class="reserved">default</span>(<span class="reserved">object</span>).F;

        <span class="comment">// 以下の2つの呼び出しでは、e (カリー化デリゲート)の方が圧倒的に高速</span>
        s(10);
        e(10);
    }
}
</code></pre>
<h3><a id="optimization-static">(最適化手法2) 匿名関数を拡張メソッドに置き換え</h3>
<p>ちょっとした変換処理などに対して、匿名関数を使うよりも拡張メソッドを挟んだ方が速くなることもあります。</p>
<p>単純な例として、あるインスタンスを返すだけのラムダ式を、
拡張メソッドに置き換えることで高速化してみましょう。
以下のように書けます。</p>
<pre class="source" title="拡張メソッドを介することでちょっと高速化する例">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// Func 越しに何かのインスタンスを取りたい</span>
    <span class="reserved">static</span> <span class="reserved">void</span> M(Func&lt;<span class="reserved">string</span>&gt; factory)
    {
        Console.WriteLine(factory());
    }

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// でも、呼ぶ側としては単に何かインスタンスを1個渡したいだけ</span>
        <span class="reserved">string</span> s = Console.ReadLine();

        <span class="comment">// そこで、ラムダ式で1段覆って、string から Func&lt;string&gt; を作る</span>
        <span class="comment">// これだと、匿名関数の仕様から、匿名のクラスが作られて、その new のコストが余計にかかる</span>
        M(() =&gt; s);

        <span class="comment">// 一方で、以下のように、拡張メソッドを介することで、カリー化デリゲート(速い)になる</span>
        M(s.Identity);
    }
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">TrickyExtension</span>
{
    <span class="comment">// 素通しするだけの拡張メソッドを用意</span>
    <span class="reserved">public</span> <span class="reserved">static</span> T Identity&lt;<span class="type">T</span>&gt;(<span class="reserved">this</span> T x) =&gt; x;
}
</code></pre>
<p>この例の「素通し」よりもう少し複雑な場合でも同様です。
いくつか例を挙げると、以下のような場合にも同様の手法が使えます。</p>
<ul>
<li><a href="https://gist.github.com/ufcpp/c6bca9e382c579b25f618bf9befbefae#file-stringgetlength-cs">文字列から<code>Length</code>を抜き出す<code>Func&lt;string, int&gt;</code>を作る</a></li>
<li><a href="https://gist.github.com/ufcpp/c6bca9e382c579b25f618bf9befbefae#file-makeprimitivecovariant-cs"><code>Func&lt;int&gt;</code>から<code>Func&lt;long&gt;</code>を作る</a></li>
<li><a href="https://gist.github.com/ufcpp/c6bca9e382c579b25f618bf9befbefae#file-makeprimitivecontravariant-cs"><code>Action&lt;long&gt;</code>から<code>Action&lt;int&gt;</code>を作る</a></li>
<li><a href="https://gist.github.com/ufcpp/9e476a8a4bfaf04e3e1256bedfd83881">自作の型でも、引数の型違いの<code>Action</code>の変換</a></li>
</ul>
<p>匿名関数(特にラムダ式)と比べるとはるかに手間がかかる書き方なので使い勝手はかなり悪いですが、
よっぽど「速度最優先」な場合には有効です。</p>
 ]]></description>
				<pubDate>Sun, 03 Dec 2017 17:17:26 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] インライン化</title>
				<link>http://www.ufcpp.net/study/csharp/structured/miscinlining/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p><a href="/study/csharp/st_function.html">前述</a>の通り、関数によって「同じ処理を何度も繰り返し書かない」、「意味のある単位で明確な名前を付ける」ということができ、プログラムを読みやすく・書きやすくすることができます。</p>
<p>一方で、ここでは、プログラムのパフォーマンスの面から関数を見てみましょう。関数呼び出しには多少のコストが掛かります。このコストをなくすため、コンパイラーによってインライン化という最適化が行われます。</p>
<h2><a id="invoke-cost">関数呼び出しのコスト</h2>
<p>読みやすさ・書きやすさの面は抜きにして、関数のパフォーマンス面だけを考えてみます。</p>
<p><img src="/media/1152/functioncall.png" alt="関数呼び出しのパフォーマンス上のメリット・コスト" /></p>
<p>まずメリットですが、関数化によって重複コードが消えることで、プログラム全体のサイズが小さくなります。
サイズの減少量にもよりますが、基本的には小さい方が、プログラム自身の読み込み速度などの面で、実行速度的にもメリットになります。</p>
<p>一方で、関数化することで、関数の呼び出しや戻り時のジャンプにコストが掛かります。
また、共通化した結果、処理の前後を見ての最適化はかけづらくなります。</p>
<p>特に、関数の中身が小さい時には、コードの共通化によってサイズが減るメリットがほとんどなく、
ただ単にコストが掛かるだけになってしまいます。</p>
<h2><a id="inlining">インライン化</h2>
<p>関数化にはコストが掛かるといっても、
パフォーマンス改善のために、関数化すべきところをわざわざ手作業でコピペ展開する必要はありません。
コンパイラーが自動的に最適化してくれます。</p>
<p>すなわち、「展開する方が確実に良い」と判定できる関数に対しては、関数の中身を呼び出しカ所に、コンパイラーが自動的に展開します。
この処理を<strong id="key-inlining" class="keyword">インライン化</strong>(inlining: in-lineに埋め込む)やインライン展開(inline expansion)と呼びます。</p>
<p><img src="/media/1153/inlining.png" alt="インライン化の例" /></p>
<h2><a id="dotnet-inlining">C# のインライン化</h2>
<p>C# の場合、C# コンパイラー自身はインライン化を全くしません。
.NET ランタイムが<a href="/study/il/">IL</a>を解釈する際にインライン化が行われます。
すなわち、インライン化が掛かるタイミングは<a href="/study/csharp/framework/fwjitcompilation/#jit-compilation">JITコンパイル</a>時です。</p>
<p>実際にインライン化が掛かるかどうかはランタイムの実装依存で、仕様としては決まっていません。
現在インライン化が掛からない場合であっても、将来的には掛かるようになる可能性もあります。
公式にドキュメントがあるわけでもないのですが、非公式なブログ等の情報によると、以下のような判定を行うそうです。</p>
<ul>
<li>C# コンパイル結果の IL 命令が32バイトを超える場合、インライン化しない</li>
<li><a href="/study/csharp/st_loop.html">反復処理</a>を含む場合、インライン化しない</li>
<li><a href="/study/csharp/oo_exception.html">例外処理</a>を含む場合、インライン化しない</li>
</ul>
<p>また、そもそも原理的にインライン化できない場合もあります。通常、<a href="/study/csharp/oo_polymorphism.html#virtual">仮想呼び出し</a>になっている関数をはインライン化できません。
その結果、<a href="/study/csharp/oo_interface.html">インターフェイス</a>や<a href="/study/csharp/sp_delegate.html">デリゲート</a>を介した関数呼び出しはインライン化できません。</p>
<p>.NET は、ある程度インライン化の有無を制御する手段も提供しています。
以下のように、<code>MethodImpl</code><a href="/study/csharp/sp_attribute.html">属性</a>(<code>System.Runtime.CompilerServices</code><a href="/study/csharp/sp_namespace.html">名前空間</a>)を付けます。</p>
<pre class="source" title="インライン化に関する属性">
<code><span class="comment">// 積極的にインライン化してもらいたい</span>
[<span class="type">MethodImpl</span>(<span class="type">MethodImplOptions</span>.AggressiveInlining)]
<span class="reserved">static</span> <span class="reserved">int</span> SumAgressive(<span class="reserved">int</span>[] a)
{
    <span class="reserved">var</span> sum = 0;
    <span class="reserved">foreach</span> (var x <span class="reserved">in</span> a)
    {
        sum += x;
    }
    <span class="reserved">return</span> sum;
}

<span class="comment">// 全くインライン化させたくない</span>
[<span class="type">MethodImpl</span>(<span class="type">MethodImplOptions</span>.NoInlining)]
<span class="reserved">static</span> <span class="reserved">int</span> SumNo(<span class="reserved">int</span>[] a)
{
    <span class="reserved">var</span> sum = 0;
    <span class="reserved">foreach</span> (var x <span class="reserved">in</span> a)
    {
        sum += x;
    }
    <span class="reserved">return</span> sum;
}
</code></pre>
<p><code>AggressiveInlining</code>が付いている場合、前述の「32バイト」「反復処理・例外処理を含む」という条件が緩和されます。
あくまで「緩和」であって、無条件にインライン化されるわけではありません。
この例の場合は、「<code>foreach</code>ループを含んではいるものの、関数の中身自体は十分に小さい」という条件なので、
何も属性を付けなければインライン化されず、<code>AggressiveInlining</code>を付けるとインライン化されます。</p>
<p>一方、<code>NoInlining</code>を付けると絶対にインライン化されなくなります。
わざわざ最適化を阻害するものなので、かなり特殊な用途でしか使わないでしょう。</p>
<h3><a id="inlining-perf">インライン化によるパフォーマンス改善</h3>
<p>このインライン化の有無によってどの程度性能が変わるかを見てみましょう。
以下に、計測用のコードを示します。</p>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/blob/master/Chapters/StructuredProgramming/Inlining/SimpleAdd.cs">単純な加算</a></li>
<li><a href="https://github.com/ufcpp/UfcppSample/blob/master/Chapters/StructuredProgramming/Inlining/WithLoop.cs">単純な反復処理</a></li>
</ul>
<p>どちらもかなり関数の中身が小さいものなので、インライン化の有無が顕著に効いてきます。
単純な加算の方に至っては倍以上の速度差があります。</p>
<h3><a id="common-execution-path">頻出経路の最適化</h3>
<p>反復処理や例外処理でインライン化が阻害される性質を考えると、
阻害する部分だけを切り出してしまうことでプログラムを高速化できることがあります。</p>
<p>あくまで、以下のような限られた場面でしか使えないテクニックですし、高速化といっても数%程度のものではありますが、
実行速度が非常に重要になる場面では役立つでしょう。</p>
<ul>
<li>引数としてわたってくるものの頻度を予測できる</li>
<li>高頻度で中身が単純な経路と、低頻度で中身が複雑な経路に分かれている</li>
</ul>
<p>例えば以下のようなコードを見てみましょう。</p>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/blob/master/Chapters/StructuredProgramming/Inlining/CommonExecutionPath.cs">サンプル</a></li>
</ul>
<pre class="source" title="長さ1の時と2の時だけ特別扱いする総和">
<code><span class="reserved">static</span> <span class="reserved">int</span> Sum(<span class="reserved">int</span>[] a)
{
    <span class="comment">// ほとんどの場合、Length == 1 または 2 のところを通るという想定</span>
    <span class="reserved">if</span> (a.Length == 1) <span class="reserved">return</span> a[0];
    <span class="reserved">else</span> <span class="reserved">if</span> (a.Length == 2) <span class="reserved">return</span> a[0] + a[1];
    <span class="reserved">else</span> <span class="reserved">if</span> (a.Length &gt;= 3)
    {
        <span class="comment">// 反復がインライン化を阻害</span>
        <span class="reserved">var</span> sum = 0;
        <span class="reserved">foreach</span> (var x <span class="reserved">in</span> a)
        {
            sum += x;
        }
        <span class="reserved">return</span> sum;
    }

    <span class="comment">// 例外がインライン化を阻害</span>
    <span class="reserved">throw</span> <span class="reserved">new</span> IndexOutOfRangeException();
}
</code></pre>
<p>単に配列の総和を取るコードですが、
「ほとんどの場合長さ1か2の配列しか来ない」というような前提で、
その長さ1か2の場合を特別扱いしているものです。</p>
<p>この<code>Sum</code>メソッドは、反復処理と例外処理を含んでいるため、インライン化できません。
しかし、この反復処理と例外処理は、先ほどの前提から言うと、めったに通らない個所にあります。
そこで、以下のように書き換えます。</p>
<pre class="source" title="めったに通らないくせにインライン化を阻害している部分を外に追い出す">
<code><span class="reserved">static</span> <span class="reserved">int</span> OptimizedSum(<span class="reserved">int</span>[] a)
{
    <span class="comment">// ほとんどの場合、Length == 1 または 2 のところを通るという想定</span>
    <span class="reserved">if</span> (a.Length == 1) <span class="reserved">return</span> a[0];
    <span class="reserved">else</span> <span class="reserved">if</span> (a.Length == 2) <span class="reserved">return</span> a[0] + a[1];
    <span class="reserved">else</span> <span class="reserved">if</span> (a.Length &gt;= 3) <span class="reserved">return</span> LongSum(a);
    ThrowIndexOutOfRange();
    <span class="reserved">return</span> 0;
}

<span class="comment">// インライン化を阻害しているものを外に追い出す</span>
<span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">int</span> LongSum(<span class="reserved">int</span>[] a)
{
    <span class="reserved">var</span> sum = 0;
    <span class="reserved">foreach</span> (var x <span class="reserved">in</span> a)
    {
        sum += x;
    }
    <span class="reserved">return</span> sum;
}
<span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">void</span> ThrowIndexOutOfRange() =&gt; <span class="reserved">throw</span> <span class="reserved">new</span> IndexOutOfRangeException();
</code></pre>
<p>めったに通らないくせにインライン化を阻害していた<code>foreach</code>ループと例外の<code>throw</code>を外に追い出しています。
その結果、<code>OptimizedSum</code>メソッド自体にはインライン化が掛かるようになり、関数呼び出しのコストが消えます。
数%程度ですが、これで高速化します。</p>
 ]]></description>
				<pubDate>Sat, 25 Nov 2017 15:48:18 +0900</pubDate>
			</item>
			<item>
				<title>Span&lt;T&gt;構造体</title>
				<link>http://www.ufcpp.net/study/csharp/resource/span/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version7">Ver. 7.2</h5>
<p><code>Span&lt;T&gt;</code>構造体(<code>System</code>名前空間)は、span (区間、範囲)という名前通り、連続してデータが並んでいるもの(<a href="/study/csharp/st_array.html">配列</a>など)の一定範囲を読み書きするために使う型です。</p>
<p>この型によって、ファイルの読み書きや通信などの際の、生データの読み書きがやりやすくなります。
生データの読み書きを直接行うことは少ないでしょうが、通信ライブラリなどを利用することで間接的に<code>Span&lt;T&gt;</code>構造体のお世話になることはこれから多くなるでしょう。</p>
<p><code>Span&lt;T&gt;</code>構造体は、 .NET Core 2.1 からは標準で入ります。それ以前のバージョンや、.NET Framework では、<a href="https://www.nuget.org/packages/System.Memory/">System.Memory</a>パッケージを参照することで利用できます。</p>
<p>C# 7.2の新機能のうちいくつかは、この型を効率的に・安全に使うために入ったものです。
そこで、言語機能に先立って、この<code>Span&lt;T&gt;</code>構造体自体について説明しておきます。</p>
<h5 class="version version14">Ver. 14</h5>
<p>C# 14 では、<code>Span&lt;T&gt;</code> 構造体を言語構文的に特別扱いするようになって、より便利に使えるようになりました。
(C# 7.2 から C# 13 までの間、<code>Span&lt;T&gt;</code> 構造体はあくまでもあまたある普通の構造体の1つという扱いを脱していませんでした。)</p>
<p>こちらについては「<a href="#first-class-span">First-class Span</a>」で説明します。</p>
<h5>サンプル コード</h5>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Resource/Span">サンプル コード</a></li>
</ul>
<h2><a id="data-span">連続データの一定範囲の読み書き</h2>
<p>「一定範囲の読み書き」の説明に、まずは配列で例を示します。
例えば以下のような書き方で、配列の一部分だけの読み書きができます。</p>
<pre class="source" title="配列の一部分だけを読み書きする例">
<code><span class="comment">// 長さ 8 で配列作成</span>
<span class="comment">// C# の仕様で、全要素 0 で作られる</span>
<span class="reserved">var</span> array = <span class="reserved">new</span> <span class="reserved">int</span>[8];

<span class="comment">// 配列の、2番目(0 始まりなので3要素目)から、3要素分の範囲</span>
<span class="reserved">var</span> span = <span class="reserved">new</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;(array, 2, 3);

<span class="comment">// その範囲だけを 1 に上書き</span>
<span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; span.Length; i++)
{
    span[i] = 1;
}

<span class="comment">// ちゃんと、2, 3, 4 番目だけが 1 になってる</span>
<span class="reserved">foreach</span> (var x <span class="reserved">in</span> array)
{
    <span class="type">Console</span>.WriteLine(x); <span class="comment">// 0, 0, 1, 1, 1, 0, 0, 0</span>
}
</code></pre>
<p>このコードで、以下のような書き換えが発生します。</p>
<p><img src="/media/1148/span1.png" alt="配列の一部分だけを読み書きする例" /></p>
<p><code>Span&lt;T&gt;</code>構造体を作る部分は、以下のように、拡張メソッドでも書けます。</p>
<pre class="source" title="配列に対する拡張メソッドで Span を作る">
<code><span class="reserved">var</span> span = array.AsSpan().Slice(2, 3);
</code></pre>
<p>この<code>AsSpan</code>は、<code>System.SpanExtensions</code>クラスで定義されている拡張メソッドで、
配列全体を指す <code>Span&lt;T&gt;</code> を作るものです。
また、<code>Slice</code>メソッドは<code>Span&lt;T&gt;</code>構造体の、さらに一部分だけを抜き出すメソッドです。</p>
<p>ちなみに、読み書き両方可能な<code>Span&lt;T&gt;</code>に加えて、読み取り専用の<code>ReadOnlySpan&lt;T&gt;</code>構造体もあります。</p>
<pre class="source" title="読み取り専用の ReadOnlySpan">
<code><span class="comment">// 読み取り専用版</span>
<span class="type">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; r = span;
<span class="reserved">var</span> a = r[0]; <span class="comment">// 読み取りは OK</span>
r[0] = 1;     <span class="comment">// 書き込みは NG</span>
</code></pre>
<p>配列に限って言えば、「配列の一部分を指す型」として、昔から<code>ArraySegment&lt;T&gt;</code>構造体(<code>System</code>名前空間)がありました。
しかし、以下のような差があります。</p>
<ul>
<li><code>Span&lt;T&gt;</code>は、配列だけでなく、いろいろなものを指せる</li>
<li><code>Span&lt;T&gt;</code>の方が効率的で、読み書きがだいぶ速い</li>
</ul>
<h2><a id="various-data">いろいろなタイプのメモリ領域を指せる</h2>
<p><code>Span&lt;T&gt;</code>は、配列だけでなく、文字列、スタック上の領域、.NET 管理外のメモリ領域などいろいろな場所を指せます。
以下のような使い方ができます。</p>
<pre class="source" title="Span でいろいろな場所を指す">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.InteropServices;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// 配列</span>
        <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; array = <span class="reserved">new</span> <span class="reserved">int</span>[8].AsSpan().Slice(2, 3);

        <span class="comment">// 文字列</span>
        <span class="type">ReadOnlySpan</span>&lt;<span class="reserved">char</span>&gt; str = <span class="string">"abcdefgh"</span>.AsReadOnlySpan().Slice(2, 3);

        <span class="comment">// スタック領域</span>
        <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; stack = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[8];

        <span class="reserved">unsafe</span>
        {
            <span class="comment">// .NET 管理外メモリ</span>
            <span class="reserved">var</span> p = <span class="type">Marshal</span>.AllocHGlobal(<span class="reserved">sizeof</span>(<span class="reserved">int</span>) * 8);
            <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; unmanaged = <span class="reserved">new</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;((<span class="reserved">int</span>*)p, 8);

            <span class="comment">// 他の言語との相互運用</span>
            <span class="reserved">var</span> q = malloc((<span class="type">IntPtr</span>)(<span class="reserved">sizeof</span>(<span class="reserved">int</span>) * 8));
            <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; interop = <span class="reserved">new</span> <span class="type">Span</span>&lt;<span class="reserved">int</span>&gt;((<span class="reserved">int</span>*)q, 8);

            <span class="type">Marshal</span>.FreeHGlobal(p);
            free(q);
        }
    }

    [<span class="type">DllImport</span>(<span class="string">"msvcrt.dll"</span>, CallingConvention = CallingConvention.Cdecl)]
    <span class="reserved">static</span> <span class="reserved">extern</span> IntPtr malloc(IntPtr size);

    [<span class="type">DllImport</span>(<span class="string">"msvcrt.dll"</span>, CallingConvention = CallingConvention.Cdecl)]
    <span class="reserved">static</span> <span class="reserved">extern</span> <span class="reserved">void</span> free(IntPtr ptr);
}
</code></pre>
<h3><a id="by-reference">部分参照</h3>
<p><code>Span&lt;T&gt;</code>は、配列や文字列の一部分を直接参照しています。</p>
<p>例えば、<code>string</code>の<code>Substring</code>メソッドを使うと、部分文字列をコピーした新しい別の<code>string</code>が生成されて、ちょっと非効率です。
これに対して、<code>Span&lt;char&gt;</code>と<code>Slice</code>を使えば、コピーなしで部分文字列を参照できます。</p>
<p>例えば以下のようなコードを書いたとします。</p>
<pre class="source" title="部分文字列の取り出し">
<code><span class="reserved">var</span> s = <span class="string">"abcあいう亜以宇"</span>;

<span class="reserved">var</span> sub = s.Substring(3, 3);
<span class="reserved">var</span> span = s.AsReadOnlySpan().Slice(3, 3);

<span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 3; i++)
{
    <span class="type">Console</span>.WriteLine((sub[i], span[i])); <span class="comment">// あ、い、う が2つずつ表示される</span>
}
</code></pre>
<p><code>sub</code> (<code>Substring</code>メソッドを利用)と<code>span</code> (<code>Slice</code>メソッドを利用)はいずれも、「3番目から3つ分」の部分文字列を取り出しています。
しかし、以下のように、<code>sub</code>ではコピーが発生し、<code>span</code>では発生しません。</p>
<p><img src="/media/1149/span2.png" alt="Substring と Span の差" /></p>
<h3><a id="pointer-and-array">配列とポインターに両対応</h3>
<p><code>Span&lt;T&gt;</code>を使う利点は、配列とポインターの両方に、1つの型で対応できることです。</p>
<p><a href="http://ufcpp.net/study/csharp/sp_pinvoke.html">ネイティブ コードとの相互運用</a>で有用なのはもちろん、
C# だけでプログラムを作るにしてもポインターを使いたいことが稀にあります
(主に、パフォーマンスが非常に重要になる場面で)。</p>
<p>例えば以下のようなコードを考えます。
<a href="/study/csharp/sp_unsafe.html">unsafe</a> を使うと速い処理の典型例として、一定範囲を 0 クリアする処理を、ポインターを使って書いています。</p>
<pre class="source" title="unsafe を使うと速い処理の典型例">
<code><span class="comment">// unsafe を使うと速い処理の典型例として、一定範囲を 0 クリアする処理</span>
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// 作る側</span>
    <span class="comment">// ライブラリを作る側としては別に unsafe コードがあっても不都合はそこまでない</span>
    <span class="reserved">static</span> <span class="reserved">unsafe</span> <span class="reserved">void</span> Clear(<span class="reserved">byte</span>* p, <span class="reserved">int</span> length)
    {
        <span class="reserved">var</span> last = p + length;
        <span class="reserved">while</span> (p + 7 &lt; last)
        {
            *(<span class="reserved">ulong</span>*)p = 0;
            p += 8;
        }
        <span class="reserved">if</span> (p + 3 &lt; last)
        {
            *(<span class="reserved">uint</span>*)p = 0;
            p += 4;
        }
        <span class="reserved">while</span> (p &lt; last)
        {
            *p = 0;
            ++p;
        }
    }

    <span class="comment">// 使う側</span>
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> array = <span class="reserved">new</span> <span class="reserved">byte</span>[256];

        <span class="comment">// array をいろいろ書き換えた後、全要素 0 にクリアしたいとして</span>

        <span class="comment">// ライブラリを使う側に unsafe が必要なのは怖いし面倒</span>
        <span class="reserved">unsafe</span>
        {
            <span class="reserved">fixed</span> (<span class="reserved">byte</span>* p = array)
                Clear(p, array.Length);
        }
    }
}
</code></pre>
<p>コード中にも書いていますが、ここで問題になるのは、使う側に unsafe コードを強要する点です。
ライブラリを作る側は作る人の責任で多少危険なコードも書けますが、
どういう人が使うかはコントロールできないので、使う側に unsafe を求めるのはつらいです。
また、見ての通り、<code>unsafe</code>や<code>fixed</code>などのブロックで囲う処理は面倒です。</p>
<p>そこで、通常、以下のようにいくつかのオーバーロードを増やすことになります。</p>
<pre class="source" title="unsafe を避けるためのオーバーロードいろいろ">
<code><span class="comment">// 使う側に unsafe を求めないために要するオーバーロードいろいろ</span>
<span class="reserved">static</span> <span class="reserved">void</span> Clear(<span class="type">ArraySegment</span>&lt;<span class="reserved">byte</span>&gt; segment) =&gt; Clear(segment.Array, segment.Offset, segment.Count);
<span class="reserved">static</span> <span class="reserved">void</span> Clear(<span class="reserved">byte</span>[] array, <span class="reserved">int</span> offset = 0) =&gt; Clear(array, offset, array.Length - offset);
<span class="reserved">static</span> <span class="reserved">void</span> Clear(<span class="reserved">byte</span>[] array, <span class="reserved">int</span> offset, <span class="reserved">int</span> length)
{
    <span class="reserved">unsafe</span>
    {
        <span class="reserved">fixed</span> (<span class="reserved">byte</span>* p = array)
        {
            Clear(p + offset, length);
        }
    }
}
</code></pre>
<p>1セットくらいなら別にまだ平気なんですが、例えばコピー処理(コピー元とコピー先の2セット必要)とか、引数が増えるとかなり大変なことになります。</p>
<pre class="source" title="コピー元とコピー先の2つになることで面倒になる例">
<code><span class="comment">// Clear は1つしか引数がないのでまだマシ。</span>
<span class="comment">// コピー(コピー元とコピー先)とか、2つになるとだいぶ面倒に。</span>

<span class="reserved">static</span> <span class="reserved">void</span> Copy(<span class="type">ArraySegment</span>&lt;<span class="reserved">byte</span>&gt; source, <span class="type">ArraySegment</span>&lt;<span class="reserved">byte</span>&gt; destination)
    =&gt; Copy(source.Array, source.Offset, destination.Array, destination.Offset, source.Count);
<span class="reserved">static</span> <span class="reserved">void</span> Copy(<span class="reserved">byte</span>[] source, <span class="reserved">int</span> sourceOffset, <span class="reserved">byte</span>[] destination, <span class="reserved">int</span> destinationOffset)
    =&gt; Copy(source, sourceOffset, destination, destinationOffset, source.Length - sourceOffset);
<span class="reserved">static</span> <span class="reserved">void</span> Copy(<span class="reserved">byte</span>[] source, <span class="reserved">int</span> sourceOffset, <span class="reserved">byte</span>[] destination, <span class="reserved">int</span> destinationOffset, <span class="reserved">int</span> length)
{
    <span class="reserved">unsafe</span>
    {
        <span class="reserved">fixed</span> (<span class="reserved">byte</span>* s = source)
        <span class="reserved">fixed</span> (<span class="reserved">byte</span>* d = destination)
        {
            Copy(s + sourceOffset, d + destinationOffset, length);
        }
    }
}
<span class="comment">// 他にも、利便性を求めるなら、</span>
<span class="comment">// source, destination の片方だけが ArraySegment のパターンとか</span>
<span class="comment">// 片方だけがポインターのパターンとか(組み合わせなのでパターンが多くなる)</span>

<span class="reserved">static</span> <span class="reserved">unsafe</span> <span class="reserved">void</span> <span class="method">Copy</span>(<span class="reserved">byte</span>* <span class="variable">source</span>, <span class="reserved">byte</span>* <span class="variable">destination</span>, <span class="reserved">int</span> <span class="variable">length</span>)
{
    <span class="reserved">var</span> <span class="variable">last</span> = <span class="variable">source</span> + <span class="variable">length</span>;
    <span class="control">while</span> (<span class="variable">source</span> + 7 &lt; <span class="variable">last</span>)
    {
        *(<span class="reserved">ulong</span>*)<span class="variable">destination</span> = *(<span class="reserved">ulong</span>*)<span class="variable">source</span>;
        <span class="variable">source</span> += 8;
        <span class="variable">destination</span> += 8;
    }
    <span class="control">if</span> (<span class="variable">source</span> + 3 &lt; <span class="variable">last</span>)
    {
        *(<span class="reserved">uint</span>*)<span class="variable">destination</span> = *(<span class="reserved">uint</span>*)<span class="variable">source</span>;
        <span class="variable">source</span> += 4;
        <span class="variable">destination</span> += 4;
    }
    <span class="control">while</span> (<span class="variable">source</span> &lt; <span class="variable">last</span>)
    {
        *<span class="variable">destination</span> = *<span class="variable">source</span>;
        ++<span class="variable">source</span>;
        ++<span class="variable">destination</span>;
    }
}
</code></pre>
<p>この問題に対して、<code>Span&lt;T&gt;</code>であれば、この構造体1つで配列でもポインターでも、その全体でも一部分でも受け取れるので、
オーバーロードは1つで十分です。</p>
<pre class="source" title="Spanを使ってオーバーロードを減らす">
<code><span class="comment">// 作る側</span>
<span class="comment">// Span&lt;T&gt; なら配列でもポインターでも、その全体でも一部分でも受け取れる</span>
<span class="reserved">static</span> <span class="reserved">void</span> Clear(<span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; span)
{
    <span class="reserved">unsafe</span>
    {
        <span class="comment">// 結局内部的には unsafe にしてポインターを使った方が速い場合あり</span>
        <span class="reserved">fixed</span> (<span class="reserved">byte</span>* pin = &amp;span.GetPinnableReference())
        <span class="comment">// 注: C# 7.3 からは以下の書き方ができる</span>
        <span class="comment">// fixed (byte* pin = span)</span>
        {
            <span class="reserved">var</span> p = pin;
            <span class="reserved">var</span> last = p + span.Length;
            <span class="reserved">while</span> (p + 7 &lt; last)
            {
                *(<span class="reserved">ulong</span>*)p = 0;
                p += 8;
            }
            <span class="reserved">if</span> (p + 3 &lt; last)
            {
                *(<span class="reserved">uint</span>*)p = 0;
                p += 4;
            }
            <span class="reserved">while</span> (p &lt; last)
            {
                *p = 0;
                ++p;
            }
        }
    }
}

<span class="comment">// 使う側</span>
<span class="reserved">static</span> <span class="reserved">void</span> Main()
{
    <span class="reserved">var</span> array = <span class="reserved">new</span> <span class="reserved">byte</span>[256];

    <span class="comment">// array をいろいろ書き換えた後、全要素 0 にクリアしたいとして</span>

    <span class="comment">// 呼ぶのがだいぶ楽</span>
    Clear(array);
}
</code></pre>
<h3><a id="safe-stackalloc">安全な stackalloc</h3>
<p>C# の速度最適化のコツの1つに、「<a href="/study/csharp/rm_gc.html#garbage-collection">ガベージ コレクション</a>を避ける」というのがあります。
要は、可能であれば、クラスや配列の <code>new</code> を避けろという話になります。
(割かし「言うは易し」で、なかなか<code>new</code>を避けるのが大変なことはよくありますが。)</p>
<p>例えば、ファイルからデータを読み出しつつ、何か処理をしたいとします。
データは一気に全体を見る必要はなく、一定サイズずつ(仮にここでは128バイトずつ)読んでは捨ててを繰り返せるものとします。
これまでであれば、以下のように、そのサイズ分の配列を <code>new</code> して使うことになります。</p>
<pre class="source" title="読み出し用の一時配列を new する例">
<code><span class="reserved">const</span> <span class="reserved">int</span> BufferSize = 128;

<span class="reserved">using</span> (<span class="reserved">var</span> f = <span class="type">File</span>.OpenRead(<span class="string">"test.data"</span>))
{
    <span class="reserved">var</span> rest = (<span class="reserved">int</span>)f.Length;
    <span class="reserved">var</span> buffer = <span class="reserved">new</span> <span class="reserved">byte</span>[BufferSize];

    <span class="reserved">while</span> (<span class="reserved">true</span>)
    {
        <span class="reserved">var</span> read = f.Read(buffer, 0, Math.Min(rest, BufferSize));
        rest -= read;

        <span class="comment">// buffer に対して何か処理する</span>

        <span class="reserved">if</span> (rest == 0) <span class="reserved">break</span>;
    }
}
</code></pre>
<p>こういう場合に、これまでも、unsafe コードを使えば配列の <code>new</code> を避ける手段がありました。
<a href="/study/csharp/sp_unsafe.html#stackalloc"><code>stackalloc</code></a>というものを使って、スタック上に一時領域を確保できます。
(スタックはガベージ コレクションの負担になりません。)
ただ、これだけのために unsafe コードを必要とするもの、ちょっとしんどいものがあります。</p>
<p>これに対して、C# 7.2では、<code>Span&lt;T&gt;</code>構造体と併用することで、unsafe なしで <code>stackalloc</code>を使えるようになりました。</p>
<p>例えば先ほどのコードは、以下のように書き直せます。
このコードはunsafeなしでコンパイルできます。
(※ .NET Core 2.1 で実行するか、他の環境では最新の <a href="https://www.nuget.org/packages/System.IO/">System.IO パッケージ</a>の参照が必要です。現状ではプレビュー版のみ。)</p>
<pre class="source" title="Span を使って一時バッファーを stackalloc に変更">
<code><span class="reserved">const</span> <span class="reserved">int</span> BufferSize = 128;

<span class="reserved">using</span> (<span class="reserved">var</span> f = <span class="type">File</span>.OpenRead(<span class="string">"test.data"</span>))
{
    <span class="reserved">var</span> rest = (<span class="reserved">int</span>)f.Length;
    <span class="comment">// Span&lt;byte&gt; で受け取ることで、new (配列)を stackalloc (スタック確保)に変更できる</span>
    <em><span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; buffer = <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[BufferSize];</em>

    <span class="reserved">while</span> (<span class="reserved">true</span>)
    {
        <span class="comment">// Read(Span&lt;byte&gt;) が追加された</span>
        <span class="reserved">var</span> read = f.Read(buffer);
        rest -= read;
        <span class="reserved">if</span> (rest == 0) <span class="reserved">break</span>;

        <span class="comment">// buffer に対して何か処理する</span>
    }
}
</code></pre>
<p>ただし、<code>Span&lt;T&gt;</code>相手であっても、<code>stackalloc</code>が使える型は<a href="/study/csharp/sp_unsafe.html#unmanaged-types">アンマネージ型</a>に限られます。
クラスなどに対しては使えません。</p>
<pre class="source" title="">
<code><span class="comment">// これはOK。</span>
<span class="type">Span</span>&lt;<span class="reserved">int</span>&gt; i = <span class="reserved">stackalloc</span> <span class="reserved">int</span>[4];

<span class="comment">// こっちはダメ。</span>
<span class="comment">// Span&lt;string&gt; は大丈夫だけど、stackalloc string はダメ。</span>
<span class="type">Span</span>&lt;<span class="reserved">string</span>&gt; s = <span class="reserved">stackalloc</span> <span class="reserved"><span class="error">string</span></span>[4];
</code></pre>
<p>ちなみに、スタック上の領域確保は、あんまり大きなサイズにはできません。
一般的には、多くても数キロバイト程度くらいまでしか使いません。
そのため、確保したいバッファーのサイズに応じて、<code>stackalloc</code>と配列の<code>new</code>を切り替えたいと言ったこともあります。
そこでC# 7.2 では、以下のように、条件演算子で<code>stackalloc</code>を使うこともできるようになっています。</p>
<pre class="source" title="条件 stackalloc">
<code><span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; buffer = bufferSize &lt;= 128 ? <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[bufferSize] : <span class="reserved">new</span> <span class="reserved">byte</span>[bufferSize];
</code></pre>
<p>また、unsafeが不要なことからもわかる通り、<code>Span&lt;T&gt;</code>との併用であれば<code>stackalloc</code>は安全です。
以下のように、範囲チェックが掛かって、確保した分を越えての読み書きはできないようになっています。</p>
<pre class="source" title="Span + stackalloc は安全">
<code><span class="comment">// Span 版 = safe</span>
<span class="reserved">static</span> <span class="reserved">void</span> Safe()
{
    <span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; span = <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[8];

    <span class="reserved">try</span>
    {
        <span class="comment">// 8バイトしか確保していないのに、9要素目に書き込み</span>
        span[8] = 1;
    }
    <span class="reserved">catch</span>(IndexOutOfRangeException)
    {
        <span class="comment">// ちゃんと例外が発生してここに来る</span>
        Console.WriteLine(<span class="string">"span[8] はダメ"</span>);
    }
}

<span class="comment">// ポインター版 = unsafe</span>
<span class="reserved">static</span> <span class="reserved">unsafe</span> <span class="reserved">void</span> Unsafe()
{
    <span class="reserved">byte</span>* p = <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[8];

    <span class="reserved">try</span>
    {
        <span class="comment">// 8バイトしか確保していないのに、9要素目に書き込み</span>
        p[8] = 1;
    }
    <span class="reserved">catch</span> (Exception)
    {
        <span class="comment">// ここには来ない！</span>
        <span class="comment">// 結果、不正な場所に 1 が書き込まれてるはず(かなり危険)</span>
        <span class="comment">// それも、エラーを拾う手段がないので気づきにくい</span>
        <span class="reserved">throw</span>;
    }
}
</code></pre>
<h3><a id="nested-stackalloc">式中の stackalloc</h3>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 で、式中の任意の場所に <code>stackalloc</code> を書けるようになりました。
例えば以下のような書き方ができます。</p>
<pre class="source" title="式中の任意の場所に stackalloc">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// Span を受け取る適当なメソッドを用意。</span>
    <span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">buf</span>) =&gt; 0;
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">len</span>)
    {
        <span class="comment">// if の条件式中</span>
        <span class="control">if</span> (<span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1] <span class="method">==</span> <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1]) ;
        <span class="method">M</span>(<span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1]);
 
        <span class="comment">// でもこれが今まではダメだった。</span>
        <span class="comment">// C# 8.0 ではコンパイルできる。</span>
        <span class="method">M</span>(<span class="variable">len</span> &gt; 512 ? <span class="reserved">new</span> <span class="reserved">byte</span>[<span class="variable">len</span>] : <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[<span class="variable">len</span>]);
 
        <span class="comment">// こういう書き方は C# 8.0 以前からできてた。条件演算子だけ特別扱いしてたらしい。</span>
        <span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt; <span class="variable">buf</span> = <span class="variable">len</span> &gt; 512 ? <span class="reserved">new</span> <span class="reserved">byte</span>[<span class="variable">len</span>] : <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[<span class="variable">len</span>];
    }
 
    <span class="comment">// フィールド初期化子の中でも書ける。</span>
    <span class="reserved">int</span> a = <span class="method">M</span>(<span class="reserved">stackalloc</span> <span class="reserved">byte</span>[8]);
 
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> <span class="method">MAsync</span>()
    {
        <span class="comment">// こういう入れ子の stackalloc の場合、非同期メソッド中でも書ける。</span>
        <span class="method">M</span>(<span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1]);
 
        <span class="reserved">await</span> <span class="type">Task</span>.<span class="method">Yield</span>();
 
        {
            <span class="comment">// これは C# 8.0 でもダメ。</span>
            <span class="comment">// { } でくくってて(await をまたがない状態)もダメ。</span>
            <span class="error"><span class="type">Span</span>&lt;<span class="reserved">byte</span>&gt;</span> <span class="variable">buf</span> = <span class="reserved">stackalloc</span> <span class="reserved">byte</span>[1];
        }
    }
}
</code></pre>
<p>ただし、対象の型が <code>Span&lt;T&gt;</code> である必要があります。
ポインターに対する <code>stackalloc</code> にはこれまで通り <code>T* p = stackalloc T[len]</code> の形でしか書けません。</p>
<p><code>Span&lt;T&gt; span = stackalloc T[len]</code> なら元々書けたので、
それと区別して「入れ子コンテキストでの <code>stackalloc</code>」(<code>stackalloc</code> in nested context)と言ったりします。</p>
<p>C# 7.3 時点でも、条件演算子の中でだけは <code>stackalloc</code> を書けましたが、
これは条件演算子だけ特別扱いしていたみたいです。
それに対して、C# 8.0 では本当にどこにでもかけます。</p>
<p>どうも、<a href="/study/csharp/datatype/patterns/?p=2#recursive">再帰パターン</a>を実装するついでにこの機能が入ったそうです。
(再帰パターン中に<a href="/study/csharp/sp_ref.html?p=2#ref-returns">参照</a>や<a href="/study/csharp/resource/refstruct/"><code>ref</code>構造体</a>が出てきても、戻り値に返していいものかどうかをちゃんと解析しないとまずくて、それが解析できるんなら<code>stackalloc</code>の安全性も解析できるとのこと。)</p>
<h2><a id="span-internal">Span の内部的な話</h2>
<p>前節では<code>Span&lt;T&gt;</code>構造体の用途を見てきましたが、続いて、その中身がどうなっているかについて説明しておきます。</p>
<p><code>ArraySegment&lt;T&gt;</code>よりも<code>Span&lt;T&gt;</code>の方が高速な理由でもありますが、
<code>Span&lt;T&gt;</code>の中身は参照になっています。</p>
<p>比較のために<code>ArraySegment&lt;T&gt;</code>の中身から説明しましょう。
<code>ArraySegment&lt;T&gt;</code>は以下のようなメンバーを持った構造体です。</p>
<pre class="source" title="ArraySegment の中身">
<code><span class="reserved">struct</span> <span class="type">ArraySegment</span>&lt;<span class="type">T</span>&gt;
{
    <span class="type">T</span>[] Array;
    <span class="reserved">int</span> Offset;
    <span class="reserved">int</span> Count;
}
</code></pre>
<p><img src="/media/1150/arraysegmentinternal.png" alt="ArraySegmentの中身" /></p>
<p>一方で、<code>Span&lt;T&gt;</code>構造体は、論理的には以下のようなメンバーを持った構造体です。
(「論理的には」と断っているのは、これをそのまま書くことはできないため。)</p>
<pre class="source" title="Spanの中身(疑似コード。これをそのままは書けない)">
<code><span class="reserved">struct</span> <span class="type">Span</span>&lt;<span class="type">T</span>&gt;
{
    <span class="reserved">ref</span> <span class="type">T</span> Reference;
    <span class="reserved">int</span> Length;
}
</code></pre>
<p><img src="/media/1151/spaninternal.png" alt="Spanの中身" /></p>
<p>要するに、以下のような点が <code>Span&lt;T&gt;</code> の特徴になります。
(この他、<code>Span&lt;T&gt;</code>は .NET ランタイムが特別扱いしていくつか特殊な最適化を掛けてくれるため高速になります。)</p>
<ul>
<li>必要な範囲の先頭を直接参照しているので、<code>+ Offset</code>分の計算が省ける</li>
<li><code>Array</code>と<code>Offset</code>と分けて持つ必要がないので、1メンバー分省サイズ</li>
<li>配列に限らずどこでも(ポインターでも)参照できる</li>
</ul>
<h3><a id="two-implementations">slow Span と fast Span</h3>
<p>先ほど、<code>Span&lt;T&gt;</code>の中身には「論理的には」<code>ref T</code>なフィールドがあるという話をしました。
ただ、 .NET の型システム上、フィールドに <code>ref</code> を付けることはできませんでした(.NET 6 以前)。
実のところ、<code>Span&lt;T&gt;</code>はこういう「参照フィールド」を実現するためにちょっと特殊なことをしていました。</p>
<h4><a id="fast-span">fast Span (.NET Core 2.1 以降向けの Span<T>)</h4>
<p>.NET Core 2.1 では、ランタイム側で特殊処理を入れて、「参照フィールド」に相当する機能を使えるようにしました。
.NET Core 2.1 以降向けの <code>Span&lt;T&gt;</code> は以下のような構造になっています。
(<a href="https://github.com/dotnet/coreclr/blob/aae414026671e3dc1ccf0f308d351ac04cc746a4/src/mscorlib/shared/System/Span.cs#L29">coreclr レポジトリ内にソースコードがあります</a>。)</p>
<pre class="source" title="fast Span の中身">
<code><span class="reserved">struct</span> <span class="type">Span</span>&lt;<span class="type">T</span>&gt;
{
    <span class="type">ByReference</span>&lt;<span class="type">T</span>&gt; _pointer;
    <span class="reserved">int</span> _length;
}
</code></pre>
<p><code>ByReference&lt;T&gt;</code> が特殊対応部分です。
ランタイム側で「この型は参照フィールドとして扱う」という特別扱いをすることで、所望の動作を得ています。</p>
<h4><a id="fast-span7">.NET 7 以降の fast Span</h4>
<p>.NET 7 / C# 11 で、晴れて <a href="https://ufcpp.net/study/csharp/resource/refstruct/#ref-field">ref フィールド</a>を持てるようになりました。
その結果、<code>Span&lt;T&gt;</code> は「普通の」ref 構造体になりました。
おおむね以下のような内容の構造体です。</p>
<pre class="source" title=".NET 7 以降の Span 構造体">
<span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type struct">Span</span>&lt;<span class="type param">T</span>&gt;
{
    <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="type param">T</span> <span class="field">_reference</span>;
    <span class="reserved">readonly</span> <span class="reserved">int</span> <span class="field">_length</span>;
}
</pre>
<h4><a id="slow-span">slow Span (旧来のランタイム向けの Span<T>)</h4>
<p>「.NET Core 2.1以降でしか使えません」ということになると使い勝手が悪すぎるため、
旧来のランタイム向けの「ちょっと遅い」<code>Span&lt;T&gt;</code>実装もあります。
(こちらは<a href="https://github.com/dotnet/corefx/blob/8d212b41126baff94fc025e4438d6f4e8cbff7e9/src/System.Memory/src/System/Span.cs#L448">corefx リポジトリ内にソースコードがあります</a>。)</p>
<p>こちらは、概ね以下のような構造です。</p>
<pre class="source" title="slow Span の中身">
<code><span class="reserved">struct</span> <span class="type">Span</span>&lt;<span class="type">T</span>&gt;
{
    <span class="type">Pinnable</span>&lt;<span class="type">T</span>&gt; _pinnable;
    <span class="type">IntPtr</span> _byteOffset;
    <span class="reserved">int</span> _length;
}
</code></pre>
<p><code>Pinnable&lt;T&gt;</code>はただのクラスです。
ガベージ コレクション管理下の参照と、管理外の参照を同列に扱えないからこういう構造になっています。
管理メモリ(配列)は <code>_pinnable</code> (ただのクラス)で扱い、管理外メモリ(相互運用で得たポインターや<code>stackalloc</code>で確保したメモリ)は <code>_byteOffset</code> に直接ポインター値を入れて扱います。</p>
<p>結果的に、管理下/管理外で条件分岐が必要だったり、構造体のサイズが大きくなるせいで、少し動作が遅くなります。
ただし、それでも、<code>ArraySegment&lt;T&gt;</code>を使うよりはだいぶ高速です。</p>
<h3><a id="ref-fields">参照フィールド</h3>
<p>要するに、<code>Span&lt;T&gt;</code>構造体は、論理的には「参照フィールドと、長さのペア」です。
実際、「fast Span」な実装では、参照フィールドに相当するものを、ランタイム側の特殊対応で実現しています。</p>
<p>となると、<code>Span&lt;T&gt;</code>の取り扱いには少し注意が必要になります。
「<a href="http://ufcpp.net/study/csharp/sp_ref.html?p=2#ref-returns">参照戻り値と参照ローカル変数</a>」で説明していますが、
参照渡しでは、参照先が必ず有効であることを保証するために、いくつかの制限を掛けています。
それと同じ制限が<code>Span&lt;T&gt;</code>型の引数・変数・戻り値にも掛からなければいけません。</p>
<p>正確な条件などについては次節の「<a href="http://ufcpp.net/study/csharp/resource/refstruct/">ref 構造体</a>」で説明します。</p>
<h2><a id="first-class-span">First-class Span</a></h2>
<h5 class="version version14">Ver. 14</h5>
<p>C# 14 では <code>Span&lt;T&gt;</code>/<code>ReadOnlySpan&lt;T&gt;</code> 構造体を言語構文的に特別扱いするようなりました。</p>
<h3><a id="before-first-class-span">C# 13 までの問題</a></h3>
<p>C# 7.2 の頃に <code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> が導入されて以来、
これらの型を使った高パフォーマンスな実装がたくさん提供されています。</p>
<p>以前なら <code>IEnumerable&lt;T&gt;</code> インターフェイスなどを使って実装していたものを、
C# 7.2 以降は <code>ReadOnlySpan&lt;T&gt;</code> 構造体を使って実装することが増えました。
例えば以下のように、引数の型を <code>IEnumerable&lt;T&gt;</code> から <code>ReadOnlySpan&lt;T&gt;</code> に書き換えるだけで高速になるということが多々あります。</p>
<pre class="source" title="ReadOnlySpan 構造体を使うと高速になる">
<span class="reserved">class</span> <span class="type">Overloads</span>
{
    <span class="comment">// 昔からある伝統的な書き方。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>)
    {
        <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable local">values</span>)
        {
            <span class="comment">// 何か</span>
        }
    }

    <span class="comment">// C# 7.2 以降、全く同じ処理ならこっちの方が高速。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>)
    {
        <span class="control">foreach</span> (<span class="reserved">var</span> <span class="variable">x</span> <span class="control">in</span> <span class="variable local">values</span>)
        {
            <span class="comment">// 同じ何か</span>
        }
    }
}
</pre>
<p>.NET の標準ライブラリでは、例えば <a href="https://learn.microsoft.com/ja-jp/dotnet/api/system.string.join"><code>string.Join</code></a> メソッドなどがそうで、
.NET 9 (C# 13 世代)くらいで <code>ReadOnlySpan&lt;T&gt;</code> 引数のオーバーロードが追加されたものが多いです。</p>
<p>ただ、<code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> 構造体は使えない場面があったり、
そうでなくても既存のメソッドを消すわけにはいかない(使っているコードを壊す)ので、
両方のオーバーロードを残すことになります。
そうなると問題になるのがオーバーロード解決の優先順位で、
例えば配列 <code>T[]</code> に対してどちらが呼ばれるかが多少ややこしくなります。</p>
<p>C# 13 までは、<code>T[]</code> からの変換先としては <code>IEnumerable&lt;T&gt;</code> の方が優先順位が高かったり、
あるいは優劣が付かなくてオーバーロード解決ができなかったりで、
呼んでほしい(パフォーマンスが改善する) <code>ReadOnlySpan&lt;T&gt;</code> の方を呼ぶのが大変という問題がありました。</p>
<pre class="source" title="IEnumerable と ReadOnlySpan の解決ができなかった例(C# 14 で解決)">
<span class="reserved">int</span>[] <span class="variable">data</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="type">Overloads</span><span class="operator">.</span><span class="static"><span class="error" title="CS0121"><span class="method">M</span></span></span>(<span class="variable">data</span>); <span class="comment">// 呼び分けができなくてコンパイル エラー(C# 13 まで)。</span>
<span class="type">Overloads</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>(<span class="variable">data</span><span class="operator">.</span><span class="method">AsSpan</span>()); <span class="comment">// ReadOnlySpan&lt;int&gt; 版を呼びたければこう書く。</span>

<span class="reserved">class</span> <span class="type">Overloads</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>)
    {
        <span class="comment">// 何か</span>
    }

    <span class="comment">// こっちの方が高速。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>)
    {
        <span class="comment">// 同じ何か</span>
    }
}
</pre>
<p>ちなみに、<a href="https://ufcpp.net/study/csharp/datatype/collection-expression/#priority">C# 12 で入ったコレクション式</a>や、
<a href="https://ufcpp.net/study/csharp/sp_params.html#params-collections">C# 13 で入った <code>params</code> コレクション</a>では、
<code>T[]</code> や <code>IEnumerable&lt;T&gt;</code> よりも <code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> を優先的に選ぶように特別な処理が入っています。</p>
<pre class="source" title="コレクション式や params では ReadOnlySpan の優先度が高い">
<span class="comment">// int[] を経由すると解決不能になるものの、</span>
<span class="comment">// コレクション式や params を使った場合は ReadOnlySpan の優先度が高い扱い。</span>
<span class="type">Overloads</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]);
<span class="type">Overloads</span><span class="operator">.</span><span class="method"><span class="static">M</span></span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);

<span class="reserved">class</span> <span class="type">Overloads</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">params</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>)
    {
        <span class="comment">// 何か</span>
    }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">params</span> <span class="reserved">int</span>[] <span class="variable local">values</span>)
    {
        <span class="comment">// 同じ何か</span>
    }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">params</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>) <span class="comment">// これが最優先。</span>
    {
        <span class="comment">// 同じ何か</span>
    }
}
</pre>
<p>この例からもわかるように、今や <code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> が重要な地位を占めていて、
C# の言語構文上も徐々に特別扱いされるようになってい来ています。</p>
<h3><a id="after-first-class-span">C# 14 からの Span/ReadOnlySpan 特別扱い</a></h3>
<p>前節の不便は
あくまで <code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> が「ただの構造体」ということに起因します。
配列 <code>T[]</code> の変数を <code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> 型の変数/引数に渡せるのもあくまで
「<code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> 構造体に定義されたユーザー定義型変換」を経由しています。
C# 言語組み込みの型変換と比べて、ユーザー定義型変換は1段下扱いで、色々な不便があります。</p>
<p>この問題は、コレクション式の例からもわかる通り、
<code>Span&lt;T&gt;</code> や <code>ReadOnlySpan&lt;T&gt;</code> を言語組み込みにする(コンパイラーで特別扱いする)ことで解決します。
これを、「ただの構造体」扱いから「(<code>int</code> などと同列の)言語組み込みな型」扱いに格上げするという意味で、
「first-class (第一級、一流)化する」と言ったりします。</p>
<p>first-class になったことで、まず、
前述の <code>IEnumerable&lt;T&gt;</code> との呼び分けができない問題も、C# 14 にするだけで解消して、
<code>ReadOnlySpan&lt;T&gt;</code> 側が呼ばれるようになります。</p>
<pre class="source" title="C# 14 では ReadOnlySpan オーバーロードの優先度が上がった">
<span class="reserved">int</span>[] <span class="variable">data</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="type">Overloads</span><span class="operator">.</span><span class="static"><span class="method">M</span></span>(<span class="variable">data</span>); <span class="comment">// C# 14 であればエラーにならない。</span>

<span class="reserved">class</span> <span class="type">Overloads</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>) { }

    <span class="comment">// こっちの方が高速。</span>
    <span class="comment">// C# 14 からオーバーロード解決で優先されるようになった。</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>) { }
}
</pre>
<p><a href="https://ufcpp.net/study/csharp/sp3_extension.html">拡張メソッド</a>の場合はオーバーロード解決のルールがちょっと違うんですが、
「<code>ReadOnlySpan&lt;T&gt;</code> の方が有利なのに呼んでもらえなかった/呼べなかった」という問題はこちらにもありました。
これも、first-class 化したことで解決しています。
これまで、配列 <code>T[]</code> から <code>ReadOnlySpan&lt;T&gt;</code> への変換は
「ユーザー定義の変換なので拡張メソッドの解決に寄与しない」という扱いだったのが、
C# 14 からは「コンパイラーが保証している変換で、優先的に拡張メソッドの解決に使われる」という扱いになります。</p>
<pre class="source" title="拡張メソッドでも ReadOnlySpan が特別扱いされるように">
<span class="reserved">int</span>[] <span class="variable">data</span> <span class="operator">=</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];

<span class="comment">// C# 13 まで: IEnumerable の方が呼ばれる。</span>
<span class="comment">//             (というか ReadOnlySpan の方しかないとコンパイル エラーになる。)</span>
<span class="comment">// C# 14 から: ReadOnlySpan の方が呼ばれる。</span>
<span class="variable">data</span><span class="operator">.</span><span class="method">M</span>();

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">Extensions</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>(<span class="reserved">this</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">int</span>&gt; <span class="variable local">values</span>) { } <span class="comment">// こっちが高速なのでこっちを読んでほしい。</span>
}
</pre>
<h5><a id="covariance">ReadOnlySpan の共変性</a></h5>
<p>また、<a href="https://ufcpp.net/study/csharp/oo_operator.html#cast">ユーザー定義の型変換</a>では「型引数の<a href="https://ufcpp.net/study/csharp/sp4_variance.html#variance">共変性</a>」を表現できないという問題があります。
<code>ReadOnlySpan&lt;string&gt;</code> を <code>ReadOnlySpan&lt;object&gt;</code> に代入できてもいいはずなのに、
これが C# 13 まではできませんでした。
C# 14 からはこれを受け付けます。</p>
<pre class="source" title="ReadOnlySpan の共変性">
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">string</span>&gt; <span class="variable">s</span> <span class="operator">=</span> [];
<span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">object</span>&gt; <span class="variable">span</span> <span class="operator">=</span> <span class="variable">s</span>; <span class="comment">// C# 13 ではエラー。</span>
</pre>
<h5><a id="read-only-span-over-span">Span よりも ReadOnlySpan の方を優先</a></h5>
<p>ちなみに、<code>Span&lt;T&gt;</code> と <code>ReadOnlySpan&lt;T&gt;</code> の両方のオーバーロードがある場合、
<code>ReadOnlySpan&lt;T&gt;</code> の方が優先されます。</p>
<pre class="source" title="ReadOnlySpan 優先">
<span class="reserved">string</span>[] <span class="variable">s</span> <span class="operator">=</span> [];

<span class="comment">// ReadOnlySpan の方が優先。</span>
<span class="variable">s</span><span class="operator">.</span><span class="method">M</span>();

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type"><span class="static">Extensions</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">T</span>&gt;(<span class="reserved">this</span> <span class="type struct">Span</span>&lt;<span class="type param">T</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="method"><span class="static">M</span></span>&lt;<span class="type param">T</span>&gt;(<span class="reserved">this</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="type param">T</span>&gt; <span class="variable local">_</span>) { } <span class="comment">// こちらが呼ばれる。</span>
}
</pre>
<p>これはパフォーマンス(どちらが高速か)の問題ではなく、
こうしておかないとまた「<a href="https://ufcpp.net/blog/2022/11/covariantarrayincident/">配列の共変性の地雷</a>を踏むから」という理由だそうです。</p>
<pre class="source" title="配列の共変性は結構な地雷">
<span class="reserved">string</span>[] <span class="variable">s</span> <span class="operator">=</span> [];
<span class="reserved">object</span>[] <span class="variable">o</span> <span class="operator">=</span> <span class="variable">s</span>; <span class="comment">// C# の配列は共変(歴史的経緯)。</span>

<span class="comment">// Span を優先するとこれが例外を起こしちゃう。</span>
<span class="comment">// ReadOnlySpan&lt;object&gt; x = s; は合法。</span>
<span class="comment">// Span&lt;object&gt; x = s; は実行時例外。</span>
<span class="variable">o</span><span class="operator">.</span><span class="method">M</span>(); <span class="comment">// ReadOnlySpan&lt;object&gt; を優先しないとここで例外が出る。</span>

<span class="reserved">static</span> <span class="reserved">class</span> <span class="static"><span class="type">Ex</span></span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">this</span> <span class="type struct">Span</span>&lt;<span class="reserved">object</span>&gt; <span class="variable local">_</span>) { }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <span class="static"><span class="method">M</span></span>(<span class="reserved">this</span> <span class="type struct">ReadOnlySpan</span>&lt;<span class="reserved">object</span>&gt; <span class="variable local">_</span>) { }
}
</pre> ]]></description>
				<pubDate>Wed, 08 Nov 2017 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>構造体</title>
				<link>http://www.ufcpp.net/study/csharp/resource/rm_struct/</link>
				<description><![CDATA[ <p>クラスと構造体は、次節で説明する「<a href="http://ufcpp.net/study/csharp/oo_reference.html#valtype">値型</a>」か「<a href="http://ufcpp.net/study/csharp/oo_reference.html#reftype">参照型</a>」かの違いに起因します。構造体は値型で、そのためにクラスと比べていくつか用途に制限がかかります。</p>
<h2><a id="abstract">概要</h2>
<p>「<a href="http://ufcpp.net/study/csharp/st_struct.html">データの構造化</a>」で少し触れて以来、ずっとクラスだけを使って説明してきましたが、ここで、C#における「もう1つの複合型」である構造体について説明します。</p>
<p>根本的な差は、次項で説明する「<a href="http://ufcpp.net/study/csharp/oo_reference.html#valtype">値型</a>」か「<a href="http://ufcpp.net/study/csharp/oo_reference.html#reftype">参照型</a>」かの違いに起因します。構造体は値型で、そのためにクラスと比べていくつか用途に制限がかかります。</p>
<h2><a id="restriction">構造体の制限</h2>
<p>とりあえず、クラスと構造体を並べて書いてみましょう。</p>
<h4>構造体</h4>
<pre class="source" title="">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">SampleStruct</span> : <span class="type">InterfaceA</span>, <span class="type">InterfaceB</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> A { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> B { <span class="reserved">get</span>; }

    <span class="reserved">public</span> SampleStruct(<span class="reserved">int</span> a, <span class="reserved">int</span> b) { A = a; B = b; }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">SampleStruct</span> <span class="reserved">operator</span>-(<span class="type">SampleStruct</span> x)
        =&gt; <span class="reserved">new</span> <span class="type">SampleStruct</span>(-x.A, -x.B);
}

<span class="reserved">public</span> <span class="reserved">interface</span> <span class="type">InterfaceA</span> { <span class="reserved">int</span> A { <span class="reserved">get</span>; } }
<span class="reserved">public</span> <span class="reserved">interface</span> <span class="type">InterfaceB</span> { <span class="reserved">int</span> B { <span class="reserved">get</span>; } }
</code></pre>
<h4>クラス</h4>
<pre class="source" title="">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">sealed</span> <span class="reserved">class</span> <span class="type">SampleClass</span> : <span class="type">BaseClass</span>, <span class="type">InterfaceA</span>, <span class="type">InterfaceB</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> A { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> B { <span class="reserved">get</span>; <span class="reserved">set</span>; }

    <span class="reserved">public</span> SampleClass() { }
    <span class="reserved">public</span> SampleClass(<span class="reserved">int</span> a, <span class="reserved">int</span> b) { A = a; B = b; }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">SampleClass</span> <span class="reserved">operator</span> -(<span class="type">SampleClass</span> x)
        =&gt; <span class="reserved">new</span> <span class="type">SampleClass</span>(-x.A, -x.B);

    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">void</span> X() { }

    ~SampleClass() { }
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">BaseClass</span>
{
    <span class="reserved">public</span> <span class="reserved">virtual</span> <span class="reserved">void</span> X() { }
}

<span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">StaticClass</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">string</span> Hex(<span class="reserved">int</span> x) =&gt; x.ToString(<span class="string">"X"</span>);
}
</code></pre>
<p>単純に、クラスの方ができることは多いです。</p>
<p>クラスにしかできないことは以下の通り。</p>
<ul>
<li>
他のクラスから派生(他のクラスを継承)する
<ul>
<li>継承に関連する修飾子(<code>abstract</code>, <code>sealed</code>, <code>virtual</code>, <code>override</code>など)を使えるもクラスだけ</li>
</ul>
</li>
<li>静的クラス</li>
<li>引数なしのコンストラクターの定義(C# 9.0 まで)</li>
<li>ファイナライザーの定義</li>
</ul>
<p>一方、クラス・構造体どちらでもできることは以下のとおりです。</p>
<ul>
<li>引数なしコンストラクターとファイナライザー以外のメンバー定義</li>
<li>インターフェイスの実装(複数も可)</li>
<li>(構造体自身には<code>static</code>修飾子を付けれないものの)静的メンバーの定義自体は可能</li>
</ul>
<h2><a id="usage">構造体の用途</h2>
<p>「できること」でいうと、構造体はクラスの完全下位互換で、メリットがないように見えます。構造体の利点を理解するには、次項の<a href="http://ufcpp.net/study/csharp/oo_reference.html">値型と参照型</a>についての知識が必要になります。</p>
<p>おおまかに言うと、</p>
<ul>
<li>クラスと構造体ではメモリの使い方が違う</li>
<li>
小さなデータ構造に対しては構造体が有利
<ul>
<li>使い方にもよりますが、大まかなガイドラインとしては16バイト程度が境界と言われています</li>
</ul>
</li>
</ul>
<p>というものです。</p>
<p>この性質と、前節で説明した制限とを併せて考えると、構造体の利用を検討するのは、</p>
<ul>
<li>データ構造が16バイト未満</li>
<li>継承が必要ない</li>
</ul>
<p>という状況下になります。</p>
<h2><a id="default">構造体の既定値</h2>
<p>これも<a href="http://ufcpp.net/study/csharp/oo_reference.html#valtype">値型</a>の性質になりますが、
クラス(<code>new</code>するまでメモリ領域を確保しない)と違って、
構造体は宣言した時点でデータを記録するためのメモリ領域が確保されます。</p>
<p>クラス型のフィールドの場合は、<code>new</code>するなり他のインスタンスを代入するなりして初期化するまでの間、
<code>null</code> (何のインスタンスも指していない状態)が入ります。</p>
<p>一方、構造体の場合、いわゆる「0初期化」状態になっています。
全てのメンバーに対して、0、もしくはそれに類する以下のような値が入ります。</p>
<ul>
<li>
数値型(<code>int</code>, <code>double</code>など)の場合は0
<ul>
<li>列挙型も、0 に相当する値</li>
</ul>
</li>
<li><code>bool</code> 型の場合は <code>false</code></li>
<li>参照型(<code>string</code>、配列、クラス、デリゲートなど)や<a href="http://ufcpp.net/study/csharp/sp2_nullable.html#nullableType">Null許容型</a>の場合は <code>null</code></li>
</ul>
<p>これら、0初期化状態にある値を、<em>構造体の既定値</em>(default value)と呼びます。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> I;
    <span class="reserved">public</span> <span class="reserved">double</span> D;
    <span class="reserved">public</span> <span class="reserved">bool</span> B;
    <span class="reserved">public</span> <span class="reserved">string</span> S;
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="type">Sample</span> s;

    <span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
    {
        <span class="type">Console</span>.WriteLine(s.I);
        <span class="type">Console</span>.WriteLine(s.D);
        <span class="type">Console</span>.WriteLine(s.B);
        <span class="type">Console</span>.WriteLine(s.S);
    }
}
</code></pre>
<pre class="console" title="">
<code>0
0
False

</code></pre>
<h2><a id="parameterless-ctor">引数なしコンストラクター</h2>
<p>C# 9.0 まで、構造体のメンバーとして引数なしのコンストラクターを書くことはできませんでした。
これは、<code>new T()</code>を<a href="/study/csharp/rm_default.html#default-keyword">既定値</a>(0初期化)として使っていたせいです。</p>
<p>例えば以下のコードでは、<code>Point</code>クラスには引数なしのコンストラクターを定義していませんが、
<code>new Point()</code>という書き方で 0 初期化を行っています。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; }
    <span class="reserved">public</span> Point(<span class="reserved">int</span> x, <span class="reserved">int</span> y) { X = x; Y = y; }
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> ToString() =&gt; <span class="string">$"(</span>{X}<span class="string">, </span>{Y}<span class="string">)"</span>;
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
    {
        <span class="reserved">var</span> p1 = <span class="reserved">new</span> <span class="type">Point</span>(); <span class="comment">// 既定値、つまり、「XもYも0に初期化」という意味で使われる</span>
        <span class="reserved">var</span> p2 = <span class="reserved">new</span> <span class="type">Point</span>(10, 20);
        <span class="reserved">var</span> p3 = <span class="reserved">default</span>(<span class="type">Point</span>); <span class="comment">// C# 2.0～9.0 まで、p1と同じ意味</span>

        <span class="type">Console</span>.WriteLine(p1);
        <span class="type">Console</span>.WriteLine(p2);
        <span class="type">Console</span>.WriteLine(p3);
    }
}
</code></pre>
<pre class="console" title="">
<code>(0, 0)
(10, 20)
(0, 0)
</code></pre>
<h5 class="version version2">Ver. 2.0</h5>
<p>ちなみに、C# 2.0 以降では、構造体の既定値は、<code>new T()</code>という書き方の他に、<code>default(T)</code>という書き方もできます。
(主に<a href="http://ufcpp.net/study/csharp/sp2_generics.html">ジェネリック</a>のために導入された構文です。)</p>
<p>既定値について、詳しくは別項「<a href="http://ufcpp.net/study/csharp/rm_default.html#default-constructor">既定値</a>」で説明します。</p>
<h5 class="version version10">Ver. 10</h5>
<p>C# 2.0 で <code>default(T)</code> を使った既定値(0初期化)ができるようになって、
「<code>new T()</code> と書く場合は引数なしコンストラクターを呼ぶ」という仕様に変えたい
(構造体にも引数なしコンストラクターを書けるようにして、<code>new T()</code> と <code>default(T)</code> を区別する)
という話は前々からありました。</p>
<p>C# 10.0 で、ついにその案が採用されることになり、
引数なしコンストラクターを書けるようになりました。
例えば以下のようなコードが書けるようになります。</p>
<pre class="source" title="構造体の引数なしコンストラクターの例">
<code><span class="reserved">struct</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="type">A</span>() =&gt; X = 1;
}
</code></pre>
<p>これで、<code>new A()</code> で <code>X</code> が1になります。</p>
<h3><a id="new-or-default">new() と default</h3>
<p>背景説明の通り、<code>new()</code> と <code>default</code> の意味が変わったので注意が必要です。
この例の構造体 <code>A</code> の場合、以下のような挙動になります。</p>
<pre class="source" title="new A() と default(A)">
<code><span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="reserved">new</span> <span class="type">A</span>().X); <span class="comment">// コンストラクターが呼ばれて、X == 1 になってる。</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="reserved">default</span>(<span class="type">A</span>).X); <span class="comment">// コンストラクターも呼ばれず 0 初期化で、X == 0 になってる。</span>
</code></pre>
<p>C# 7.1/9.0 で、<code>new()</code> や <code>default</code> に<a href="/study/csharp/start/misctyperesolution/#target-type">ターゲット型からの推論</a>が働くようになったので、以下のようにも書けます。</p>
<pre class="source" title="new() と default">
<code><span class="type">A</span> a = <span class="reserved">new</span>();
<span class="type">Console</span>.<span class="method">WriteLine</span>(a.X); <span class="comment">// 1</span>

a = <span class="reserved">default</span>;
<span class="type">Console</span>.<span class="method">WriteLine</span>(a.X); <span class="comment">// 0</span>
</code></pre>
<p><code>default</code> を書く以外に、配列の要素も既定値(0初期化)になるので注意が必要です。</p>
<pre class="source" title=" 配列の要素は暗黙的に default">
<code><span class="comment">// 配列の要素は暗黙的に default…</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>((<span class="reserved">new</span> <span class="type">A</span>[1])[0].X); <span class="comment">// default(A) と同じ扱いで、X == 0 になってる。</span>
</code></pre>
<p>ちなみに、ジェネリクス越しでも <code>new()</code> と <code>default</code> の呼び分けが掛かります。</p>
<pre class="source" title="ジェネリクス越しの new() と default">
<code><span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">New</span>&lt;<span class="type">A</span>&gt;().X); <span class="comment">// 1</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="method">Default</span>&lt;<span class="type">A</span>&gt;().X); <span class="comment">// 0</span>

<span class="reserved">static</span> <span class="type">T</span> <span class="method">New</span>&lt;<span class="type">T</span>&gt;() <span class="reserved">where</span> <span class="type">T</span> : <span class="reserved">new</span>() =&gt; <span class="reserved">new</span>();
<span class="reserved">static</span> <span class="type">T</span>? <span class="method">Default</span>&lt;<span class="type">T</span>&gt;() =&gt; <span class="reserved">default</span>;
</code></pre>
<p>また、これまで <code>default</code> と同じ意味だった <code>new()</code> が、引数なしコンストラクターの有無で違う意味になるのでこの点にも注意が必要です。
例えば、一般の構造体で<a href="/study/csharp/st_function.html#default-parameter">オプション引数</a>を使いたい場合、
既定値しか使えません。
引数なしコンストラクターがない場合には <code>new()</code> も既定値扱いですが、
ある場合には <code>new()</code> を渡せなくなります。</p>
<pre class="source" title="引数なしコンストラクターの有無で new() の意味が変わる例">
<code><span class="reserved">void</span> <span class="method">m</span>(
    <span class="type">NoCtor</span> n1 = <span class="reserved">new</span>(),
    <span class="type">NoCtor</span> n2 = <span class="reserved">default</span>,
    <span class="type">Ctor</span> c1 = <span class="error"><span class="reserved">new</span>()</span>, <span class="comment">// この行だけコンパイル エラー</span>
    <span class="type">Ctor</span> c2 = <span class="reserved">default</span>
    )
{ }

<span class="reserved">struct</span> <span class="type">NoCtor</span> { }
<span class="reserved">struct</span> <span class="type">Ctor</span> { <span class="reserved">public</span> <span class="type">Ctor</span>() { } }
</code></pre>
<h3><a id="field-initialize">フィールド初期化子</h3>
<p>C# 10.0 で構造体に引数なしコンストラクターが使えるようになったことに伴って、
フィールド初期化子も使えるようになりました。
以下のようなコードは C# 10.0 から書けるようになります。</p>
<pre class="source" title="構造体のフィールド初期化子の例">
<code><span class="reserved">struct</span> <span class="type struct">FieldInitializer</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="field">X</span> <span class="operator">=</span> <span class="number">1</span>;
    <span class="reserved">public</span> <span class="reserved">int</span> <span class="field">Y</span> <span class="operator">=</span> <span class="number">2</span>;

    <span class="reserved">public</span> <span class="type struct">FieldInitializer</span>() { }
}
</code></pre>
<p><code>new()</code> だけで、<code>X</code>、<code>Y</code> の値がそれぞれ1、2に初期化されます。</p>
<pre class="source" title="引数なしコンストラクターでフィールド初期化子が呼ばれる例">
<code><span class="reserved">var</span> f = <span class="reserved">new</span> <span class="type">FieldInitializer</span>();
<span class="type">Console</span>.<span class="method">WriteLine</span>(f.X); <span class="comment">// 1</span>
<span class="type">Console</span>.<span class="method">WriteLine</span>(f.Y); <span class="comment">// 2
</code></pre>
<p>(※ 初期案では、明示的なコンストラクター定義もなしでフィールド初期化子を書けるようにする予定でした。
この際、フィールド初期化子を書くとコンパイラーが引数なしコンストラクターを生成していました。
C# 10 リリース当初はその案に基づいた実装になっていましたが、
ちょっと問題があって撤回され、明示的にコンストラクターを書かなければならなくなりました。)</p>
<h3><a id="accessibility">引数なしコンストラクターのアクセシビリティ</h3>
<p><code>new()</code> が <code>default</code> と同じ意味になるのか、
それとも引数なしコンストラクターの呼び出しになるのか紛らわしくなるので、
構造体の引数なしコンストラクターは public 以外を認めていません。</p>
<pre class="source" title="private、internal な引数なしコンストラクターはエラーになる">
<code><span class="reserved">struct</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X;
    <span class="reserved">private</span> <span class="error"><span class="type">A</span></span>() =&gt; X = 0; <span class="comment">// エラー</span>
}

<span class="reserved">struct</span> <span class="type">B</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X;
    <span class="reserved">internal</span> <span class="error"><span class="type">B</span></span>() =&gt; X = 0; <span class="comment">// エラー</span>
}
</code></pre>
<h2><a id="definite-assignment">確実な初期化</h2>
<p>※ C# 10 までの仕様になります。</p>
<p><code>new T()</code> や<code>default(T)</code>で作る「既定値」とは違って、
引数付きのコンストラクターを使う場合は、コンストラクター内で全てのメンバーをきっちり自分の手で初期化する必要がありました。</p>
<p>例えば、以下のコードは、コンストラクター内で <code>_z</code> の初期化を忘れているのでコンパイル エラーになっていました。</p>
<pre class="source" title="_z の初期化忘れ">
<code><reserved></span><span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">int</span> _x;
    <span class="reserved">int</span> _y;
    <span class="reserved">int</span> _z;

    <span class="reserved">public</span> Sample(<span class="reserved">int</span> x, <span class="reserved">int</span> y)
    {
        _x = x;
        _y = y;
        <span class="comment">// C# 10 以前はコンパイル エラー</span>
    }
}
</code></pre>
<p>(クラスの場合はこういう制限はなく、明示的に初期化しなかったフィールドは既定値(0)で初期化されます。)</p>
<p>また、全てのフィールドを初期化するまで、プロパティやメソッドなどの関数メンバーを呼べないという制約もありました。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">int</span> _x;
    <span class="reserved">int</span> _y;

    <span class="reserved">public</span> Sample(<span class="reserved">int</span> x, <span class="reserved">int</span> y)
    {
        M(); <span class="comment">// エラー: _x, _y の初期化より前に呼んじゃダメ。</span>
        _x = x;
        _y = y;
        M(); <span class="comment">// この順ならOK。</span>
    }

    <span class="reserved">void</span> M() { }
}
</code></pre>
<p>(同じくクラスの場合は制限はなし。既定値(0)が使われるだけ。)</p>
<h3><a id="auto-default">構造体のフィールドの既定値初期化</a></h3>
<h5 class="version version11">Ver. 11.0</h5>
<p>C# 11 では、構造体でもフィールドの明示的な初期化が不要になりました。
(クラスと構造体の差が1つなくなりました。)</p>
<p>前節のコードとほぼ同じですが、 C# 11 にすれば以下のようなコードがコンパイルできるようになります。</p>
<pre class="source" title="構造体のフィールドが自動的に 0 初期化されるように">
<code><span class="reserved">struct</span> <span class="type struct">Sample</span>
{
    <span class="reserved">int</span> <span class="field">_x</span>;
    <span class="reserved">int</span> <span class="field">_y</span>;
    <span class="reserved">int</span> <span class="field">_z</span>;

    <span class="reserved">public</span> <span class="type struct">Sample</span>(<span class="reserved">int</span> <span class="variable local">x</span>, <span class="reserved">int</span> <span class="variable local">y</span>)
    {
        <span class="method">M</span>(); <span class="comment">// C# 11 では初期化よりも先に読んでも平気。_x, _y にもこの時点でいったん 0 が入ってる。</span>

        <span class="field">_x</span> <span class="operator">=</span> <span class="variable local">x</span>;
        <span class="field">_y</span> <span class="operator">=</span> <span class="variable local">y</span>;
        <span class="comment">// C# 11 では _z に 0 が自動で入る。</span>
    }

    <span class="reserved">void</span> <span class="method">M</span>() <span class="operator">=&gt;</span> <span class="type">Console</span><span class="operator">.</span><span class="method">WriteLine</span>(<span class="string">$&quot;</span>{<span class="field">_x</span>}<span class="string">, </span>{<span class="field">_y</span>}<span class="string">, </span>{<span class="field">_z</span>}<span class="string">&quot;</span>);
}
</code></pre>
<h3><a id="auto-property">自動プロパティの扱い変更</h3>
<h5 class="version version6">Ver. 6</h5>
<p>前節の「確実な初期化」と絡んで、C# 5.0までのC#では、自動プロパティの初期化が非常に面倒でした。</p>
<p>C# 5.0 以前の場合、以下のコードはコンパイル エラーを起こします。</p>
<pre class="source" title="C# 5.0まではエラーになるコード">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; <span class="reserved">private</span> <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; <span class="reserved">private</span> <span class="reserved">set</span>; }

    <span class="reserved">public</span> Point(<span class="reserved">int</span> x, <span class="reserved">int</span> y)
    {
        <span class="comment">// C# 5.0 まではエラーになる</span>
        X = x;
        Y = y;
    }
}
</code></pre>
<p>エラーを起こす原因は、以下の組み合わせのせいです。</p>
<ul>
<li>自動プロパティを定義すると、コンパイラーが対応するフィールド(バック フィールド)を作る</li>
<li>構造体の制約のせいで、バック フィールドが初期化されるまで、プロパティの読み書きできない</li>
<li>でも、自動プロパティの場合、プロパティを介さずにバック フィールドを初期化する方法がない</li>
</ul>
<p>このせいで、構造体と自動プロパティは相性が悪く、以下のように、自動プロパティを使わない書き方に書き換える必要がありました。</p>
<pre class="source" title="C# 5.0までで正しくコンパイルできるようにするには">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> _x;
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span> { <span class="reserved">return</span> _x; } }

    <span class="reserved">private</span> <span class="reserved">int</span> _y;
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span> { <span class="reserved">return</span> _y; } }

    <span class="reserved">public</span> Point(<span class="reserved">int</span> x, <span class="reserved">int</span> y)
    {
        _x = x;
        _y = y;
    }
}
</code></pre>
<p>これに対して、C# 6では、最初のコードがコンパイルできるようになっています。
C#の仕様書に以下の1文が追加されたことによります。</p>
<ul>
<li>自動プロパティを型の中から使う場合、そのバック フィールドに対する読み書きに置き換える</li>
</ul>
<p>この仕様が追加されたことで、先ほどのコードはバック フィールドの初期化と見なされ、構造体の制約に引っかからなくなりました。</p>
<p>ちなみに、C# 6の場合は get のみの自動プロパティ(get-only auto-property)という構文が追加されて、先ほどのコードはさらに、以下のように書けるようになりました。</p>
<pre class="source" title="C# 6のget-only自動プロパティ">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; }

    <span class="reserved">public</span> Point(<span class="reserved">int</span> x, <span class="reserved">int</span> y)
    {
        X = x;
        Y = y;
    }
}
</code></pre>
<h2><a id="memberwise">メンバー毎コピー、メンバー毎比較</h2>
<p>構造体の変数への代入は、全メンバーのコピーになります。
また、構造体には自動的に<code>Equals</code>メソッドが実装されて、メンバー毎の比較(全メンバー一致の場合に一致)になります。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">Point</span>
    {
        <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; }
        <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; }

        <span class="reserved">public</span> Point(<span class="reserved">int</span> x, <span class="reserved">int</span> y) { X = x; Y = y; }
        <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">string</span> ToString() =&gt; <span class="string">$"(</span>{X}<span class="string">, </span>{Y}<span class="string">)"</span>;
    }

    <span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
    {
        <span class="reserved">var</span> x = <span class="reserved">new</span> <span class="type">Point</span>(1, 2);
        <span class="reserved">var</span> y = x;

        <span class="type">Console</span>.WriteLine(y); <span class="comment">// x のメンバー毎コピー = (1, 2)</span>

        <span class="comment">// メンバー毎比較(全メンバー一致なら一致)</span>
        <span class="type">Console</span>.WriteLine(x.Equals(<span class="reserved">new</span> <span class="type">Point</span>(1, 2))); <span class="comment">// true</span>
        <span class="type">Console</span>.WriteLine(x.Equals(<span class="reserved">new</span> <span class="type">Point</span>(1, 3))); <span class="comment">// false</span>
    }
}
</code></pre>
<h2><a id="struct-modifier">構造体に対する特別な修飾子</h2>
<p>ここでは紹介だけになりますが、構造体にだけ付けることができる特別な修飾子があります。</p>
<ul>
<li><a href="/study/csharp/resource/readonlyness/#readonly-struct">readonly</a></li>
<li><a href="/study/csharp/resource/refstruct/">ref</a></li>
</ul>
<p>詳細についてはそれぞれリンク先を参照してください。</p>
<p>ちなみに、現状では、<code>ref</code> には語順に制約があって、
<code>struct</code>もしくは<code>partial</code>の直前に来る必要があります(緩和も検討されています)。
要するに、<code>readonly ref struct</code>はOKですが、<code>ref readonly struct</code>はエラーになります。</p>
<p>いくつか実例を挙げます。</p>
<pre class="source" title="ref の語順の例">
<code><span class="comment">// OK</span>
<span class="reserved">readonly</span> <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">struct</span> <span class="type">Ok1</span> { }
<span class="reserved">readonly</span> <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">partial</span> <span class="reserved">struct</span> <span class="type">Ok2</span> { }
<span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">partial</span> <span class="reserved">struct</span> <span class="type">Ok3</span> { }

<span class="comment">// コンパイル エラー</span>
<span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved"><span class="error">struct</span></span> <span class="type">Ng1</span> { }
<span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved"><span class="error">public</span></span> <span class="reserved">struct</span> <span class="type">Ng2</span> { }
<span class="reserved">readonly</span> <span class="reserved">public</span> <span class="error">partial</span> <span class="reserved"><span class="error">ref</span></span> <span class="reserved">struct</span> <span class="type">Ng3</span> { }
<span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved"><span class="error">partial</span></span> <span class="reserved">struct</span> <span class="type">Ng4</span> { }
<span class="reserved">public</span> <span class="reserved">ref</span> <span class="error">partial</span> <span class="reserved"><span class="error">readonly</span></span> <span class="reserved">struct</span> <span class="type">Ng5</span> { }
</code></pre>
<p>おそらく、以下のような型の入れ子とメソッド定義の区別を楽にするための制限(あくまでコンパイラー都合)と思われます。</p>
<pre class="source" title="ref の語順に制限がある理由">
<code><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="comment">// 以下のエラー行、エラー内容は「readonly の後ろには型名が必要」になる</span>
    <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved"><span class="error">struct</span></span> <span class="type">InnerStruct</span> { }
    <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> Method(<span class="reserved">in</span> <span class="reserved">int</span> x) =&gt; <span class="reserved">ref</span> x;
}
</code></pre> ]]></description>
				<pubDate>Sat, 04 Nov 2017 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>readonly の注意点</title>
				<link>http://www.ufcpp.net/study/csharp/resource/readonlyness/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>「<a href="http://ufcpp.net/study/csharp/sp_const.html#readonly">定数</a>」で、読み取り専用のフィールドが作れるという話をしました。
この時点ではまだ<a href="/study/csharp/oo_class.html">クラス</a>や<a href="/study/csharp/resource/rm_struct/">構造体</a>、<a href="/study/csharp/oo_reference.html">値型と参照型の違い</a>などについて触れていなかったので<code>readonly</code>修飾子の簡単な紹介だけに留めましたが、
本項で改めて<code>readonly</code>について説明します。</p>
<p>整数などの基本的な型に対して使う分には特に問題は起きないんですが、構造体やクラスなど、複合型に対して使うときには注意が必要です。</p>
<h2><a id="class-readonly">参照型のフィールドに対して readonly</h2>
<p><code>readonly</code>に関して最も注意が必要な点は、<code>readonly</code>は再帰的には働かないという点です。
<code>readonly</code>を付けたその場所だけが読み取り専用になり、参照先などについては書き換えが可能です。</p>
<p>例えば以下のコードを見てください。<code>Program</code>クラスのフィールド<code>c</code>には<code>readonly</code>が付いていますが、
<code>c</code>が普通に書き換え可能なクラスのフィールドなので、クラスの中身は自由に書き換えられます。</p>
<pre class="source" title="参照型のフィールドに対してreadonlyを付ける例">
<code><span class="comment">// 書き換え可能なクラス</span>
<span class="reserved">class</span> <span class="type">MutableClass</span>
{
    <span class="comment">// フィールドを直接公開</span>
    <span class="reserved">public</span> <span class="reserved">int</span> X;

    <span class="comment">// 書き換え可能なプロパティ</span>
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; <span class="reserved">set</span>; }

    <span class="comment">// フィールドの値を書き換えるメソッド</span>
    <span class="reserved">public</span> <span class="reserved">void</span> M(<span class="reserved">int</span> value) =&gt; X = value;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">readonly</span> <span class="type">MutableClass</span> c = <span class="reserved">new</span> <span class="type">MutableClass</span>();

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// これは許されない。c は readonly なので、c 自体の書き換えはできない</span>
        <span class="error">c</span> = <span class="reserved">new</span> <span class="type">MutableClass</span>();

        <span class="comment">// けども、c の中身までは保証してない</span>
        <span class="comment">// 書き換え放題</span>
        c.X = 1;
        c.Y = 2;
        c.M(3);
    }
}
</code></pre>
<p><img src="/media/1145/mutableclass.png" alt="参照型のフィールドに対してreadonlyを付ける例" /></p>
<p>クラスを書き換えできないように作る場合、クラス自体を書き換え不能に作りましょう。
(クラスの方で、フィールドを<code>readonly</code>にしたり、プロパティを<a href="http://ufcpp.net/study/csharp/oo_property.html#get-only">get-only</a>にします。)</p>
<h2><a id="struct-readonly">値型のフィールドに対して readonly</h2>
<p>クラス(参照型)とは対照的に、構造体(値型)の場合はデータを直接持ちます。
そのため、構造体のフィールドに対して<code>readonly</code>を付けると、構造体の中身も読み取り専用になります。
ただし、メソッドの呼び出しなどを行う際、コピーが発生するという別の注意が必要です。</p>
<p>例えば以下のように、<code>readonly</code>が付いたフィールド<code>c</code>自体に加えて、<code>c</code>のフィールドも書き換えできません。</p>
<pre class="source" title="値型のフィールドに対してreadonlyを付ける例">
<code><span class="reserved">using</span> System;

<span class="comment">// 書き換え可能な構造体</span>
<span class="reserved">struct</span> <span class="type">MutableStruct</span>
{
    <span class="comment">// フィールドを直接公開</span>
    <span class="reserved">public</span> <span class="reserved">int</span> X;

    <span class="comment">// フィールドの値を書き換えるメソッド</span>
    <span class="reserved">public</span> <span class="reserved">void</span> M(<span class="reserved">int</span> value) =&gt; X = value;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">readonly</span>  <span class="type">MutableStruct</span> c = <span class="reserved">new</span>  <span class="type">MutableStruct</span>();

    <span class="reserved">static</span> <span class="reserved">void</span> Main() =&gt; Allowed();

    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">void</span> NotAllowed()
    {
        <span class="comment">// これはもちろん許されない。c は readonly なので、c 自体の書き換えはできない</span>
        <span class="error">c</span> = <span class="reserved">new</span>  <span class="type">MutableStruct</span>();

        <span class="comment">// 構造体の場合、フィールドに関しては readonly な性質を引き継ぐ</span>
        <span class="error">c.X</span> = 1;
    }

    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">void</span> Allowed()
    {
        <span class="comment">// でも、メソッドは呼べてしまう</span>
        c.M(3); <span class="comment">// X を 3 で上書きしているはず？</span>

        <span class="type">Console</span>.WriteLine(c.X); <span class="comment">// でも、X は 0 のまま</span>

        <span class="comment">//↑のコードは、実はコピーが発生している</span>
        <span class="comment">// 以下のコードと同じ意味になる</span>

        <span class="reserved">var</span> local = c;
        local.M(3);

        <span class="type">Console</span>.WriteLine(c.X); <span class="comment">// 書き換わってるのは local (コピー)の方なので、c は書き換わらない(0)</span>

        <span class="type">Console</span>.WriteLine(local.X); <span class="comment">// もちろんこっちは書き換わってる(3)</span>
    }
}
</code></pre>
<p><img src="/media/1146/mutablestruct.png" alt="値型のフィールドに対してreadonlyを付ける例" /></p>
<p>この例の後半を見ての通り、メソッドは呼べてしまいます。
フィールド<code>X</code>は書き換えれないはずなのに、その<code>X</code>を書き換えているメソッド<code>M</code>を呼んでもエラーになりません。
C# では、こういう場合に、<code>readonly</code>であることを保証しつつメソッドを呼び出せるように、フィールドを一度コピーしてから、そのコピーに対してメソッドを呼ぶということをしています。</p>
<p>このコピーは、万が一に備えて防衛的にコピー(defensive copy)するものです。
実際にコピーが必要かどうか(実際にメソッド内で書き換えをしているかどうか)に関わらず、常にコピーが発生します。
ソースコード上は目に見えないコピーなので、<strong id="hidden-copy" class="keyword">隠れたコピー</strong>(hidden copy)と呼ばれたりもします。</p>
<p>すなわち、コピーが発生してまずいような場合(例えば構造体のサイズが大きくてコピーにコストが掛かるとか)には、<code>readonly</code>なフィールドを使うことで問題が発生することがあります。
この問題は、<a href="http://ufcpp.net/study/csharp/sp_ref.html#in"><code>in</code>引数</a>などでも発生しまえます。
後述する<a href="#readonly-struct"><code>readonly struct</code></a>や<a href="#readonly-member">readonly 関数メンバー</a>を使えばこの問題は少し緩和するので、そちらも参照してください。</p>
<h2><a id="this-rewrite">構造体の this 書き換え</h2>
<p>C# の<code>readonly</code>フィールドには少し片手落ちなところがあって、実は、構造体の場合にちょっとした問題を起こせたりします。</p>
<p>構造体のメソッドの中では<code>this</code>が「自分自身の参照」の意味なんですが、この<code>this</code>参照は書き換えできてしまいます。
そのため、以下のように、<code>readonly</code>で一見書き換えができなさそうなフィールドを書き換えてしまうことができます。</p>
<pre class="source" title="構造体の this 書き換えの例">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="comment">// フィールドに readonly を付けているものの…</span>
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> Y;

    <span class="reserved">public</span> <span class="type">Point</span>(<span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; (X, Y) = (x, y);

    <span class="comment">// this の書き換えができてしまうので、実は X, Y の書き換えが可能</span>
    <span class="reserved">public</span> <span class="reserved">void</span> Set(<span class="reserved">int</span> x, <span class="reserved">int</span> y)
    {
        <span class="comment">// X = x; Y = y; とは書けない</span>
        <span class="comment">// でも、this 自体は書き換えられる</span>
        <span class="reserved">this</span> = <span class="reserved">new</span> <span class="type">Point</span>(x, y);
    }
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> p = <span class="reserved">new</span> <span class="type">Point</span>(1, 2);

        <span class="comment">// p.X = 0; とは書けない。これはちゃんとコンパイル エラーになる</span>

        <span class="comment">// でも、このメソッドは呼べるし、X, Y が書き換わる</span>
        p.Set(3, 4);

        <span class="type">Console</span>.WriteLine(p.X); <span class="comment">// 3</span>
        <span class="type">Console</span>.WriteLine(p.Y); <span class="comment">// 4</span>
    }
}
</code></pre>
<p>わざわざこんな紛らわしいことをしようとは思わないのでめったに問題になることはないんですが、一応は注意が必要です。
また、この問題は、次節で説明する通り、C# 7.2で少し緩和されます。</p>
<h2><a id="readonly-struct">readonly struct</h2>
<h5 class="version version7">Ver. 7.2</h5>
<p>C# 7.2で、構造体自体に<code>readonly</code>修飾を付けられるようになりました。
<code>readonly</code>を付けた構造体は以下のような状態になります。</p>
<ul>
<li>
全てのフィールドに対して <code>readonly</code> を付けなければならなくなる
<ul>
<li><a href="http://ufcpp.net/study/csharp/oo_property.html#get-only">get-onlyプロパティ</a>は使えます(自動生成されるフィールドが<code>readonly</code>なので問題ない)</li>
</ul>
</li>
<li><code>this</code>参照も<code>readonly</code>扱いされる</li>
</ul>
<p><code>this</code>が<code>readonly</code>扱いになるので、前節のような<code>this</code>書き換えの問題は起きません。</p>
<pre class="source" title="readonly struct の例">
<code><span class="reserved">using</span> System;

<span class="comment">// 構造体自体に readonly を付ける</span>
<span class="reserved"><em>readonly</em></span> <span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="comment">// フィールドには readonly が必須</span>
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> Y;

    <span class="reserved">public</span> <span class="type">Point</span>(<span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; (X, Y) = (x, y);

    <span class="comment">// readonly を付けない場合と違って、以下のような this 書き換えも不可</span>
    <span class="comment">//public void Set(int x, int y) =&gt; this = new <span class="type">Point</span>(x, y);</span>
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> p = <span class="reserved">new</span> <span class="type">Point</span>(1, 2);

        <span class="comment">// p.X = 0; とは書けない。これはちゃんとコンパイル エラーになる</span>
        <span class="comment">// p.Set(3, 4); みたいなのもダメ</span>

        <span class="type">Console</span>.WriteLine(p.X); <span class="comment">// 1 しかありえない</span>
        <span class="type">Console</span>.WriteLine(p.Y); <span class="comment">// 2 しかありえない</span>
    }
}
</code></pre>
<h3><a id="avoid-copy">readonly struct によるコピー回避</h3>
<p><a href="/study/csharp/resource/readonlyness/#struct-readonly">前述</a>の通り、(無印の)構造体の<code>readonly</code>フィールドに対してメソッドを呼ぶと防衛的コピーが発生するという問題があります。
これに対して、<code>readonly struct</code>であれば、このコピーを回避できます。</p>
<p>例えば以下のように、ほぼ同じ構造・どちらも書き換え不能な構造体を作ったとして、<code>readonly struct</code>になっているかどうかでコピー発生の有無が変わります。</p>
<pre class="source" title="">
<code><span class="reserved">using</span> System;

<span class="comment">// 作りとしては readonly を意図しているので、何も書き換えしない</span>
<span class="comment">// でも、struct 自体には readonly が付いていない</span>
<span class="reserved">struct</span> <span class="type">NoReadOnly</span>
{
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="reserved">void</span> M() { }
}

<span class="comment">// <span class="type">NoReadOnly</span> と作りは同じ</span>
<span class="comment">// ちゃんと readonly struct</span>
<span class="reserved">readonly</span> <span class="reserved">struct</span> <span class="type">ReadOnly</span>
{
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="reserved">void</span> M() { }
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">readonly</span> <span class="type">NoReadOnly</span> nro;
    <span class="reserved">static</span> <span class="reserved">readonly</span> <span class="type">ReadOnly</span> ro;

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// readonly を付けなかった場合</span>
        <span class="comment">// フィールド参照(読み取り)は問題ない</span>
        <span class="type">Console</span>.WriteLine(nro.X);

        <span class="comment">// メソッド呼び出しが問題。ここでコピー発生</span>
        <span class="comment">// (呼び出し側では、「M の中で特に何も書き換えていない」というのを知るすべがないので、防衛的にコピーが発生)</span>
        nro.M();

        <span class="comment">// readonly を付けた場合</span>
        <span class="comment">// これなら、M をそのまま呼んでも何も書き換わらない保証があるので、コピーは起きない</span>
        ro.M();
    }

    <span class="comment">// これも問題あり(コピー発生)</span>
    <span class="comment">// in を付けたので readonly 扱い → M を呼ぶ際にコピー発生</span>
    <span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">in</span> <span class="type">NoReadOnly</span> x) =&gt; x.M();

    <span class="comment">// こちらも、readonly struct であれば問題なし(コピー回避)</span>
    <span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">in</span> <span class="type">ReadOnly</span> x) =&gt; x.M();
}
</code></pre>
<p>C# 7.2 以降では、書き換えを意図していない構造体に対しては<code>readonly</code>修飾を付けるのが無難でしょう。</p>
<p>また、「フィールド直接参照なら大丈夫だけど、メソッドを(プロパティも)呼ぶとコピー発生」という性質上、
書き換えを最初から意図している構造体の場合は、プロパティよりも、フィールドを直接<code>public</code>にしてしまう方が都合がいいことがあります。</p>
<h2><a id="ref-readonly">readonly参照と不変性</h2>
<p><a href="/study/csharp/sp_ref.html#in"><code>in</code>引数</a>や<a href="http://ufcpp.net/study/csharp/sp_ref.html?p=2#ref-readonly"><code>ref readonly</code></a>で、読み取り専用の参照を作れます。
この読み取り専用参照は、「そのメソッド内で書き換えない」、「その引数・変数を通した書き換えをしない」という意思表明としては非常に有用です。
その一方で、「外で書き換わる」、「参照元の値が書き換わる」という意味で、不変性(immutability)の保証はありません。</p>
<p>例えば以下の例を見てください。</p>
<pre class="source" title="in/ref readonly で保証できる範囲">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        _value = 0;
        ByVal(_value); <span class="comment">// 0, 0</span>

        _value = 0;
        ByRef(_value); <span class="comment">// 0, 1</span>
    }

    <span class="comment">// 書き換えできるフィールド</span>
    <span class="reserved">static</span> <span class="reserved">int</span> _value;

    <span class="comment">// 値渡し = コピー なので、 _value 書き換えの影響は受けない</span>
    <span class="reserved">static</span> <span class="reserved">void</span> ByVal(<span class="reserved">int</span> value)
    {
        <span class="type">Console</span>.WriteLine(value);
        _value++;
        <span class="type">Console</span>.WriteLine(value);
    }

    <span class="comment">// 参照渡しなので、 _value 書き換えの影響を受ける</span>
    <span class="comment">// in (ref readonly) であっても、immutable ではない</span>
    <span class="comment">// value を通して書き換えない保証があるだけで、別経路で書き換わることに対しては無力</span>
    <span class="reserved">static</span> <span class="reserved">void</span> ByRef(<span class="reserved">in</span> <span class="reserved">int</span> value)
    {
        <span class="type">Console</span>.WriteLine(value);
        _value++;
        <span class="type">Console</span>.WriteLine(value);
    }
}
</code></pre>
<p>メソッドの中身としては全く同じメソッドが2つありますが、片方(<code>ByVal</code>)は値渡しで、もう片方(<code>ByRef</code>)は <code>in</code> 引数で整数値を受け取っています。
<code>ByVal</code>では、<code>value</code>は値のコピーを受け取っているので、元の値の出どころとは無縁になっています。
一方、<code>ByRef</code>の方では<code>value</code>自身は<code>in</code>が付いていて書き換えられませんが、その参照元になっている<code>_value</code> の方が書き換わると、<code>value</code>の値も一緒に変化します。
書き換え不能(readonly)だからと言って、値の不変性(immutable)の保証はなく、こうして値が変化する場合があります。</p>
<h2><a id="readonly-member">readonly 関数メンバー</h2>
<h5 class="version version8">Ver. 8.0</h5>
<p>C# 8.0 で、<a href="/study/csharp/st_function.html#sec-function-member">関数メンバー</a>単位で「フィールドを書き換えてない」ということを保証できるようになりました。
構造体全体を <code>readonly struct</code> にしなくても、<a href="#hidden-copy">隠れたコピー</a>問題を避けられる機会が増えます。</p>
<p>以下のように、関数メンバーに <code>readonly</code> 修飾を付けます。</p>
<pre class="source" title="readonly 関数メンバーの例">
<code><span class="comment">// 構造体自体は readonly にしない。</span>
<span class="comment">// フィールドは書き換えたい</span>
<span class="reserved">struct</span> <span class="type">NonReadOnly</span>
{
    <span class="reserved">public</span> <span class="reserved">float</span> X;
    <span class="reserved">public</span> <span class="reserved">float</span> Y;
 
    <span class="comment">// でも、このプロパティ内ではフィールドを書き換えない</span>
    <span class="reserved">public</span> <span class="reserved">float</span> LengthSquared =&gt; X * X + Y * Y;
}
 
<span class="comment">// NonReadOnly との差は LengthSquared の readonly の有無だけ</span>
<span class="reserved">struct</span> <span class="type">ReadOnly</span>
{
    <span class="reserved">public</span> <span class="reserved">float</span> X;
    <span class="reserved">public</span> <span class="reserved">float</span> Y;
 
    <span class="comment">// readonly 修飾でフィールドを書き換えないことを明示</span>
    <span class="reserved">public</span> <span class="reserved"><em>readonly</em></span> <span class="reserved">float</span> LengthSquared =&gt; X * X + Y * Y;
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// こっちは、LengthSquared 内での X, Y の書き換えを恐れて隠れたコピーが発生する。</span>
    <span class="reserved">static</span> <span class="reserved">float</span> <span class="method">M</span>(<span class="reserved">in</span> <span class="type">NonReadOnly</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span>.LengthSquared;
 
    <span class="comment">// こっちは、LengthSquared に readonly が付いているのでコピー発生しない。</span>
    <span class="reserved">static</span> <span class="reserved">float</span> <span class="method">M</span>(<span class="reserved">in</span> <span class="type">ReadOnly</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span>.LengthSquared;
 
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>(<span class="reserved">string</span>[] <span class="variable">args</span>)
    {
        <span class="method">M</span>(<span class="reserved">new</span> <span class="type">NonReadOnly</span> { X = 1, Y = 2 });
        <span class="method">M</span>(<span class="reserved">new</span> <span class="type">ReadOnly</span> { X = 1, Y = 2 });
    }
}
</code></pre>
<p>隠れたコピー問題はソースコードの見た目に現れず、気づきにくい問題なので、
関数内でフィールドを書き換えていないなら積極的に <code>readonly</code> 修飾を付けておくべきでしょう。</p>
<p>ちなみに、逆に、<code>readonly</code> 関数メンバー内から、<code>readonly</code> ではないものを触ろうとしても隠れたコピーが発生します。
例えば以下のコードでは、<code>A</code>のフィールドを書き換える<code>Increment</code>メソッドを、
<code>readonly</code> なメソッドとそうでないメソッドから呼び出してみています。</p>
<pre class="source" title="readonly 関数メンバーから、非 readonly な構造体フィールドに触る">
<code><span class="reserved">using</span> System;
 
<span class="reserved">struct</span> <span class="type">A</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> Value;
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Increment</span>() =&gt; Value++;
}
 
<span class="reserved">struct</span> <span class="type">B</span>
{
    <span class="reserved">public</span> <span class="type">A</span> A;
 
    <span class="comment">// A の非 readonly メンバーを呼ぶ。</span>
    <span class="reserved">public</span> <span class="reserved">void</span> <span class="method">Mutable</span>() =&gt; A.<span class="method">Increment</span>();
 
    <span class="comment">// Mutable との差は readonly 修飾が付いてるだけ。</span>
    <span class="comment">// this が書き換わらないように、A のコピーが作られる。A 自体には変化が起きない。</span>
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">void</span> <span class="method">Immutable</span>() =&gt; A.<span class="method">Increment</span>();
}
 
<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
    {
        <span class="reserved">var</span> <span class="variable">b</span> = <span class="reserved">new</span> <span class="type">B</span>();
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">b</span>.A.Value); <span class="comment">// 初期状態: 0</span>
 
        <span class="variable">b</span>.<span class="method">Mutable</span>();
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">b</span>.A.Value); <span class="comment">// 意図通りの書き換え: 1</span>
 
        <span class="variable">b</span>.<span class="method">Immutable</span>();
        <span class="type">Console</span>.<span class="method">WriteLine</span>(<span class="variable">b</span>.A.Value); <span class="comment">// 書き換わらない: 1 (Immutable の中で A のコピーが発生)</span>
    }
}
</code></pre>
<h3><a id="similar-but-different">注意: 似て非なるもの(ref readonly)</h3>
<p>この <code>readonly</code> 関数メンバーは、構文上、<a href="/study/csharp/sp_ref.html?p=2#ref-readonly"><code>ref readonly</code></a>と似ているのでちょっと注意が必要かもしれません。</p>
<pre class="source" title="readonly ref との兼ね合い">
<code><span class="reserved">struct</span> <span class="type">S</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span>[] _value;
 
    <span class="comment">// これは、読み取り専用参照を返すという意味。</span>
    <span class="comment">// _value 配列の中身が書き換わってもらっては困る。</span>
    <span class="reserved">public</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> X =&gt; <span class="reserved">ref</span> _value[0];
 
    <span class="comment">// これは、S 内のフィールド(この場合 _value) を書き換えないという意味。</span>
    <span class="comment">// _value 配列の中身が書き換わろうと知ったことではない。</span>
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">int</span> Y =&gt; <span class="reserved">ref</span> _value[0];
 
    <span class="comment">// これは、上記2つの両方の意味。</span>
    <span class="comment">// _value 自体も書き換わらないし、_value の中身を書き換えてもらっても困るとき用。</span>
    <span class="reserved">public</span> <span class="reserved">readonly</span> <span class="reserved">ref</span> <span class="reserved">readonly</span> <span class="reserved">int</span> Z =&gt; <span class="reserved">ref</span> _value[0];
}
</code></pre>
<p>ちなみに、プロパティの場合は <code>get</code>/<code>set</code> それぞれ別に <code>readonly</code> 指定ができます。
当然ですが、ほとんどの場合は「<code>get</code> だけが <code>readonly</code>」になると思われます。</p>
<pre class="source" title="プロパティの get にだけ readonly 修飾">
<code><span class="reserved">struct</span> <span class="type">X</span>
{
    <span class="reserved">int</span> _value;
 
    <span class="reserved">public</span> <span class="reserved">int</span> Value
    {
        <span class="reserved">readonly</span> <span class="reserved">get</span> =&gt; _value;
        <span class="reserved">set</span> =&gt; _value = <span class="reserved">value</span>;
    }
}
</code></pre> ]]></description>
				<pubDate>Sat, 04 Nov 2017 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 7.1 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver7_1/</link>
				<description><![CDATA[ <h2><a id="ver7_1">C# 7.1</h2>
<div class="version version7_1">Ver. 7.1</div>
<table>
<tr>
<th>リリース時期</th>
<td>2017/8</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>Visual Studio 2017 Update 3 (15.3)</li>
</td>
</tr>
<tr>
<th>要約・目玉機能</ht>
<td>
<ul>
<li>C# 7.0のちょっとした改善</li>
</ul>
</td>
</tr>
</table>
<p>2017年8月、すなわち、C# 7.0のリリース(2017年2月)から半年足らずで C# 7.1 がリリースされました。</p>
<p>C# 7.0の頃から、目標としては C# のリリース サイクルの短縮を考えていました。
多くの機能を2・3年に1度一気にリリースするよりも、細かく出せるものに関しては短いリリース サイクルで出したいという意図です。
今回、(実質的に<sup>※</sup>)初の「マイナー バージョンアップ」となる C# 7.1 が誕生しました。</p>
<p>(<sup>※</sup> 一応、<a href="http://ufcpp.net/study/csharp/cheatsheet/ap_ver1/#sec-generated-title-2">C# 1.1</a>があったんですが、ほとんど使われない機能が2つ追加されただけなので、1.1があったこと自体あまり認知されていないものです。)</p>
<p>C# 7.1 は、Visual Studio 2017のリリース時期に間に合わなかった C# 7.0 の積み残しと言った感じの、小さい機能が4つほど追加されています。</p>
<h2><a id="async-Main">非同期Main</h2>
<p><code>Main</code>メソッドの戻り値に<code>Task</code>クラス(<code>System.Threading.Tasks</code>名前空間)を使えるようになりました。
以下のいずれかのオーバーロードであればエントリーポイントとして認識されます。</p>
<pre class="source" title="非同期Main(C# 7.1 から)">
<code><span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; Main()
<span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; Main(<span class="reserved">string</span>[] args)
<span class="reserved">static</span> <span class="type">Task</span> Main()
<span class="reserved">static</span> <span class="type">Task</span> Main(<span class="reserved">string</span>[] args)
</code></pre>
<p>詳しくは、「<a href="http://ufcpp.net/study/csharp/structured/miscentrypoint/#async-main">非同期Main</a>」で説明します。</p>
<h2><a id="default-expr">default 式</h2>
<p>これまでも<a href="http://ufcpp.net/study/csharp/rm_default.html">既定値</a>を作るために、<code>default(T)</code>という構文がありましたが、
型名<code>T</code>の指定が煩雑でした。
特に、名前の長い型に対して<code>default(T)</code>を使うと、かなりのうっとおしさがあります。</p>
<p>既定値を結構使って、かつ、名前が長い型というと、例えば<code>CancellationToken</code>構造体(<code>System.Threading</code>名前空間)とかです。
以下のようなコードを書いたりします。</p>
<pre class="source" title="CancellationTokenの規定値をdefault(T)で作る例">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> DefaultExpression(<span class="type">CancellationToken</span> c = <span class="reserved">default</span>(<span class="type">CancellationToken</span>))
{
    <span class="reserved">while</span> (c != <span class="reserved">default</span>(<span class="type">CancellationToken</span>) &amp;&amp; !c.IsCancellationRequested)
    {
        <span class="reserved">await</span> <span class="type">Task</span>.Delay(1000);
        <span class="type">Console</span>.WriteLine(<span class="string">"."</span>);
    }
}
</code></pre>
<p>これに対して、C# 7.1では、左辺(代入先)から推論できる場合に、<code>(T)</code>を省略して<code>default</code>だけで既定値を作れるようになりました。
例えば先ほどのコードは以下のように書き直せます。</p>
<pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> DefaultExpression(<span class="type">CancellationToken</span> c = <em><span class="reserved">default</span></em>)
{
    <span class="reserved">while</span> (c != <em><span class="reserved">default</span></em> &amp;&amp; !c.IsCancellationRequested)
    {
        <span class="reserved">await</span> <span class="type">Task</span>.Delay(1000);
        <span class="type">Console</span>.WriteLine(<span class="string">"."</span>);
    }
}
</code></pre>
<p>既定値自体や、<code>default(T)</code>の説明は「<a href="http://ufcpp.net/study/csharp/rm_default.html">既定値</a>」を参照してください。</p>
<h2><a id="infer-tuple-name">タプル要素名の推論</h2>
<p>タプルの要素名が、タプル構築時に渡した変数から推論できるようになりました。
例えば以下のように、<code>(x, y)</code> と書くだけで、1要素目に<code>x</code>、2要素目に <code>y</code> という名前が付きます。
(これまでだと、<code>(x: x, y: y)</code> と書く必要があった。)</p>
<pre class="source" title="タプル要素名の推論の例">
<code><span class="reserved">var</span> x = 1;
<span class="reserved">var</span> y = 2;
<span class="reserved">var</span> t = (x, y);

<span class="comment">// C# 7.0。t の要素には名前が付かない</span>
<span class="type">Console</span>.WriteLine(t.Item1);
<span class="type">Console</span>.WriteLine(t.Item2);

<span class="comment">// C# 7.1。(x, y) で (x: x, y: y) 扱い</span>
<span class="comment">// t の要素に x, y という名前が付く</span>
<span class="type">Console</span>.WriteLine(t.x);
<span class="type">Console</span>.WriteLine(t.y);
</code></pre>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/datatype/tuples/#infer-tuple-name">タプル</a>」で説明します。</p>
<h2><a id="generic-type-switch">ジェネリック型に対するパターン マッチング(型スイッチ)</h2>
<p>C# 7.0で<a href="http://ufcpp.net/study/csharp/datatype/typeswitch/"><code>is</code>や<code>switch</code>で型を見ての分岐</a>ができるようになりました。
しかし、<a href="http://ufcpp.net/study/csharp/sp2_generics.html">ジェネリクス</a>が絡む場合、
例えば以下のようなコードはC# 7.0ではコンパイル エラーになっていました。</p>
<pre class="source" title="C# 7.0ではコンパイルできないswitchの例">
<code><span class="reserved">static</span> <span class="reserved">void</span> M&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x)
{
    <span class="reserved">switch</span> (x)
    {
        <span class="reserved">case</span> <span class="reserved">int</span> i:
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="reserved">string</span> s:
            <span class="reserved">break</span>;
    }
}
</code></pre>
<p>「<code>T</code>を<code>int</code>や<code>string</code>として処理できない」と言った旨のコンパイル エラーが出ます。</p>
<p>さらにいうと、以下のような需要が結構ありそうな場面でも、C# 7.0ではコンパイル エラーになりました。</p>
<pre class="source" title="C# 7.0ではコンパイルできないswitchの例(型制約付き)">
<code><span class="reserved">class</span> <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">Derived1</span> : <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">Derived2</span> : <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">Derived3</span> : <span class="type">Base</span> { }

<span class="comment">// こういう、型制約付きのやつですら 7.0 ではダメだった</span>
<span class="reserved">static</span> <span class="reserved">void</span> N&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">Base</span>
{
    <span class="reserved">switch</span> (x)
    {
        <span class="reserved">case</span> <span class="type">Derived1</span> d:
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="type">Derived2</span> d:
            <span class="reserved">break</span>;
        <span class="reserved">case</span> <span class="type">Derived3</span> d:
            <span class="reserved">break</span>;
    }
}
</code></pre>
<p>C# 7.0でも、以下のように、<code>as</code>演算子を使った場合にはちゃんとコンパイルできます。
型スイッチは、内部的には<code>as</code>演算子に展開される機能で、<code>as</code>演算子にできて型スイッチにできないことがあるのは不自然です。</p>
<pre class="source" title="as 演算子での置き換え">
<code><span class="reserved">static</span> <span class="reserved">void</span> N&lt;<span class="type">T</span>&gt;(<span class="type">T</span> x)
    <span class="reserved">where</span> <span class="type">T</span> : <span class="type">Base</span>
{
    { <span class="reserved">var</span> d = x <span class="reserved">as</span> <span class="type">Derived1</span>; <span class="reserved">if</span> (d != <span class="reserved">null</span>) { <span class="reserved">return</span>; } }
    { <span class="reserved">var</span> d = x <span class="reserved">as</span> <span class="type">Derived2</span>; <span class="reserved">if</span> (d != <span class="reserved">null</span>) { <span class="reserved">return</span>; } }
    { <span class="reserved">var</span> d = x <span class="reserved">as</span> <span class="type">Derived3</span>; <span class="reserved">if</span> (d != <span class="reserved">null</span>) { <span class="reserved">return</span>; } }
}
</code></pre>
<p>そこで、C# 7.1では、上記コードのような、ジェネリックな型に対する型スイッチを使えるようになりました。
(新機能というよりは、仕様漏れ・バグ修正の類です。)</p>
<p>パターンマッチング(型スイッチ)自体の説明に関しては「<a href="http://ufcpp.net/study/csharp/datatype/typeswitch/">型スイッチ</a>」を参照してください。</p>
 ]]></description>
				<pubDate>Tue, 15 Aug 2017 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] エントリーポイント</title>
				<link>http://www.ufcpp.net/study/csharp/structured/miscentrypoint/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>C# では通常、1つのプログラムは複数の C# ソースコードからなり、そのソースコード中には複数の関数が含まれています。
その、多数ある関数の中で、プログラム起動時に最初に呼ばれるものを<strong id="entry-point" class="keyword">エントリーポイント</strong>(entry point: 入場地点)と呼びます。</p>
<p>「<a href="http://ufcpp.net/study/csharp/st_basis.html">C# のプログラムの基本構造</a>」で例を出したように、
C# では、<code>Main</code>という名前の関数が自動的にエントリーポイントになります。</p>
<p>(「<a href="http://ufcpp.net/study/csharp/st_function.html">関数</a>」内でも補足していますが、
正確にいうと、<code>Main</code>という名前のメソッドがエントリーポイントになります。)</p>
<h3><a id="cs-script">[補足] C# スクリプト</h3>
<p><a href="http://ufcpp.net/study/csharp/cheatsheet/apscripting/">スクリプト実行</a>の場合は関数で囲わなくてもどこにでも処理を書けます。
<code>Main</code>関数も不要です。</p>
<h2><a id="Main">Main の引数、戻り値</h2>
<p><code>Main</code>の引数と戻り値は、以下のいずれかである必要があります。
これ以外のオーバーロードはエントリーポイントになりません。</p>
<pre class="source" title="Main の引数と戻り値">
<code><span class="reserved">static</span> <span class="reserved">int</span> Main()
<span class="reserved">static</span> <span class="reserved">int</span> Main(<span class="reserved">string</span>[] args)
<span class="reserved">static</span> <span class="reserved">void</span> Main()
<span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
</code></pre>
<p>(ただし、後述しますが、C# 7.1 からは戻り値として<code>Task</code>クラスが使えるようになりました。)</p>
<p>引数を持っている場合、引数にはコマンドライン引数が渡ってきます。
(引数なし版は、コマンドライン引数を受け取る必要がない時に使います。)</p>
<p>また、戻り値はプログラムの終了コードを返します。
<a href="https://msdn.microsoft.com/ja-jp/library/ms194959(v=vs.100).aspx">Windows の場合</a>は0が正常終了、1が部分的な成功、…などの意味があるようです。
戻り値なし版の場合は常に0(正常終了)扱いです。</p>
<h2><a id="no-main">Main がないタイプのプロジェクト</h2>
<p>GUI アプリや Web アプリでは、<code>Main</code>関数を書かない場合があります。
この場合、以下のいずれかです。</p>
<ul>
<li>他のプログラムから呼び出される。どの関数から呼び出すかは、呼び出し元次第</li>
<li>開発者に見えないところで自動的に<code>Main</code>が作られている</li>
</ul>
<p>例えば、ASP.NETの場合は前者、WPF アプリの場合は後者になります。</p>
<h2><a id="explicit-entry-point">エントリーポイントの指定</h2>
<p>1つのプログラムの中に複数のクラスがあって、
複数のクラスの中に<code>Main</code>関数がある場合、そのままではエントリーポイントを決定できず、コンパイル エラーになります。</p>
<p>この場合、どの<code>Main</code>関数を使うかをオプション指定できます。</p>
<p>参考:</p>
<ul>
<li><a href="https://msdn.microsoft.com/ja-jp/library/17k74w0c.aspx">方法 : アプリケーションのスタートアップ オブジェクトを変更する</a></li>
<li><a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/main-compiler-option">/main (C# Compiler Options</a></li>
</ul>
<h2><a id="async-main">非同期 Main</h2>
<h5 class="version version7_1">Ver. 7.1</h5>
<p>C# 7.1で、以下のように、<code>Main</code>関数の戻り値に<code>Task</code>クラス(<code>System.Threading.Tasks</code>名前空間)を使えるようになりました。</p>
<pre class="source" title="Main関数の引数と戻り値(C# 7.1 から)">
<code><span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; Main()
<span class="reserved">static</span> <span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; Main(<span class="reserved">string</span>[] args)
<span class="reserved">static</span> <span class="type">Task</span> Main()
<span class="reserved">static</span> <span class="type">Task</span> Main(<span class="reserved">string</span>[] args)
</code></pre>
<p>もちろん、<a href="http://ufcpp.net/study/csharp/sp5_async.html">非同期メソッド</a>を使えるようにするためです。
例えば以下のような<code>Main</code>関数が、ちゃんとエントリーポイントとして認識されます。</p>
<pre class="source" title="非同期Mainの例">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> Main()
{
    <span class="reserved">for</span> (<span class="reserved">int</span> i = 10; i &gt; 0; i--)
    {
        <span class="type">Console</span>.WriteLine(i);
        <span class="reserved">await</span> <span class="type">Task</span>.Delay(1000);
    }

    <span class="type">Console</span>.WriteLine(<span class="string">"done."</span>);
}
</code></pre>
<h3><a id="internal-async-main">非同期 Main の仕組み</h3>
<p>ちなみに、この機能は、コンパイラーが通常の(<code>void</code>/<code>int</code>戻り値の)エントリーポイントを別途自動生成することで実現しています。
例えば、先ほどの例のように、<code>Task Main()</code>を書くと、追加で以下のような関数が作られ、これが実際のエントリーポイントとして機能します。</p>
<pre class="source" title="非同期Mainから自動生成される通常のMain">
<code><span class="comment">// 実際には &lt;Main&gt; というような、C# で本来使えない名前で生成される</span>
<span class="reserved">static</span> <span class="reserved">void</span> _Main_(<span class="reserved">string</span>[] args)
{
    Main().GetAwaiter().GetResult();
}
</code></pre>
<p>中身は<code>GetAwaiter().GetResult()</code>を呼んでいるだけです。</p>
<h3><a id="compatibility">通常の Main がすでにある場合</h3>
<p>非同期 Main の仕様は C# 7.1 で追加されたものです。
そのため、これまでに書いたコードの中にすでに、エントリーポイントにするつもりがない <code>Task Main()</code> が含まれている場合に対する考慮が必要です。</p>
<p>C# 7.1 では、通常の(<code>void</code>/<code>int</code>戻り値の)<code>Main</code>関数がある場合、そちらだけをエントリーポイント扱いします。</p>
<pre class="source" title="Main の優先度">
<code><span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
{
    <span class="type">Console</span>.WriteLine(<span class="string">"こちらがエントリーポイント扱い"</span>);
}

<span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> Main()
{
    <span class="type">Console</span>.WriteLine(<span class="string">"void Main(string[]) がある限り、こちらは呼ばれない"</span>);
}
</code></pre> ]]></description>
				<pubDate>Sun, 11 Jun 2017 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 7 の新機能</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver7/</link>
				<description><![CDATA[ <h2><a id="ver7">C# 7</h2>
<div class="version version7">Ver. 7</div>
<table>
<tr>
<th>リリース時期</th>
<td>2017/3</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>Visual Studio 2017</li>
<li>Visual Basic 15</li>
</td>
</tr>
<tr>
<th>要約・目玉機能</ht>
<td>
<ul>
<li>タプル型</li>
<li>パターン マッチング</li>
</ul>
</td>
</tr>
</table>
<p>C# 6からは<a href="https://github.com/dotnet/roslyn">C#コンパイラーがオープンソース化</a>されたわけですが、
C# 6の言語仕様自体はオープン化前から大筋が決まっていました。
C# 7は、仕様を決めるかなり早い段階からすべてがオープンとなる初めてのバージョンになります。</p>
<p>C# 7以降のC#の大きなテーマとしては以下のようなものがあります。</p>
<ul>
<li>データ中心の設計</li>
<li>パフォーマンスや信頼性の向上</li>
</ul>
<p>C# 7にはその最初の一歩となる機能がいろいろと追加されています。
また、この大きなテーマ以外にも、こまごまとして改善が何点かあります。</p>
<h2><a id="data-centric">データ中心の設計</h2>
<p>伝統的なオブジェクト指向的な発想は多くの場面で有用ですが、別の発想を持つ方が好ましい場面もあります。
オブジェクト指向では、具体的なデータは隠蔽し、メソッド越しにデータを操作します。
振る舞い中心(behavior-centric)な設計になります。</p>
<p>一方で、関数型言語では、純粋なデータ(C#でいうとpublicなフィールドだけの構造体とか)を最初に用意して、
そのデータを変化させる関数を作ったりします。
データ中心(data-centric)な設計です。</p>
<p>この2者は相補的なものです。
C#はまだまだ前者(振る舞い中心)に寄っているので、もっと後者(データ中心)になじむ構文が必要になります。</p>
<p>C# 7では、タプルや型スイッチなどの機能が入ります。
これらは、将来的に、レコード型やパターン マッチングという、C# 8以降で検討されている機能につながっていきます。</p>
<h3><a id="tuple">タプル</h3>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/">名前のない複合型</a>」で説明しますが、
型には常によい名前が付くわけではなく、名無しにしておきたいことがあります。
そういう場合に使うもののうちの1つがC# 7で導入されたタプル(tuple)です。</p>
<p>タプルの最大の用途は<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/#multiple-returns">多値戻り値</a>です。
関数の戻り値は引数と対になるものなので、タプルの書き心地は引数に近くなるように設計されています。</p>
<p>例えば以下のように書けます。</p>
<pre class="source" title="タプルの例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="comment">// タプルを使って2つの戻り値を返す</span>
    <span class="reserved">static</span> <em>(<span class="reserved">int</span> count, <span class="reserved">int</span> sum)</em> Tally(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; items)
    {
        <span class="reserved">var</span> count = 0;
        <span class="reserved">var</span> sum = 0;
        <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> items)
        {
            sum += x;
            count++;
        }

        <span class="reserved">return</span> (count, sum);
    }

    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> data = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 };
        <span class="reserved">var</span> t = Tally(data);
        <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{t.sum}<span class="string">/</span>{t.count}<span class="string">"</span>);
    }
}
</code></pre>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/datatype/tuples/">タプル</a>」で説明します。</p>
<h3><a id="deconstruction">分解</h3>
<p>タプルは、メンバー名だけ見ればその型が何を意味するか分かるからこそ型に名前が付かないわけです。 このとき、その型を受け取る変数にも、よい名前が浮かばなくなるはずです。
実際、前節では<code>t</code>という特に意味のない名前の変数で値を受け取っています。</p>
<p>であれば、最初から、中身の<code>count</code>、 <code>sum</code>に分解して戻り値を受け取りたいです。
C# 7では、そのための分解構文(deconstruction)も追加されました。
前節のコードを、分解を使うように書き換えると以下のようになります。</p>
<pre class="source" title="タプルを分解して受け取る">
<code><span class="reserved">var</span> data = <span class="reserved">new</span>[] { 1, 2, 3, 4, 5 };
<em><span class="reserved">var</span> (count, sum)</em> = Tally(data);
<span class="type">Console</span>.WriteLine(<span class="string">$"</span>{sum}<span class="string">/</span>{count}<span class="string">"</span>);
</code></pre>
<p>ちなみに、分解はタプル専用の構文ではなく、以下のように、<code>Deconstruct</code>という名前のメソッド(拡張メソッドでも可)を持っている型なら何にでも使うことができます。</p>
<pre class="source" title="任意の型を分解する例">
<code><span class="reserved">using</span> System.Collections.Generic;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> (key, value) = <span class="reserved">new</span> <span class="type">KeyValuePair</span>&lt;<span class="reserved">string</span>, <span class="reserved">int</span>&gt;(<span class="string">"one"</span>, 1);
    }
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Extensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> <em>Deconstruct</em>&lt;<span class="type">T</span>, <span class="type">U</span>&gt;(<span class="reserved">this</span> <span class="type">KeyValuePair</span>&lt;<span class="type">T</span>, <span class="type">U</span>&gt; pair, <span class="reserved">out</span> <span class="type">T</span> key, <span class="reserved">out</span> <span class="type">U</span> value)
    {
        key = pair.Key;
        value = pair.Value;
    }
}
</code></pre>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/datatype/deconstruction/">分解</a>
」で説明します。</p>
<h3><a id="out-var">出力変数宣言</h3>
<p>タプルが入るまで、複数の戻り値を返すためには<a href="http://ufcpp.net/study/csharp/sp_ref.html#out">出力引数</a>を使っていました。</p>
<p>タプルが複数の戻り値を返す全く新しい手法なのに対して、
C# 7では既存の出力引数にも利便性向上のための機能が追加されました。
それが、出力変数宣言(out variable declaration。あるいは、略して out-var)です。</p>
<p>以下のように、out引数を受け取ると同時に、式の中で変数宣言できるようになりました。</p>
<pre class="source" title="out-var">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    <span class="reserved">public</span> <span class="reserved">int</span> Y { <span class="reserved">get</span>; <span class="reserved">set</span>; }

    <span class="reserved">public</span> <span class="reserved">void</span> GetCoordinate(<span class="reserved">out</span> <span class="reserved">int</span> x, <span class="reserved">out</span> <span class="reserved">int</span> y)
    {
        x = X;
        y = Y;
    }
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> p = <span class="reserved">new</span> <span class="type">Point</span> { X = 1, Y = 2 };
        p.GetCoordinate(<em><span class="reserved">out</span> <span class="reserved">var</span> x, <span class="reserved">out</span> <span class="reserved">var</span> y</em>);

        <span class="comment">// 以下のような書き方をしたのと同じ</span>
        <span class="comment">// int x, y;</span>
        <span class="comment">// p.GetCoordinate(out x, out y);</span>

        <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string">, </span>{y}<span class="string">"</span>);
    }
}
</code></pre>
<p>タプルが入っても、出力引数の方が使いやすい場面は残ります(参考: <a href="http://ufcpp.net/study/csharp/datatype/tuples/?p=3#out-params">出力引数との比較</a>)。
そういう意味では、出力変数宣言はタプルと相補的な関係にあります。</p>
<p>また、この構文は、将来的には前節で出てきた「<a href="http://ufcpp.net/study/csharp/datatype/deconstruction/">分解</a>
」や、次節で話す「<a href="http://ufcpp.net/study/csharp/datatype/typeswitch/">型スイッチ</a>」と統合されて、
パターン マッチングというより大きな機能に発展するものです。</p>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/sp_ref.html#out-var">出力変数宣言</a>」で説明します。</p>
<h3><a id="type-switch">型スイッチ</h3>
<p>C# 7で、<a href="http://ufcpp.net/study/csharp/oo_polymorphism.html?sec=downcast#is-operator"><code>is</code>演算子</a>や<a href="http://ufcpp.net/study/csharp/st_branch.html#switch"><code>switch</code>ステートメント</a>の<code>case</code>が拡張されて、以下のような機能が入りました。</p>
<ul>
<li><code>case</code>でも、<code>is</code>演算子と同じように、インスタンスの型を見ての分岐ができるようになった</li>
<li><code>x is T t</code>や、<code>case T t</code>というように、型を調べつつ、型が一致してたらキャスト結果を変数<code>t</code>で受け取れるようになった</li>
</ul>
<p>この機能を型スイッチ(type switch)と呼びます。
以下のような書き方ができます。</p>
<pre class="source" title="isとcaseの拡張の例">
<code><span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">string</span> <em>s</em>)
{
    <span class="type">Console</span>.WriteLine(<span class="string">"string #"</span> + s.Length);
}

<span class="reserved">switch</span> (obj)
{
    <span class="reserved">case</span> 7:
        <span class="type">Console</span>.WriteLine(<span class="string">"7の時だけここに来る"</span>);
        <span class="reserved">break</span>;
    <span class="reserved">case</span> <em><span class="reserved">int</span> n <span class="reserved">when</span> n &gt; 0</em>:
        <span class="type">Console</span>.WriteLine(<span class="string">"正の数の時にここに来る "</span> + n);
        <span class="comment">// ただし、上から順に判定するので、7 の時には来なくなる</span>
        <span class="reserved">break</span>;
    <span class="reserved">case</span> <em><span class="reserved">int</span> n</em>:
        <span class="type">Console</span>.WriteLine(<span class="string">"整数の時にここに来る"</span> + n);
        <span class="comment">// 同上、0 以下の時にしか来ない</span>
        <span class="reserved">break</span>;
    <span class="reserved">default</span>:
        <span class="type">Console</span>.WriteLine(<span class="string">"その他"</span>);
        <span class="reserved">break</span>;
}
</code></pre>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/datatype/typeswitch/">型スイッチ</a>」で説明します。</p>
<h4><a id="var-expressions">式の中での変数宣言</h4>
<p><a href="http://ufcpp.net/study/csharp/datatype/typeswitch/#is">is 演算子の拡張</a>と<a href="http://ufcpp.net/study/csharp/sp_ref.html#out-var">出力変数宣言</a>では、式の中で変数宣言ができます。
式は割かしどこにでも書けるものなので、これまで変数宣言できなかったような場所(それも、かなり無制限)で変数を宣言できるようになりました。</p>
<p>そこで問題になるのは、式の中で宣言した変数のスコープがどうなるかです。
そのスコープは「式を囲うブロック、埋め込みステートメント、for、foreach、using、 case内」ということになっています。</p>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/start/st_scope/?p=3#csharp7">is演算子の拡張と出力変数宣言で作った変数のスコープ</a>」を参照してください。</p>
<h3><a id="discard">値の破棄</h3>
<p>型スイッチや分解では、変数を宣言しつつ何らかの値を受け取るわけですが、 特に受け取る必要のない余剰の値が生まれたりします。</p>
<p>例えば、分解では、複数の値のうち、1つだけを受け取りたい場合があったとします。
こういう場合に、<code>_</code>を使うことで、値を受け取らずに無視することができます。</p>
<pre class="source" title="_ で値を破棄">
<code><span class="reserved">static</span> (<span class="reserved">int</span> quotient, <span class="reserved">int</span> remainder) DivRem(<span class="reserved">int</span> dividend, <span class="reserved">int</span> divisor)
    =&gt; (<span class="type">Math</span>.DivRem(dividend, divisor, <span class="reserved">out</span> <span class="reserved">var</span> remainder), remainder);

<span class="reserved">static</span> <span class="reserved">void</span> Deconstruct()
{
    <span class="comment">// 商と余りを計算するメソッドがあるけども、ここでは商しか要らない</span>
    <span class="comment">// _ を書いたところでは、値を受け取らずに無視する</span>
    <span class="reserved">var</span> (q, <span class="reserved">_</span>) = DivRem(123, 11);

    <span class="comment">// 逆に、余りしか要らない</span>
    <span class="comment">// また、本来「var x」とか変数宣言を書くべき場所にも _ だけを書ける</span>
    (_, <span class="reserved">var</span> r) = DivRem(123, 11);
}
</code></pre>
<p>同様の機能は、型スイッチや出力変数宣言でも使えます。</p>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/datatype/patternmatching/#discards">値の破棄</a>」を参照してください。</p>
<h2><a id="performance">パフォーマンス改善</h2>
<p>C#にとって一番重要視しているのは生産性の高さで、書きやすさ、読みやすさなどが一番大事です。
しかし、パフォーマンスへの配慮も大事です。いくら書きやすくても、出来上がったものがあまりにも遅いと言語の魅力は半減するでしょう。
そして、近年では、C#の用途も増え、パフォーマンスが求められる場面が増えています。
参考: <a href="http://www.buildinsider.net/column/iwanaga-nobuyuki/006">次期C#とパフォーマンス向上</a></p>
<p>それに、生産性を損なわずとも、パフォーマンス向上に関してできることもまだまだあるはずです。
そのため、C# 7では、パフォーマンス向上を目的とした新機能がいくつか入っています。</p>
<p>いくつかは、かつてマイクロソフト内で動いていた、<a href="https://ja.wikipedia.org/wiki/Midori_(%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0)">Midori</a>という研究プロジェクトの成果から来ているようです。
Midoriは、マネージ コードをベースとしたOSを作ろうというプロジェクトでした。
OSのような低レイヤーのソフトウェアを作る以上、パフォーマンスは非常に重要です。
プロジェクト自体は閉じられましたが、その成果は、.NETやC#に取り込まれようとしています。</p>
<p>C# 7で入るものの多くが、値型と参照渡しを活用したメモリ管理の効率化になります。</p>
<h3><a id="ref-returns">参照戻り値と参照ローカル変数</h3>
<p>戻り値とローカル変数でも参照渡しを使えるようになりました。 書き方はほぼ参照引数と同じです。 戻り値の型の前、値を渡す側、値を受ける側それぞれに<code>ref</code>修飾子を付けます。</p>
<pre class="source" title="参照戻り値と参照ローカル変数の例">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> x = 10;
        <span class="reserved">var</span> y = 20;

        <span class="comment">// x, y のうち、大きい方の参照を返す。この例の場合 y を参照。</span>
        <span class="reserved">ref</span> var m = <span class="reserved">ref</span> Max(<span class="reserved">ref</span> x, <span class="reserved">ref</span> y);

        <span class="comment">// 参照の書き換えなので、その先の y が書き換わる。</span>
        m = 0;

        <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string">, </span>{y}<span class="string">"</span>); <span class="comment">// 10, 0</span>
    }

    <span class="reserved">static</span> <span class="reserved">ref</span> <span class="reserved">int</span> Max(<span class="reserved">ref</span> <span class="reserved">int</span> x, <span class="reserved">ref</span> <span class="reserved">int</span> y)
    {
        <span class="reserved">if</span> (x &lt; y) <span class="reserved">return</span> <span class="reserved">ref</span> y;
        <span class="reserved">else</span> <span class="reserved">return</span> <span class="reserved">ref</span> x;
    }
}
</code></pre>
<p>詳しくは「<a href="http://ufcpp.net/study/csharp/sp_ref.html?p=2#ref-returns">参照戻り値と参照ローカル変数</a>」を参照してください。</p>
<p>この機能によって、大き目の値型を無駄なコピーなく取り扱えるようになって、パフォーマンスの向上が期待できます(参考: 「<a href="http://ufcpp.net/study/csharp/sp_ref.html?p=3#value-type">値型の参照渡し</a>」)。</p>
<h3><a id="local-functions">ローカル関数</h3>
<p>関数の中に入れ子で関数を書ける機能が追加されました。
入れ子の関数は、定義した関数の中でだけ使えます。
この機能をローカル関数と呼びます。</p>
<pre class="source" title="ローカル関数の例">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// Main 関数の中で、ローカル関数 f を定義</span>
        <em><span class="reserved">int</span> f(<span class="reserved">int</span> n) =&gt; n &gt;= 1 ? n * f(n - 1) : 1;</em>

        <span class="type">Console</span>.WriteLine(f(10));
    }
}
</code></pre>
<p>詳しくは、<a href="http://ufcpp.net/study/csharp/functional/fun_localfunctions/">ローカル関数と匿名関数</a>で説明します。</p>
<p>この機能はちょっとした利便性向上の機能ではありますが、
同時に、状況によってはラムダ式よりもパフォーマンスの良いコードが生成されるよう、最適化が掛かっています
(参考: <a href="http://ufcpp.net/study/csharp/sp2_anonymousmethod.html#closure-local-function">ローカル関数かつクロージャの場合</a>)。</p>
<h3><a id="tasklike">非同期メソッドの戻り値に任意の型を使えるように</h3>
<p>C# 6までは、<a href="http://ufcpp.net/study/csharp/sp5_async.html#async">非同期メソッド</a>の戻り値は、<code>void</code>か、<code>Task</code>、<code>Task&lt;TResult&gt;</code>クラス(<code>System.Threading.Tasks</code>名前空間)のいずれかである必要がありました。</p>
<p>これに対して、C# 7では、特定の条件を満たすように作れば、任意の型を非同期メソッドの戻り値として使えるようになりました。
最も有効と思われる例は、<code>ValueTask&lt;TResult&gt;</code>構造体(<code>System.Threading.Tasks</code>名前空間)です。
以下のようなコードが書けるようになります。</p>
<pre class="source" title="ValueTaskの例">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">ValueTask</span>&lt;<span class="reserved">int</span>&gt; XAsync(<span class="type">Random</span> r)
    {
        <span class="reserved">if</span> (r.NextDouble() &lt; 0.99)
        {
            <span class="comment">// 99% ここを通る。</span>
            <span class="comment">// この場合、await が1度もなく、非同期処理にならない。</span>
            <span class="comment">// 非同期処理じゃないのに Task&lt;int&gt; のインスタンスが作られるのはもったいない</span>
            <span class="reserved">return</span> 1;
        }

        <span class="comment">// こちら側は本当に非同期処理なので、Task&lt;int&gt; が必要。</span>
        <span class="reserved">await</span> <span class="type">Task</span>.Delay(100);
        <span class="reserved">return</span> 0;
    }
}
</code></pre>
<p>この例のように、大部分が実際には非同期処理を行わないような場合、都度<code>Task</code>クラスを作ってしまうと無駄なメモリ確保が必要になります。
それを避けるために使うのが<code>ValueTask</code>構造体です。</p>
<p>詳しくは、「<a href="http://ufcpp.net/study/csharp/sp5_async.html#task-like">Task-like</a>」を参照してください。</p>
<h2>その他、利便性向上</h2>
<p>その他、こまごまとした利便性向上がいくつかあります。
中には、C#チーム的に「要望があるのはわかるが、メリットは小さいので後回し」という位置づけになっていたものが、
チーム外からのPull Requestによって実装されたものもあります。</p>
<h3><a id="literals">数値リテラルの改善</h3>
<p>2進数リテラルが書けるようになりました。
また、数値リテラルの途中に、<code>_</code> を挟んで桁区切りに使えるようになりました。</p>
<pre class="source" title="数値リテラルがらみの新機能の例">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> M()
    {
        <span class="reserved">byte</span> bitMask = 0b1100_0000;
        <span class="type">Console</span>.WriteLine(bitMask); <span class="comment">// 192</span>

        <span class="reserved">uint</span> magicNumber = 0xDEAD_BEEF;
        <span class="type">Console</span>.WriteLine(magicNumber); <span class="comment">// 3735928559</span>
        <span class="type">Console</span>.WriteLine(magicNumber.ToString(<span class="string">"X"</span>)); <span class="comment">// DEADBEEF </span>
    }
}
</code></pre>
<p>詳しくは、「<a href="http://ufcpp.net/study/csharp/start/stnumber/#binary">2進数リテラル</a>」や「<a href="http://ufcpp.net/study/csharp/start/stnumber/#digit-separator">数字区切り文字</a>」を参照してください。</p>
<h3><a id="throw-expression">throw 式</h3>
<p>以下の3つの場面に限ってですが、式の中に<code>throw</code>を書けるようになりました。</p>
<ul>
<li><a href="http://ufcpp.net/study/csharp/sp3_lambda.html#lambda">ラムダ式</a>や<a href="http://ufcpp.net/study/csharp/st_function.html#sec-expression-bodied">式形式メンバー</a>の中(<code>=&gt;</code> の後ろ)</li>
<li><a href="http://ufcpp.net/study/csharp/sp2_nullable.html#nullableType">null合体演算子</a>(<code>??</code>)の後ろ</li>
<li><a href="http://ufcpp.net/study/csharp/oo_exception.html">条件演算子</a>の第2、第3引数(条件式以外の部分。 <code>:</code> の前後)</li>
</ul>
<pre class="source" title="throw 式">
<code><span class="comment">// 式形式メンバーの中( =&gt; の直後)</span>
<span class="reserved">static</span> <span class="reserved">void</span> A() =&gt; <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">NotImplementedException</span>();

<span class="reserved">static</span> <span class="reserved">string</span> B(<span class="reserved">object</span> obj)
{
    <span class="comment">// null 合体演算子(??)の後ろ</span>
    <span class="reserved">var</span> s = obj <span class="reserved">as</span> <span class="reserved">string</span> ?? <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">ArgumentException</span>(<span class="reserved">nameof</span>(obj));

    <span class="comment">// 条件演算子(?:)の条件以外の部分</span>
    <span class="reserved">return</span> s.Length == 0 ? <span class="string">"empty"</span> :
        s.Length &lt; 5 ? <span class="string">"short"</span> :
        <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">InvalidOperationException</span>(<span class="string">"too long"</span>);
}
</code></pre>
<p>詳しくは、「<a href="http://ufcpp.net/study/csharp/oo_exception.html#throwexpr">throw式</a>」を参照してください。</p>
<h3><a id="throw-expression">式形式のメンバーの拡充</h3>
<p>C# 6で、メソッド、演算子、プロパティとインデクサー(get-only)に対して、式が1つだけの場合に<code>=&gt;</code>を使った略記法が追加されました。</p>
<p>これが、C# 7では、コンストラクター、ファイナライザー、プロパティとインデクサー(get/set それぞれ)、イベント(add/removeそれぞれ)でも使えるようになりました。
例えば、コンストラクターとファイナライザーであれば以下のように書けます。</p>
<pre class="source" title="コンストラクター、ファイナライザーを式形式で定義する例。">
<code><span class="reserved">class</span> <span class="type">Counter</span>
{
    <span class="reserved">static</span> <span class="reserved">int</span> x;

    <span class="comment">// コンストラクター</span>
    Counter() =&gt; x++;

    <span class="comment">// ファイナライザー</span>
    ~Counter() =&gt; x--;
}
</code></pre>
<p>詳しくは、「<a href="http://ufcpp.net/study/csharp/st_function.html#sec-expression-bodied">expression-bodiedメンバーの拡充</a>」を参照してください。</p>
 ]]></description>
				<pubDate>Sun, 30 Oct 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>タプル</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/tuples/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version7">Ver. 7</h5>
<p>「<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/">名前のない複合型</a>」で説明したように、
型には常によい名前が付くわけではなく、名無しにしておきたいことがあります。
そういう場合に使うもののうちの1つがC# 7で導入されたタプルです。</p>
<p>タプルの最大の用途は<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/#multiple-returns">多値戻り値</a>です。
関数の戻り値は引数と対になるものなので、タプルの書き心地は引数に近くなるように設計されています。</p>
<h4>ポイント</h4>
<ul>
<li><code>(int x, int y)</code>というような、引数みたいな書き方で「名前のない型」を作れます</li>
<li>この書き方をタプルと呼びます</li>
</ul>
<h2><a id="tuple">タプル</h2>
<p>C# 7で導入された<strong id="key-tuple" class="keyword">タプル</strong>(tuple)は、
<code>(int x, int y)</code>というような、引数みたいな書き方で「名前のない型」を作る機能です。</p>
<p>※ タプルの利用には、<code>ValueTuple</code>構造体という型が必要になります。
この型が標準ライブラリに取り込まれるのは .NET Framework 4.7、.NET Standard 1.7を予定しています。
それ以前のバージョンでタプルを使いたい場合には、以下のパッケージを参照する必要があります。</p>
<ul>
<li><a href="https://www.nuget.org/packages/System.ValueTuple/">System.ValueTuple</a></li>
</ul>
<h3><a id="name">タプルという名前</h3>
<p>最初に例を挙げた<code>(int x, int y)</code>という書き方は、2つの<code>int</code>の値<code>x</code>と<code>y</code>を並べたものなわけですが、こういう「データを複数並べたもの」を意味する単語がタプルです。</p>
<p>英語では倍数を「double, triple, quadruple, ...」などという単語で表しますが、これを一般化して n-tuple (nは0以上の任意の整数)と書くことがあり、これがタプルの語源です。
n倍、n重、n連結というような意味しかなく、まさに「名前のない複合型」にピッタリの単語です。</p>
<h3><a id="denotation">型の明示</h3>
<p><code>(int x, int y)</code>みたいな書き方で、1つの型を表します。
タプルの型の書き方はメソッドの仮引数リスト(引数を受け取る側の書き方)に似ていて、<code>()</code>の中に「型名 メンバー名」を <code>,</code> 区切りで並べます。</p>
<p>これは、型を書ける場所であれば概ねどこにでもこの「型」を書けます。
まず、以下のように、フィールドや戻り値などの型にできます。</p>
<pre class="source" title="フィールドや戻り値の型にタプルを使う">
<code><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">private</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) value;
    <span class="reserved">public</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) GetValue() =&gt; value;
}
</code></pre>
<p>以下のように、ローカル変数の型としても明示できます。</p>
<pre class="source" title="明示的にローカル変数の型をタプル型にする">
<code><reserved></span><span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>();
(<span class="reserved">int</span> x, <span class="reserved">int</span> y) t = s.GetValue();
</code></pre>
<p>もちろん、<code>var</code>を使った型推論も効きます。</p>
<p><img src="/media/1091/tuplelocalinference.png" alt="varで型推論" /></p>
<p>また、ジェネリックな型の型引数にも使えます。</p>
<pre class="source" title="型引数にタプルを使う">
<code><span class="reserved">var</span> dic = <span class="reserved">new</span> <span class="type">Dictionary</span>&lt;(<span class="reserved">string</span> s, <span class="reserved">string</span> t), (<span class="reserved">int</span> x, <span class="reserved">int</span> y)&gt;
{
    { (<span class="string">"a"</span>, <span class="string">"b"</span>), (1, 2) },
    { (<span class="string">"x"</span>, <span class="string">"y"</span>), (4, 8) },
};

<span class="type">Console</span>.WriteLine(dic[(<span class="string">"a"</span>, <span class="string">"b"</span>)]); <span class="comment">// (1, 2)</span>
</code></pre>
<h3><a id="denotation-disallowed">制限事項</h3>
<p>ただ、いくつか、通常の型であれば書ける場所で、タプルのこの記法を使えないところがあります。
以下の3つです。</p>
<ul>
<li><code>new</code>演算子</li>
<li><code>is</code>演算子 (C# 8.0 以降は使えるようになった)</li>
<li><code>using</code>ディレクティブ (これは将来的に認められる可能性あり)</li>
</ul>
<p>例えば以下のコードはコンパイル エラーを起こします。</p>
<pre class="source" title="タプル型を掛けない場所">
<code><span class="comment">// using でエイリアスを付けることはできない</span>
<span class="reserved">using</span> T = (<span class="reserved">int</span> x, <span class="reserved">int</span> y);

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// var t = new T(1, 2); みたいなのと同じノリでは書けない</span>
        <span class="reserved">var</span> t1 = <span class="reserved">new</span> <span class="error">(<span class="reserved">int</span> x, <span class="reserved">int</span> y)</span>(1, 2);
        <span class="reserved">var</span> t2 = <span class="reserved">new</span> <span class="error">(<span class="reserved">int</span> x, <span class="reserved">int</span> y)</span> { x = 1, y = 2 };
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">object</span> obj)
    {
        <span class="comment">// (C# 7.3 までは) is 演算子には使えない</span>
        <span class="reserved">if</span>(obj <span class="reserved">is</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y))
        {
        }
    }
}
</code></pre>
<p>ただし、以下のように、配列やnull許容型を作る場合には<code>new</code>を使えます。</p>
<pre class="source" title="">
<code><span class="reserved">var</span> a = <span class="reserved">new</span>(<span class="reserved">int</span> x, <span class="reserved">int</span> y)[10]; <span class="comment">// OK</span>
<span class="reserved">var</span> n = <span class="reserved">new</span>(<span class="reserved">int</span> x, <span class="reserved">int</span> y)?();  <span class="comment">// OK</span>
</code></pre>
<p><code>new (int x, int y)</code>という書き方は、将来的な言語拡張の予定と被る(被ってしまったら将来の拡張ができない)ため禁止しているようです。
<code>is</code>演算子は、C# 8.0で入った<a href="/study/csharp/datatype/patterns/?p=2#positional">位置パターン</a>との競合を懸念して、C# 8.0までは認めていませんでした。</p>
<pre class="source" title="将来的な拡張予定">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> ticks = 100000;
        <span class="comment">// (予定。C#7 ではできない) C# 8?</span>
        <span class="type">DateTime</span> d = <span class="reserved">new</span>(ticks); <span class="comment">// 左辺から型推論して、new DateTime(ticks) が呼ばれる</span>
    }

    <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">object</span> obj)
    {
        <span class="comment">// C# 8.0 で入った構文</span>
        <span class="comment">// is T 扱いじゃなくて、位置パターンで obj を x, y に分解</span>
        <span class="reserved">if</span> (obj <span class="reserved">is</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y))
        {
            <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string">, </span>{y}<span class="string">"</span>);
        }
    }
}
</code></pre>
<p>また、タプルのメンバーは2つ以上である必要があります。<code>()</code>や<code>(int x)</code>というようなタプルは現在の仕様では作れません。</p>
<pre class="source" title="0-tuple, 1-tuple は書けない">
<code>() noneple;     <span class="comment">// ダメ</span>
(<span class="reserved">int</span> x) oneple; <span class="comment">// ダメ</span>

<span class="comment">// タプル構文で書けるのは2つ以上だけ</span>
(<span class="reserved">int</span> x, <span class="reserved">int</span> y) twople; <span class="comment">// OK</span>

<span class="comment">// タプル構文でなければ、0-tuple, 1-tuple も作れる</span>
<span class="type">ValueTuple</span> none;     <span class="comment">// OK</span>
<span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>&gt; one; <span class="comment">// OK</span>
</code></pre>
<h3><a id="literal">タプル リテラル</h3>
<p>タプルは<code>(1, 2)</code>というような書き方で<a href="http://ufcpp.net/study/csharp/st_variable.html#literal">リテラル</a>を書くことができます。
タプル リテラルは実引数リスト(引数を渡す側の書き方)に似ています。</p>
<pre class="source" title="タプル リテラル">
<code><span class="comment">// メソッド呼び出し時の F(1, 2); みたいなノリ</span>
(<span class="reserved">int</span> x, <span class="reserved">int</span> y) t1 = (1, 2);

<span class="comment">// メソッド呼び出し時の F(x: 1, y: 2); みたいなノリ</span>
<span class="reserved">var</span> t2 = (x: 1, y: 2);
</code></pre>
<p><code>null</code>のように単体では型が決まらないものも、左辺に型があれば推論が効きます。
一方で、左辺も<code>var</code>等になっていて型が決まらない場合、コンパイル エラーになります。</p>
<pre class="source" title="">
<code><span class="comment">// これは左辺から型推論が聞くので、null も書ける</span>
(<span class="reserved">string</span> s, <span class="reserved">int</span> i) t1 = (<span class="reserved">null</span>, 1);

<span class="comment">// これはダメ。null の型が決まらない。</span>
<span class="reserved">var</span> t2 = (<span class="reserved">null</span>, 1); <span class="comment">// コンパイル エラー</span>
</code></pre>
<h3><a id="member-access">メンバー参照</h3>
<p>メンバーの参照の仕方は普通の型と変わりません。<code>(int x, int y)</code>であれば、<code>x</code>、<code>y</code>という名前でアクセスできます。
ちなみに、タプルのメンバーは書き換え可能です。</p>
<pre class="source" title="タプルのメンバー参照">
<code><span class="reserved">var</span> t = (x: 1, y: 2);
<span class="type">Console</span>.WriteLine(t.x); <span class="comment">// 1</span>
<span class="type">Console</span>.WriteLine(t.y); <span class="comment">// 2</span>

<span class="comment">// メンバーごとに書き換え可能</span>
t.x = 10;
t.y = 20;
<span class="type">Console</span>.WriteLine(t.x); <span class="comment">// 10</span>
<span class="type">Console</span>.WriteLine(t.y); <span class="comment">// 20</span>

<span class="comment">// タプル自身も書き換え可能</span>
t = (100, 200);
<span class="type">Console</span>.WriteLine(t.x); <span class="comment">// 100</span>
<span class="type">Console</span>.WriteLine(t.y); <span class="comment">// 200</span>
</code></pre>
<p>ちなみに、タプルのメンバーはフィールドになっています
(プロパティではない)。
フィールドになっているということは、例えば、<a href="http://ufcpp.net/study/csharp/sp_ref.html#sec-byref">参照引数(<code>ref</code>)</a>に直接渡せます
(これが、プロパティだと無理)。</p>
<p>例えば以下のようなメソッドがあったとします。</p>
<pre class="source" title="Swapメソッド">
<code><span class="reserved">static</span> <span class="reserved">void</span> Swap&lt;<span class="type">T</span>&gt;(<span class="reserved">ref</span> <span class="type">T</span> x, <span class="reserved">ref</span> <span class="type">T</span> y)
{
    <span class="reserved">var</span> t = x;
    x = y;
    y = t;
}
</code></pre>
<p>このとき、以下のようにタプルのメンバーを渡せます。</p>
<pre class="source" title="タプルのメンバーを参照引数に渡す">
<code><span class="reserved">var</span> t = (x: 1, y: 2);
Swap(<span class="reserved">ref</span> t.x, <span class="reserved">ref</span> t.y);
<span class="type">Console</span>.WriteLine(t.x); <span class="comment">// 2</span>
<span class="type">Console</span>.WriteLine(t.y); <span class="comment">// 1</span>
</code></pre>
<h3><a id="deconstruction">タプルの分解</h3>
<p>タプルは、各メンバーを分解して、それぞれ別の変数に受けて使うことができます。</p>
<pre class="source" title="タプルの分解">
<code><span class="reserved">var</span> t = (x: 1, y: 2);

<span class="comment">// 分解宣言1</span>
(<span class="reserved">int</span> x1, <span class="reserved">int</span> y1) = t; <span class="comment">// x1, y1 を宣言しつつ、ｔ を分解</span>
<span class="comment">// 分解宣言2</span>
<span class="reserved">var</span> (x2, y2) = t; <span class="comment">// 分解宣言の簡易記法</span>

<span class="comment">// 分解代入</span>
<span class="reserved">int</span> x, y;
(x, y) = t; <span class="comment">// 分解結果を既存の変数に代入</span>
</code></pre>
<p>この分解は、タプル以外の型に対しても使えるものです。
詳しくは「<a href="http://ufcpp.net/study/csharp/data/deconstruction/">複合型の分解</a>」で説明します。</p>
<h3><a id="conversion">タプル間の変換</h3>
<p>タプル間の代入は、一定の条件下では暗黙的変換が掛かります。</p>
<h4><a id="different-names">名前違いのタプル</h4>
<p>タプル間の代入は、メンバーの宣言位置に基づいて行われます。
逆に言うと、名前は無関係で、メンバーの型の並びだけ一致していれば代入できます。</p>
<p>例えば以下のように書くと、1番目同士(<code>x</code> → <code>s</code>)、2番目同士(<code>y</code> → <code>t</code>)で値が代入されます。</p>
<pre class="source" title="">
<code>(<span class="reserved">int</span> s, <span class="reserved">int</span> t) t1 = (x: 1, y: 2);
<span class="type">Console</span>.WriteLine(t1.s); <span class="comment">// 1</span>
<span class="type">Console</span>.WriteLine(t1.t); <span class="comment">// 2</span>
</code></pre>
<p>同名であっても、位置が優先です。以下のような書き方をすると、<code>x</code>、<code>y</code>が入れ替わります。</p>
<pre class="source" title="">
<code>(<span class="reserved">int</span> y, <span class="reserved">int</span> x) t2 = (x: 1, y: 2);
<span class="type">Console</span>.WriteLine(t2.x); <span class="comment">// 2</span>
<span class="type">Console</span>.WriteLine(t2.y); <span class="comment">// 1</span>
</code></pre>
<h4><a id="different-types">型違いのタプル</h4>
<p>タプルのメンバーの型が違う場合、メンバーごとに調べて、すべてのメンバーで暗黙的な変換がかかる場合に限り、
タプル間の暗黙的変換ができます。</p>
<p>例えば以下の場合、<code>x</code>も<code>y</code>も<code>z</code>も、それぞれが型変換できるので、タプルの暗黙的型変換が掛かります。</p>
<pre class="source" title="タプル間の暗黙の型変換">
<code><span class="reserved">object</span> x = <span class="string">"abc"</span>; <span class="comment">// string → object は OK</span>
<span class="reserved">long</span> y = 1; <span class="comment">// int → long は OK</span>
<span class="reserved">int</span>? z = 2; <span class="comment">// int → int? は OK</span>
<span class="comment">// ↓</span>
(<span class="reserved">object</span> x, <span class="reserved">long</span> y, <span class="reserved">int</span>? z) t = (<span class="string">"abc"</span>, 1, 2); <span class="comment">// OK</span>
</code></pre>
<p>逆に、以下の場合はコンパイル エラーになります。この例では全部のメンバーが変換不能ですが、全部でなくても、どれか1つでも変換できないと、タプル自体の変換もエラーになります。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">string</span> x = 1; <span class="comment">// int → string は NG</span>
<span class="reserved">int</span> y = 1L; <span class="comment">// long → int は NG</span>
<span class="reserved">int</span> z = <span class="reserved">default</span>(<span class="reserved">int</span>?); <span class="comment">// int? → int は NG</span>
<span class="comment">// ↓</span>
(<span class="reserved">string</span> x, <span class="reserved">int</span> y, <span class="reserved">int</span> z) t = (1, 1L, <span class="reserved">default</span>(<span class="reserved">int</span>?)); <span class="comment">// NG</span>
</code></pre>
<h4><a id="extensions">拡張メソッドの解決</h4>
<p>前節のような型違いのタプル間の変換は、拡張メソッドのオーバーロード解決の際にも働きます。</p>
<p>例えば以下のように、配列×2のタプルに対して、<code>IEnumerable</code>×2のタプルの拡張メソッドを呼べます。
(配列から<code>IEnumerable</code>への変換は暗黙的に行えるので、このタプル間の変換も暗黙的に行えます。)</p>
<pre class="source" title="">
<code><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Linq;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">int</span>[] a1 = <span class="reserved">new</span>[] { 1, 2, 3 };
        <span class="reserved">string</span>[] a2 = <span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"b"</span>, <span class="string">"c"</span> };

        <span class="comment">// 配列 ×2のタプルに対して、IEnumerable ×2のタプルの拡張メソッドを呼べる</span>
        <span class="reserved">foreach</span> (<span class="reserved">var</span> (i, s) <span class="reserved">in</span> (a1, a2).Zip())
        {
            <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{i}<span class="string">: </span>{s}<span class="string">"</span>);
        }
    }
}

<span class="reserved">static</span> <span class="reserved">class</span> <span class="type">TupelExtensions</span>
{
    <span class="comment">// IEnumerable ×2 に対する拡張メソッド</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;(<span class="type">T1</span> x1, <span class="type">T2</span> x2)&gt; Zip&lt;<span class="type">T1</span>, <span class="type">T2</span>&gt;(<span class="reserved">this</span> (<span class="type">IEnumerable</span>&lt;<span class="type">T1</span>&gt; items1, <span class="type">IEnumerable</span>&lt;<span class="type">T2</span>&gt; items2) t)
        =&gt; t.items1.Zip(t.items2, (x1, x2) =&gt; (x1, x2));
}
</code></pre>
<h3><a id="nest">タプルの入れ子</h3>
<p>タプルは入れ子にできます。</p>
<pre class="source" title="タプルの入れ子">
<code><comment></span><span class="comment">// タプルの入れ子</span>
(<span class="reserved">string</span> a, (<span class="reserved">int</span> x, <span class="reserved">int</span> y) b) t1 = (<span class="string">"abc"</span>, (1, 2));
<span class="type">Console</span>.WriteLine(t1.a);   <span class="comment">// abc</span>
<span class="type">Console</span>.WriteLine(t1.b.x); <span class="comment">// 1</span>
<span class="type">Console</span>.WriteLine(t1.b.y); <span class="comment">// 2</span>

<span class="comment">// 型推論も可能</span>
<span class="reserved">var</span> t2 = (a: <span class="string">"abc"</span>, b: (x: 1, y: 2));
</code></pre>
<h3><a id="anonymous-member">メンバー名も匿名</h3>
<p>タプルは、メンバー名もなくして、完全に匿名(名無し)にすることもできます。
この場合、メンバーを使う際には<code>Item1</code>、<code>Item2</code>、…というような名前で参照します。</p>
<pre class="source" title="メンバー名も匿名なタプル">
<code><reserved></span><span class="reserved">var</span> t1 = (1, 2);
<span class="type">Console</span>.WriteLine(t1.Item1); <span class="comment">// 1</span>
<span class="type">Console</span>.WriteLine(t1.Item2); <span class="comment">// 2</span>
</code></pre>
<p><code>Item1</code>、<code>Item2</code>、… という名前は、後述する<code>ValueTuple</code>構造体のメンバー名です。</p>
<p>冒頭や「<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/">名前のない複合型</a>」で説明したように、
「メンバー名だけ見れば十分」だから型名を省略するのであって、
メンバー名まで省略するのとさすがにプログラムが読みづらくなります。
メンバー名も持っていない完全な匿名タプルは、おそらくかなり短い寿命でしか使わないでしょう。
例えば、すぐに別の(メンバー名のある)タプル型に代入したり、分解して変数に受けて使うことになります。</p>
<h3><a id="overload">オーバーロード</h3>
<p>型違いのタプルを使うのであれば、オーバーロードに使えます。
例えば、以下のメソッド<code>F</code>は、<code>y</code>の型が違うのでオーバーロード可能です。</p>
<pre class="source" title="型違いのタプルでのオーバーロードは可能">
<code><span class="comment">// 型違いのタプルでのオーバーロードは可能</span>
<span class="reserved">void</span> F((<span class="reserved">int</span> x, <span class="reserved">int</span> y) t) { }
<span class="reserved">void</span> F((<span class="reserved">int</span> x, <span class="reserved">string</span> y) t) { }
</code></pre>
<p>一方、型が一緒で名前だけが違うタプルではオーバーロードできません。
以下のメソッド<code>G</code>は、同じものが2つあるのでコンパイル エラーを起こします。</p>
<pre class="source" title="">
<code><span class="comment">// 型が一緒で名前だけ違うタプルでのオーバーロードはダメ。コンパイル エラー</span>
<span class="reserved">void</span> G((<span class="reserved">int</span> x, <span class="reserved">int</span> y) t) { }
<span class="reserved">void</span> G((<span class="reserved">int</span> a, <span class="reserved">int</span> b) t) { }
</code></pre>
<p>こういう仕様になっている理由は2つあります。
1つは、次節で説明するように、内部実装的に名前だけ違うタプルを区別できないという、技術的な理由。
もう1つは、<a href="http://ufcpp.net/study/csharp/st_function.html#overload">引数でのオーバーロード</a>が名前を見ていない(引数の型だけがシグネチャに含まれる)のだから、引数に倣って設計されているタプルでも、メンバー名は区別しないのが自然という理由です。</p>
<h3><a id="infer-tuple-name">タプル要素名の推論</h3>
<h5 class="version version7_1">Ver. 7.1</h5>
<p>C# 7.1から、タプル構築時に渡した変数からタプルの要素名を推論できるようになりました。
例えば以下のように、<code>(x, y)</code> と書くだけで、1要素目に<code>x</code>、2要素目に <code>y</code> という名前が付きます。
(これまでだと、<code>(x: x, y: y)</code> と書く必要がありました。)</p>
<pre class="source" title="タプル要素名の推論の例">
<code><span class="reserved">var</span> x = 1;
<span class="reserved">var</span> y = 2;
<span class="reserved">var</span> t = (x, y);

<span class="comment">// C# 7.0。t の要素には名前が付かない</span>
<span class="type">Console</span>.WriteLine(t.Item1);
<span class="type">Console</span>.WriteLine(t.Item2);

<span class="comment">// C# 7.1。(x, y) で (x: x, y: y) 扱い</span>
<span class="comment">// t の要素に x, y という名前が付く</span>
<span class="type">Console</span>.WriteLine(t.x);
<span class="type">Console</span>.WriteLine(t.y);
</code></pre>
<p>以下のように、部分的な適用もされます。</p>
<pre class="source" title="タプル要素名の部分的な推論">
<code><span class="reserved">var</span> y = 2;
<span class="reserved">var</span> t = (1, y);
<span class="type">Console</span>.WriteLine(t.Item1); <span class="comment">// 1</span>
<span class="type">Console</span>.WriteLine(t.y);     <span class="comment">// 2</span>
</code></pre>
<p>ただし、名前に被りがあるときには推論が働きません。</p>
<pre class="source" title="名前被りでタプル要素名の推論ができない例">
<code><span class="reserved">var</span> x = 1;
<span class="reserved">var</span> t = (x, x);
<span class="type">Console</span>.WriteLine(t.Item1); <span class="comment">// t.x とは書けない</span>
<span class="type">Console</span>.WriteLine(t.Item2); <span class="comment">// こっちも t.x とは書けない</span>

<span class="reserved">var</span> u = (x: 0, x);
<span class="type">Console</span>.WriteLine(u.x); <span class="comment">// u.x というと Item1 の方</span>
<span class="type">Console</span>.WriteLine(u.Item2); <span class="comment">// Item2 の方は x とは書けない</span>
</code></pre>
<p>名前がないので当然ですが、リテラルからは要素名の推論はできません</p>
<pre class="source" title="リテラルからは推論不可">
<code><span class="reserved">var</span> t = (1, 2);
<span class="type">Console</span>.WriteLine(t.Item1); <span class="comment">// さすがに t.1 とかは書けない</span>
</code></pre>
<p>また、メソッド名からは推論されません。
一方で、プロパティ名からは推論されます。
プロパティやフィールドの場合、インスタンス メンバーへのアクセスでも推論されます
(<code>t.x</code>とかなら、タプル要素名は<code>x</code>になります。<code>t?.x</code>でも可)。</p>
<pre class="source" title="メソッド不可、プロパティ可。インスタンス メンバー アクセス可。null 条件演算子可">
<code><span class="reserved">int</span> F() =&gt; 1;
<span class="reserved">var</span> s = <span class="string">"abc"</span>;

<span class="reserved">var</span> t = (F(), s?.Length);
<span class="type">Console</span>.WriteLine(t.Item1); <span class="comment">// メソッド名からは推論されない(t.F はダメ)</span>
<span class="type">Console</span>.WriteLine(t.Length); <span class="comment">// プロパティ名からは推論される( . でも ?. でも OK)</span>
</code></pre>
<h3><a id="equality">==、!= での比較</h3>
<h5 class="version version7">Ver. 7.3</h5>
<p>C# 7.3で、タプル同士を <code>==</code>、<code>!=</code> 演算子で比較できるようになりました。</p>
<p>これは、後述する<a href="?p=2#tuple-ValueTuple"><code>ValueTuple</code></a>の演算子が呼ばれるわけではなく、
コンパイラーによる特別な処理が入ります。</p>
<p>タプルに対する<code>==</code>比較は、以下のように、メンバーごとの<code>==</code>を<a href="/study/csharp/st_operator.html#short-circuit"><code>&amp;&amp;</code></a>で繋いだものに展開されます。</p>
<pre class="source" title="タプル ==">
<code><span class="reserved">void</span> M((<span class="reserved">int</span> a, (<span class="reserved">int</span> x, <span class="reserved">int</span> y) b) t)
{
    <span class="comment">// このタプル == 比較は、</span>
    <span class="type">Console</span>.WriteLine(t == (1, (2, 3)));
    <span class="comment">// こんな感じで、メンバーごとの == を &amp;&amp; で繋いだものに展開される。</span>
    <span class="type">Console</span>.WriteLine(t.a == 1 &amp;&amp; t.b.x == 2 &amp;&amp; t.b.y == 3);
}
</code></pre>
<p>同様に、<code>!=</code>は以下のように、メンバーごとの<code>!=</code>を<a href="/study/csharp/st_operator.html#short-circuit"><code>||</code></a>で繋いだものになります。</p>
<pre class="source" title="タプル !=">
<code><span class="reserved">void</span> N((<span class="reserved">int</span> a, (<span class="reserved">int</span> x, <span class="reserved">int</span> y) b) t)
{
    <span class="comment">// 同じく != 比較は、</span>
    <span class="type">Console</span>.WriteLine(t != (1, (2, 3)));
    <span class="comment">// こんな感じで、メンバーごとの != を || で繋いだものに展開される。</span>
    <span class="type">Console</span>.WriteLine(t.a != 1 || t.b.x != 2 || t.b.y != 3);
}
</code></pre>
<p><code>ValueTuple</code>の<code>==</code>演算子や<code>Equals</code>メソッドではなくこういうコンパイラーによる処理が入っているのは、
「<a href="/study/csharp/datatype/tuples/#conversion">タプル間の変換</a>」で説明したような、メンバーごとの型変換を考慮してのことです。
例えば、以下のように、暗黙的型変換ができるもの同士の比較ができます。</p>
<pre class="source" title="">
<code>(<span class="reserved">long</span> a, (<span class="reserved">double</span> x, <span class="reserved">decimal</span> y) b) t = (1, (2, 3));

<span class="comment">// byte → long</span>
<span class="comment">// float → double</span>
<span class="comment">// short → decimal</span>
<span class="comment">// という、暗黙的型変換ができるもの同士の比較</span>
<span class="type">Console</span>.WriteLine(t == ((<span class="reserved">byte</span>)1, ((<span class="reserved">float</span>)2, (<span class="reserved">short</span>)3)));
</code></pre>
<p>ちなみに、<a href="/study/csharp/oo_operator.html">ユーザー定義</a>の<code>==</code>、<code>!=</code>演算子を持っている場合、そのユーザー定義のものが呼ばれます。
また、ユーザー定義であれば<code>==</code>が<code>bool</code>以外の型を返すこともありますが、
その場合も、<a href="/study/csharp/oo_operator.html#true-false"><code>true</code>、<code>false</code>演算子</a>があれば比較できます。</p>
<pre class="source" title="ユーザー定義の ==, !=, true, false が呼ばれる例">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">MyBool</span>
{
    <span class="reserved">public</span> <span class="reserved">bool</span> Value;
    <span class="reserved">public</span> <span class="type">MyBool</span>(<span class="reserved">bool</span> value) =&gt; Value = value;

    <span class="comment">// 何が呼ばれてるかがわかるように WriteLine を挟む</span>
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="reserved">operator</span> <span class="reserved">true</span>(<span class="type">MyBool</span> x) { <span class="type">Console</span>.WriteLine(<span class="string">"MyBool.true"</span>); <span class="reserved">return</span> x.Value; }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">bool</span> <span class="reserved">operator</span> <span class="reserved">false</span>(<span class="type">MyBool</span> x) { <span class="type">Console</span>.WriteLine(<span class="string">"MyBool.false"</span>); <span class="reserved">return</span> !x.Value; }
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="type">MyBool</span>(<span class="reserved">bool</span> b) =&gt; <span class="reserved">new</span> <span class="type">MyBool</span>(b);
}

<span class="reserved">struct</span> <span class="type">MyInt</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> Value;
    <span class="reserved">public</span> MyInt(<span class="reserved">int</span> value) =&gt; Value = value;
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">MyBool</span> <span class="reserved">operator</span> ==(<span class="type">MyInt</span> x, <span class="type">MyInt</span> y) =&gt; x.Value == y.Value;
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">MyBool</span> <span class="reserved">operator</span> !=(<span class="type">MyInt</span> x, <span class="type">MyInt</span> y) =&gt; x.Value != y.Value;
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">implicit</span> <span class="reserved">operator</span> <span class="type">MyInt</span>(<span class="reserved">int</span> b) =&gt; <span class="reserved">new</span> <span class="type">MyInt</span>(b);
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">bool</span> Equals(<span class="reserved">object</span> obj) =&gt; obj <span class="reserved">is</span> <span class="type">MyInt</span> x &amp;&amp; Value == x.Value;
    <span class="reserved">public</span> <span class="reserved">override</span> <span class="reserved">int</span> GetHashCode() =&gt; Value.GetHashCode();
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        (<span class="type">MyInt</span> a, (<span class="type">MyInt</span> x, <span class="type">MyInt</span> y) b) t = (1, (2, 3));

        <span class="comment">// MyInt の == に展開されるので、MyBool が得られる。</span>
        <span class="comment">// MyBool 同士の &amp;&amp; で、MyBool の false 演算子が呼ばれる。</span>
        <span class="comment">// (この例の場合、"MyBool.false" が3回表示される。)</span>
        <span class="comment">// (false の方が呼ばれるのは C# の &amp;&amp; の仕様。)</span>
        <span class="type">Console</span>.WriteLine(t == (1, (2, 3)));
    }
}
</code></pre>
<!-- pageBreak -->
<h2><a id="internal">タプルの内部実装</h2>
<p>タプルがどういうコードに展開されるかについても話しておきましょう。</p>
<p>タプルを使ったコードを古いバージョンの.NET上で動かしたり、
タプルを使ったライブラリを古いバージョンのC#から参照したり、
別のプログラミング言語から参照したい場合もあります。
そのために、タプルは、<code>ValueTuple</code>という構造体に展開されます。</p>
<h3><a id="tuple-ValueTuple">ValueTuple構造体への展開</h3>
<p>タプルは、コンパイルの結果としては<code>ValueTuple</code>構造体(<code>System</code>名前空間)に展開されます。</p>
<p>例えば、以下のようなコードを考えます。</p>
<pre class="source" title="ローカルでのタプル利用">
<code><span class="reserved">var</span> t = (x: 3, y: 5);
<span class="reserved">var</span> p = t.x * t.y;
<span class="reserved">var</span> (x, y) = t;
<span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string"> × </span>{y}<span class="string"> = </span>{p}<span class="string">"</span>);
</code></pre>
<p>以下のようなコードに展開されます。</p>
<pre class="source" title="ローカルでのタプルの展開結果">
<code><span class="reserved">var</span> t = <span class="reserved">new</span> <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(3, 5); <span class="comment">// (x: 3, y: 5)</span>
<span class="reserved">var</span> p = t.Item1 * t.Item2; <span class="comment">// t.x * t.y</span>
<span class="reserved">var</span> x = t.Item1;
<span class="reserved">var</span> y = t.Item2;
<span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string"> × </span>{y}<span class="string"> = </span>{p}<span class="string">"</span>);
</code></pre>
<p>元々の<code>x</code>や<code>y</code>という名前は、内部的には残っていません。<code>ValueTuple</code>構造体のメンバーである<code>Item1</code>や<code>Item2</code>に展開されます。</p>
<p>特に、一度<code>object</code>や<code>dynamic</code>を経由すると、名前を完全に紛失します。
以下のコードでは、<code>x</code>や<code>y</code>が見つからず、実行時エラーを起こします。</p>
<pre class="source" title="タプル型は名前を紛失する">
<code><span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">void</span> Dynamic()
{
    <span class="comment">// 匿名型は名前が残る</span>
    <span class="reserved">var</span> a = <span class="reserved">new</span> { x = 3, y = 5 };
    <span class="reserved">var</span> s1 = Sum(a); <span class="comment">// 大丈夫</span>
    <span class="type">Console</span>.WriteLine(s1);

    <span class="comment">// タプル型は名前を紛失する</span>
    <span class="reserved">var</span> t = (x: 3, y: 5);
    <span class="reserved">var</span> s2 = Sum(t); <span class="comment">// x, yという名前が実行時になくてエラーに</span>
    <span class="type">Console</span>.WriteLine(s2);
}

<span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">dynamic</span> Sum(<span class="reserved">dynamic</span> d) =&gt; d.x + d.y;
</code></pre>
<h3><a id="TupleElementNames">TupleElementNames属性</h3>
<p>とはいえ、名前をどこにも残さないと、ライブラリをまたいだ時に<code>x</code>、<code>y</code>などの名前が使えなくて困ります。
そこで、クラスのメンバーにタプルを使う場合には、<code>TupleElementNames</code>属性(<code>System.Runtime.CompilerServices</code>名前空間)を付けて、
C#コンパイラーには名前がわかるようにしています。</p>
<p>例えば、以下のような引数も戻り値もタプルなメソッドを書いたとします。</p>
<pre class="source" title="引数も戻り値もタプルなメソッド">
<code><span class="reserved">public</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) F((<span class="reserved">int</span> a, <span class="reserved">int</span> b) t) =&gt; (t.a + t.b, t.a - t.b);
</code></pre>
<p>このメソッドは、以下のように展開されます。タプルが<code>ValueTuple</code>構造体に化けますが、<code>TupleElementNames</code>属性を付けて名前を残します。</p>
<pre class="source" title="">
<code>[<span class="reserved">return</span>: <span class="type">TupleElementNames</span>(<span class="reserved">new</span>[] { <span class="string">"x"</span>, <span class="string">"y"</span> })]
<span class="reserved">public</span> <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; F([<span class="type">TupleElementNames</span>(<span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"b"</span> })] <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; t)
    =&gt; <span class="reserved">new</span> <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(t.Item1 + t.Item2, t.Item1 - t.Item2);
</code></pre>
<p>C#コンパイラーは、この情報を元に、タプルの名前を復元します。</p>
<h3><a id="ValueTuple-definition">ValueTuple構造体の中身</h3>
<p>タプルの展開結果にあたる<code>ValueTuple</code>は、型引数が0～8個の合計9個の構造体があります。
例えば、型引数2個のものは以下のような定義になっています。</p>
<pre class="source" title="ValueTuple構造体">
<code>[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Auto)]
<span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">ValueTuple</span>&lt;<span class="type">T1</span>, <span class="type">T2</span>&gt;
    : <span class="type">IEquatable</span>&lt;<span class="type">ValueTuple</span>&lt;<span class="type">T1</span>, <span class="type">T2</span>&gt;&gt;, <span class="type">IStructuralEquatable</span>, <span class="type">IStructuralComparable</span>, <span class="type">IComparable</span>, <span class="type">IComparable</span>&lt;<span class="type">ValueTuple</span>&lt;<span class="type">T1</span>, <span class="type">T2</span>&gt;&gt;
{
    <span class="reserved">public</span> <span class="type">T1</span> Item1;
    <span class="reserved">public</span> <span class="type">T2</span> Item2;

    <span class="reserved">public</span> ValueTuple(<span class="type">T1</span> item1, <span class="type">T2</span> item2)
    {
        Item1 = item1;
        Item2 = item2;
    }

    <span class="comment">// 後略、インターフェイスのメンバー定義</span>
}
</code></pre>
<p>基本的には、publicなフィールドだけを持つ構造体です。
それに、値の比較用の各種インターフェイスが実装されています。</p>
<h4><a id="long-tuple">メンバーが9個以上のタプル</h4>
<p>最初に言った通り、<code>ValueTuple</code>構造体の型引数は、最大のものでも8個です。
では、メンバーが9個以上のタプルを作るとどうなるかというと、入れ子の<code>ValueTuple</code>構造体が作られます。</p>
<p>例えば、以下のようなコードを書いたとします。
メンバー名も匿名で作ったので <code>ItemN</code>(<code>N</code>は正の整数)といったような名前でメンバーを読み書きすることになります。
C#上は、8番目以降のメンバーに対しても、<code>Item8</code>、<code>Item9</code>というような名前で参照できます。</p>
<pre class="source" title="メンバーが9個のタプル">
<code><span class="reserved">var</span> t = (1, 2, 3, 4, 5, 6, 7, 8, 9);
<span class="type">Console</span>.WriteLine(t.Item9);
</code></pre>
<p>このコードは、以下のように展開されます。</p>
<pre class="source" title="メンバーが9個のタプルの展開結果">
<code><span class="reserved">var</span> t = <span class="reserved">new</span> <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>, <span class="reserved">int</span>, <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;&gt;(
    1, 2, 3, 4, 5, 6, 7, <span class="reserved">new</span> <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(8, 9));
<span class="type">Console</span>.WriteLine(t.Rest.Item2);
</code></pre>
<p><code>ValueTuple</code>構造体には<code>Item8</code>、<code>Item9</code>という名前のメンバーはありません。
型引数の数が最大のもので8メンバーで、その8つ目のメンバーの名前は<code>Rest</code> (残り)です。
そして、以下のように、C#上<code>Item9</code>であれば展開結果的には<code>Rest</code>のさらに<code>Item2</code>というように、入れ子のメンバー参照に展開されます。</p>
<table>
<thead>
<tr>
	<th>C# 上</th>
	<th>コンパイル結果</th>
</tr>
</thead>
<tbody>
<tr>
	<td><code>Item8</code></td>
	<td><code>Rest.Item1</code></td>
</tr>
<tr>
	<td><code>Item9</code></td>
	<td><code>Rest.Item2</code></td>
</tr>
<tr>
	<td>…</td>
	<td>…</td>
</tr>
<tr>
	<td><code>Item15</code></td>
	<td><code>Rest.Rest.Item1</code></td>
</tr>
<tr>
	<td><code>Item16</code></td>
	<td><code>Rest.Rest.Item2</code></td>
</tr>
<tr>
	<td>…</td>
	<td>…</td>
</tr>
</tbody>
</table>
<h4><a id="nupkg">ValueTuple構造体の定義場所</h4>
<p>C# 7のリリースに合わせて、<code>ValueTuple</code>構造体は標準ライブラリに取り込まれる予定です。</p>
<p>一方で、古い.NET (.NET Framework 4.6.2以前、.NET Standard 1.6以前)上でタプルを使いたい場合、
以下のライブラリを参照します。この中に<code>ValueTuple</code>構造体や、<code>TupleElementNames</code>属性が定義されています。</p>
<ul>
<li><a href="https://www.nuget.org/packages/System.ValueTuple/">System.ValueTuple</a></li>
</ul>
<h3><a id="0-tuple">型引数0、1のValueTuple</h3>
<p>前述の通り、タプルのメンバーは2つ以上な必要があって、<code>()</code>や<code>(int x)</code>というようなタプルは作れません。
一方で、<code>ValueTuple</code>構造体には、型引数0個と1個のものが存在します。</p>
<pre class="source" title="型引数0個と1個のValueTuple">
<code><span class="comment">// メンバー0個、1個のものは、構造体はあるけど、タプル構文は使えない</span>
<span class="reserved">var</span> noneple = <span class="reserved">new</span> <span class="type">ValueTuple</span>();
<span class="reserved">var</span> oneple = <span class="reserved">new</span> <span class="type">ValueTuple</span>&lt;<span class="reserved">int</span>&gt;(1);

<span class="comment">// メンバー2個以上はタプル構文を使える</span>
<span class="reserved">var</span> twople = (1, 2); <span class="comment">// new ValueTuple&lt;int, int&gt;(1, 2);</span>
<span class="reserved">var</span> threeple = (1, 2, 3); <span class="comment">// new ValueTuple&lt;int, int, int&gt;(1, 2, 3);</span>
</code></pre>
<p>型引数0個の<code>ValueTuple</code>(0-tuple)は、いわゆる<a href="http://ufcpp.net/study/csharp/st_function.html#unit">Unit型</a>です。
<code>void</code>の代わりにこの型を使うことで、戻り値がある場合とない場合のコードを統一的に書けてうれしい場合があります。
一方、型引数1個のもの(1-tuple)も、用途としては0-tupleと同じです。
型引数2個以上のものと並べて、戻り値や引数の個数違いを統一的に書けます。</p>
<p>例えば、以下の2つのコードはどちらの方が統一性があっていいかという話になります。</p>
<pre class="source" title="タプルでは0、1は書けない">
<code><span class="comment">// タプルでは0、1は書けない</span>
<span class="reserved">async</span> <span class="type">Task</span> F0() { }
<span class="reserved">async</span> <span class="type">Task</span>&lt;<span class="reserved">int</span>&gt; F1() =&gt; 1;
<span class="reserved">async</span> <span class="type">Task</span>&lt;(<span class="reserved">int</span> x1, <span class="reserved">int</span> x2)&gt; F2() =&gt; (1, 2);
<span class="reserved">async</span> <span class="type">Task</span>&lt;(<span class="reserved">int</span> x1, <span class="reserved">int</span> x2, <span class="reserved">int</span> x3)&gt; F3() =&gt; (1, 2, 3);
</code></pre>
<pre class="source" title="こう書けると統一性があってきれい">
<code><span class="comment">// こう書けると統一性があってきれい(C# 7では書けない)</span>
<span class="reserved">async</span> <span class="type">Task</span>&lt;()&gt; F0() { }
<span class="reserved">async</span> <span class="type">Task</span>&lt;(<span class="reserved">int</span> x1)&gt; F1() =&gt; (1);
<span class="reserved">async</span> <span class="type">Task</span>&lt;(<span class="reserved">int</span> x1, <span class="reserved">int</span> x2)&gt; F2() =&gt; (1, 2);
<span class="reserved">async</span> <span class="type">Task</span>&lt;(<span class="reserved">int</span> x1, <span class="reserved">int</span> x2, <span class="reserved">int</span> x3)&gt; F3() =&gt; (1, 2, 3);
</code></pre>
<p>特に、ソースコード生成などでまとめて、個数違いのメソッドを生成したい場合などには、0-tupleや1-tupleがほしくなります。
0個と1個の時だけ特別扱いが必要になるかどうかという問題です。
0-tupleと1-tupleがあれば、特別扱いなしでソースコード生成ができて楽です。</p>
<p>ということで、0-tuple、1-tupleの需要はあるんですが、問題があって構文を提供できていません。
1-tupleになるであろう構文は<code>(1)</code>というような形になるはずですが、
これが、C#の既存の構文ですでに、単に<code>1</code>と同じ意味で解釈されるため、1-tupleを作れません。
0-tupleの方の<code>()</code>は、これまでは書けなかった書き方なので別にC# 7で追加できますが、
1-tupleだけ飛ばして「0か2以上のみ」とするのも変な話です。</p>
<!-- pageBreak -->
<h2><a id="related">関連</h2>
<p>タプルには、毛色の似た機能が2つあります。</p>
<ul>
<li><a href="http://ufcpp.net/study/csharp/sp3_inference.html#anonymous">匿名型</a> … タプルと同様に、名前がない型</li>
<li><a href="http://ufcpp.net/study/csharp/sp_ref.html#out">出力引数</a> … 複数の戻り値を返すのに使える</li>
</ul>
<p>これらとの関連・使い分けについても話しておきましょう。</p>
<h3><a id="anonymous-type">匿名型との比較</h3>
<p>タプルは、名前がない型という観点で言うと、<a href="http://ufcpp.net/study/csharp/sp3_inference.html#anonymous">匿名型</a>と似ています。
しかし、「<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/">名前のない複合型</a>」で説明したように、
出自・用途の違いから、内部実装は結構異なります。</p>
<p>以下の表のようになります。</p>
<table>
<thead>
<tr>
	<th></th>
	<th>タプル</th>
	<th>匿名型</th>
</tr>
</thead>
<tbody>
<tr>
	<td>主な用途</td>
	<td><a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/#multiple-returns">多値戻り値</a></td>
	<td><a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/#projection">部分的なメンバー抜き出し</a></td>
</tr>
<tr>
	<td>展開結果</td>
	<td><code>ValueTuple</code>構造体＋属性</td>
	<td>クラスの生成</td>
</tr>
<tr>
	<td>型の種類</td>
	<td>値型</td>
	<td>参照型</td>
</tr>
<tr>
	<td>見た目</td>
	<td>引数の書き方に似ている</td>
	<td>オブジェクト初期化子の書き方に似ている</td>
</tr>
</tbody>
</table>
<p>展開結果の差は用途の差から来ています。
タプルは戻り値として使います。publicなメンバーの型にも使うことになるので、ライブラリ間をまたげる必要があります。
<code>ValueTuple</code>構造体に展開することで、ライブラリをまたいでも同じ構造体を参照する状態になります。</p>
<p>一方、匿名型は、ライブラリごとにそれぞれクラスを生成します(「<a href="http://ufcpp.net/study/csharp/sp3_inference.html#anonymous">匿名型</a>」参照)。
同じ型に見えて、ライブラリをまたぐと別クラスになってしまいます。
このことから、匿名型は、メソッドの戻り値など、publicになりうる場所には書けません。
メソッド内のローカルな部分で完結して使う必要があります。</p>
<p>とはいえ、<code>ValueTuple</code>構造体に展開では、前節での説明の通り、実行時に名前を紛失します。
<a href="http://ufcpp.net/study/csharp/sp4_dynamic.html"><code>dynamic</code></a>や、<a href="http://ufcpp.net/study/csharp/sp3_expression.html">式木</a>での利用にはタプルは向きません。この用途なら匿名型の方が向いています。</p>
<p>値型か参照型かも実装が異なりますが、これも、戻り値として使う、その後すぐに<a href="http://ufcpp.net/study/csharp/data/tuples/#deconstruction">分解</a>して使うという想定だと、値型の方が実行性能的に有利だからです。
用途が変われば最適な実装は変わります。</p>
<h3><a id="out-params">出力引数との比較</h3>
<p>多値戻り値という用途だと、<a href="http://ufcpp.net/study/csharp/sp_ref.html#out">出力引数</a>という手段もあります。
一般的に言うと、多値戻り値には今後タプルを使うのがおすすめです。
出力引数の方が煩雑な書き方になりがちだからです。</p>
<p>比較のために簡単な例を挙げてみましょう。まず、C# 6以前の出力引数を使ったものです。</p>
<pre class="source" title="出力引数(C# 6)版">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="type">Point</span> p)
{
    <span class="comment">// 事前に変数を用意しないといけない/var 不可</span>
    <span class="reserved">int</span> x, y;
    <span class="comment">// 1個1個 out を付けないといけない</span>
    Deconstruct(p, <span class="reserved">out</span> x, <span class="reserved">out</span> y);
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string">, </span>{y}<span class="string">"</span>);

    <span class="comment">//非同期メソッドには使えない</span>
}

<span class="comment">// 1個1個 out を付けないといけない</span>
<span class="reserved">static</span> <span class="reserved">void</span> Deconstruct(<span class="type">Point</span> p, <span class="reserved">out</span> <span class="reserved">int</span> x, <span class="reserved">out</span> <span class="reserved">int</span> y)
{
    <span class="comment">// 1個1個代入</span>
    x = p.X;
    y = p.Y;
}
</code></pre>
<p>1個1個<code>out</code>修飾子を付けて回るのは結構な煩雑さです。
呼び出す前に別途変数宣言が必要なのも面倒です。
これらは単に煩雑なだけなので我慢すれば何とかなりますが、
致命的なのは非同期メソッドで使えないことです。</p>
<p>ちなみに、煩雑さはC# 7で多少マシになりました。<a href="http://ufcpp.net/study/csharp/sp_ref.html#out-var">出力変数宣言</a>という構文が追加されて、以下のように書けます。</p>
<pre class="source" title="出力引数(C# 7)版">
<code><span class="reserved">static</span> <span class="reserved">void</span> F(<span class="type">Point</span> p)
{
    <span class="comment">// 変数の事前準備は不要に</span>
    <span class="comment">// でも1個1個 out を付けないといけない</span>
    Deconstruct(p, <em><span class="reserved">out</span> <span class="reserved">var</span> x, <span class="reserved">out</span> <span class="reserved">var</span> y</em>);
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string">, </span>{y}<span class="string">"</span>);

    <span class="comment">//非同期メソッドには相変わらず使えない</span>
}

<span class="comment">// 1個1個 out を付けないといけない</span>
<span class="reserved">static</span> <span class="reserved">void</span> Deconstruct(<span class="type">Point</span> p, <span class="reserved">out</span> <span class="reserved">int</span> x, <span class="reserved">out</span> <span class="reserved">int</span> y) =&gt; (x, y) = (p.X, p.Y);
</code></pre>
<p>でも、相変わらず長くなりがちです。
また、非同期メソッドで使えない点は変わりません。</p>
<p>タプルを使えばこの問題は解決です。</p>
<pre class="source" title="タプル版">
<code><span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> F(<span class="type">Point</span> p)
{
    <span class="comment">// 1個の var で受け取れる</span>
    <span class="reserved">var</span> t1 = Deconstruct(p);
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{t1.x}<span class="string">, </span>{t1.y}<span class="string">"</span>);

    <span class="comment">// 何なら分解と併せればもっと書き心地よく書ける</span>
    <span class="reserved">var</span> (x, y) = Deconstruct(p);
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string">, </span>{y}<span class="string">"</span>);

    <span class="comment">// 非同期メソッドで使えるのはタプルだけ</span>
    <span class="reserved">var</span> t2 = <span class="reserved">await</span> DeconstructAsync(p);
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{t2.x}<span class="string">, </span>{t2.y}<span class="string">"</span>);
}

<span class="reserved">static</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) Deconstruct(<span class="type">Point</span> p) =&gt; (p.X, p.Y); <span class="comment">// 1個の式で書けて楽</span>
<span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span>&lt;(<span class="reserved">int</span> x, <span class="reserved">int</span> y)&gt; DeconstructAsync(<span class="type">Point</span> p) =&gt; (p.X, p.Y);
</code></pre>
<p>一方で、出力引数を使いたくなる場面も残っています。</p>
<ul>
<li><code>TryParse</code>のように、<code>bool</code>値を返して<code>if</code>ステートメントなどの条件式内で使いたい場合</li>
<li>オーバーロードを呼び分けたい場合</li>
</ul>
<p><code>if</code>内で使いたい場合は、例えば以下のようなコードになります。</p>
<pre class="source" title="if 内で使うなら bool 1個の戻り値の方が使いやすい">
<code><span class="reserved">static</span> <span class="reserved">void</span> TryPattern()
{
    <span class="reserved">var</span> s = <span class="type">Console</span>.ReadLine();
    <span class="reserved">if</span> (<span class="reserved">int</span>.TryParse(s, <span class="reserved">out</span> <span class="reserved">var</span> x)) <span class="type">Console</span>.WriteLine(x);
}
</code></pre>
<p>これはさすがにタプルを使う方が煩雑です。</p>
<pre class="source" title="if 内で使うならタプルの方が煩雑">
<code><span class="reserved">static</span> <span class="reserved">void</span> TuplePattern()
{
    <span class="reserved">var</span> s = <span class="type">Console</span>.ReadLine();
    <span class="reserved">var</span> (success, x) = Parse(s);
    <span class="reserved">if</span> (success) <span class="type">Console</span>.WriteLine(x);
}

<span class="reserved">static</span> (<span class="reserved">bool</span> success, <span class="reserved">int</span> value) Parse(<span class="reserved">string</span> s) =&gt; <span class="reserved">int</span>.TryParse(s, <span class="reserved">out</span> <span class="reserved">var</span> x) ? (<span class="reserved">true</span>, x) : (<span class="reserved">false</span>, 0);
</code></pre>
<p>もっとも、C# 7では、以下のような <code>is</code> 演算子を使った<code>null</code>チェックで同様のことをすると言う手もあります。
この書き方を型スイッチと呼びます(説明ページ準備中。でき次第リンク)。</p>
<pre class="source" title="C# 7の is を使って、int? の null チェック">
<code><span class="reserved">static</span> <span class="reserved">void</span> NullCheckPattern()
{
    <span class="reserved">var</span> s = <span class="type">Console</span>.ReadLine();
    <span class="reserved">if</span> (ParseOrDefault(s) <em><span class="reserved">is</span> <span class="reserved">int</span> x</em>) <span class="type">Console</span>.WriteLine(x);
}

<span class="reserved">static</span> <span class="reserved">int</span>? ParseOrDefault(<span class="reserved">string</span> s) =&gt; <span class="reserved">int</span>.TryParse(s, <span class="reserved">out</span> <span class="reserved">var</span> x) ? x : <span class="reserved">default</span>(<span class="reserved">int</span>?);
</code></pre>
<p>もう1つ、<a href="http://ufcpp.net/study/csharp/st_function.html#overload">オーバーロード</a>ですが、C#では(というか.NETでは)、引数でのオーバーロードはできますが、戻り値でのオーバーロードはできません。
そこで、以下のように、オーバーロードに関しては出力引数の方が有利になります。</p>
<pre class="source" title="オーバーロードの可否">
<code><span class="comment">// これはオーバーロード可能</span>
<span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">out</span> <span class="reserved">int</span> x, <span class="reserved">out</span> <span class="reserved">int</span> y) =&gt; (x, y) = (1, 2);
<span class="reserved">static</span> <span class="reserved">void</span> F(<span class="reserved">out</span> <span class="reserved">int</span> id, <span class="reserved">out</span> <span class="reserved">string</span> name) =&gt; (id, name) = (1, <span class="string">"abc"</span>);

<span class="comment">// 戻り値でのオーバーロードはできない</span>
<span class="comment">// コンパイル エラーに</span>
<span class="reserved">static</span> (<span class="reserved">int</span> x, <span class="reserved">int</span> y) F() =&gt; (1, 2);
<span class="reserved">static</span> (<span class="reserved">int</span> id, <span class="reserved">string</span> name) F() =&gt; (1, <span class="string">"abc"</span>);
</code></pre> ]]></description>
				<pubDate>Tue, 25 Oct 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] 式にまつわる補足</title>
				<link>http://www.ufcpp.net/study/csharp/structured/miscexpressions/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>「<a href="http://ufcpp.net/study/csharp/st_variable.html">変数と式</a>」で少し言葉としては出しましたが、
プログラミング言語の構文には大きく分けて式(expression)とステートメント(statement: 文、平叙文)という2種類のものがあります。</p>
<p>最近のプログラミング言語ほど式の比率が高くなっています。
C#でも、バージョンを重ねるごとに、式になっている構文が増えています。</p>
<h2><a id="term">式とステートメント</h2>
<p>「<a href="http://ufcpp.net/study/csharp/#start">基礎</a>」と「<a href="http://ufcpp.net/study/csharp/#structured">構造化</a>」のセクションで、C#の式とステートメントの結構な割合を紹介しました。ここで1度、この式とステートメントの区別についての話をしておきます。</p>
<p>式とステートメントは、大まかに言うと以下のようなものです。</p>
<ul>
<li><strong id="key-expression" class="keyword">式</strong>(expression): 割とどこにでも書ける代わりに戻り値が必須</li>
<li><strong id="key-statement" class="keyword">ステートメント</strong>(statement): 戻り値がなくてもいい代わりに書ける場所がブロック内に限られている</li>
</ul>
<h5><a id="expression">式</h5>
<p>式(expression: 表現、語句、(数学用語で)式)は、
以下のような特徴がある構文です。</p>
<ul>
<li>書ける場所が多い</li>
<li>必ず何かしらの値を返す</li>
<li>いろいろ組み合わせて書ける</li>
</ul>
<p><img src="/media/1096/expressions.png" alt="式" /></p>
<p>名前からして数学用語の「式」がもとになっていますが、
名前通り、<code>x + 1</code> というような数式みたいなものが多いです。
いかにも数式っぽいもの以外にも、<a href="/study/csharp/oo_class.html#use"><code>x.PropertyName</code></a>や<a href="/study/csharp/sp5_async.html"><code>await x</code></a> なども式です。</p>
<p>組み合わせて書けるというのは、例えば、
<code>await Task.Run(() =&gt; new[] { &quot;abc&quot; }[0].Length)</code> みたいなものも式になっています。
この式は、以下のような式を組み合わせた結果です。</p>
<ul>
<li><code>&quot;abc&quot;</code> … <a href="/csharp/st_variable.html#literal">文字列リテラル</a></li>
<li>&quot;new [] { x }` <a href="/study/csharp/st_array.html">配列生成</a></li>
<li><code>x[0]</code> … <a href="/study/csharp/oo_indexer.html">インデックス アクセス</a></li>
<li><code>x.Length</code> … <a href="/study/csharp/oo_class.html#use">メンバー アクセス</a></li>
<li><code>() =&gt; x</code> … <a href="/study/csharp/sp3_lambda.html">ラムダ式</a></li>
<li><code>Task.Run</code> … <a href="/study/csharp/oo_class.html#use">メンバー アクセス</a></li>
<li><code>x(y)</code> … <a href="/study/csharp/st_function.html">メソッド呼び出し</a></li>
<li><code>await x</code> … <a href="/study/csharp/sp5_async.html">非同期処理の完了待ち</a></li>
</ul>
<p>組み合わせて書ける分、1つ1つはシンプルなものが多いです。</p>
<h5><a id="statement">ステートメント</h5>
<p>一方、ステートメント(statement: 文、声明)は、
以下のような特徴がある構文です。</p>
<ul>
<li>ブロックの内側にしか書けない</li>
<li>組み合わせが効かない</li>
<li>1つ1つが大きい</li>
<li>戻り値がない</li>
</ul>
<p><img src="/media/1097/statements.png" alt="ステートメント" /></p>
<p><code>if</code> などの条件分岐や、<code>for</code> などの反復処理をはじめ、<a href="/study/csharp/st_control.html">制御構文</a>が多いです。</p>
<p>式との比較をまとめます。</p>
<table>
<thead>
<tr>
	<th>式</th>
	<th>ステートメント(文)</th>
</tr>
</thead>
<tbody>
<tr>
	<td>数式っぽい構文が多い</td>
	<td>制御構文が多い</td>
</tr>
<tr>
	<td>どこにでも書ける</td>
	<td>ブロック内(関数本体の中など)にしか書けない</td>
</tr>
<tr>
	<td>いろいろ組み合わせて書ける</td>
	<td>そんなに組み合わせの幅はない</td>
</tr>
<tr>
	<td>戻り値が必須</td>
	<td>戻り値がない</td>
</tr>
</tbody>
</table>
<p>式やステートメント(文)の一覧は、「<a href="http://ufcpp.net/study/csharp/list_expression.html">C# の式と文の一覧</a>」にまとめてあります。</p>
<h2><a id="increasing-expressions">式は増加傾向にある</h2>
<p>近年では、ステートメントよりも式の方が好まれる傾向があります。
C# でも、バージョンアップを重ねるたびに、式の比率が増えています。</p>
<p>ステートメントだとそもそも書けない場所も多くて困ることがあります。
なので、以前でもステートメントを使って書けたものを、
式で書き直せるような構文の追加が結構あります。
また、式を使いやすくするような構文も増えています。</p>
<p>以下に例を挙げていきます。</p>
<h5>C# 2.0</h5>
<table>
<tr>
<th>構文</th>
<th>新しい書き方</th>
<th>以前の書き方</th>
</tr>
<tr>
<td><a href="/study/csharp/rm_nullusage.html#key-null-coalesce">null 合体演算子</a></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">y</span> = <span class="variable">x</span> ?? <span class="string">&quot;&quot;</span>;
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">y</span> = <span class="variable">x</span>;
<span class="control">if</span> (<span class="variable">y</span> == <span class="reserved">null</span>) <span class="variable">y</span> = <span class="string">&quot;&quot;</span>;
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/sp_delegate.html?key=anonymous#anonymous">匿名メソッド式</a></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
{
    <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span> = <span class="reserved">delegate</span> (<span class="reserved">int</span> <span class="variable">x</span>)
    {
        <span class="control">return</span> <span class="variable">x</span> * <span class="variable">x</span>;
    };
}
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">void</span> <span class="method">Main</span>()
{
    <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span> = <span class="method">M</span>;
}
 
<span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">x</span>)
{
    <span class="control">return</span> <span class="variable">x</span> * <span class="variable">x</span>;
}
</code></pre></td>
</tr>
</table>
<h5>C# 3.0</h5>
<table>
<tr>
<th>構文</th>
<th>新しい書き方</th>
<th>以前の書き方</th>
</tr>
<tr>
<td><a href="/study/csharp/ap_ver3.html#functional">オブジェクト初期化子</a></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">p</span> = <span class="reserved">new</span> <span class="type">Point</span> { X = 1, Y = 2 };
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">p</span> = <span class="reserved">new</span> <span class="type">Point</span>();
<span class="variable">p</span>.X = 1;
<span class="variable">p</span>.Y = 2;
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/ap_ver3.html#functional">コレクション初期化子</a></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">list</span> = <span class="reserved">new</span> <span class="type">List</span>&lt;<span class="reserved">int</span>&gt; { 1, 2 };
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">list</span> = <span class="reserved">new</span> <span class="type">List</span>&lt;<span class="reserved">int</span>&gt;();
<span class="variable">list</span>.<span class="method">Add</span>(1);
<span class="variable">list</span>.<span class="method">Add</span>(2);
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/sp3_lambda.html">ラムダ式</a></td>
<td><pre class="source" title="">
<code><span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span> = <span class="variable">x</span> =&gt; <span class="variable">x</span> * <span class="variable">x</span>;
</code></pre></td>
<td><pre class="source" title="">
<code><span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; <span class="variable">f</span> = <span class="reserved">delegate</span> (<span class="reserved">int</span> <span class="variable">x</span>) { <span class="control">return</span> <span class="variable">x</span>; };
</code></pre></td>
</tr>
<tr>
</table>
<h5>C# 6.0</h5>
<table>
<tr>
<th>構文</th>
<th>新しい書き方</th>
<th>以前の書き方</th>
</tr>
<tr>
<td><a href="/study/csharp/rm_nullusage.html#key-null-conditional">null条件演算子</a></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">y</span> = <span class="variable">x</span>?.Length;
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">int</span>? <span class="variable">y</span>;
<span class="control">if</span> (<span class="variable">x</span> == <span class="reserved">null</span>) <span class="variable">y</span> = <span class="reserved">null</span>;
<span class="control">else</span> <span class="variable">y</span> = <span class="variable">x</span>.Length;
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/ap_ver6.html#index-initializer">インデックス初期化子</a></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">dic</span> = <span class="reserved">new</span> <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="reserved">int</span>&gt;
{
    [<span class="string">&quot;one&quot;</span>] = 1,
    [<span class="string">&quot;two&quot;</span>] = 2
};
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">var</span> <span class="variable">dic</span> = <span class="reserved">new</span> <span class="type">Dictionary</span>&lt;<span class="reserved">string</span>, <span class="reserved">int</span>&gt;();
<span class="variable">dic</span>[<span class="string">&quot;one&quot;</span>] = 1;
<span class="variable">dic</span>[<span class="string">&quot;two&quot;</span>] = 2;
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/ap_ver6.html#sec-expression-bodied">式形式メンバー</a></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">x</span>) =&gt; <span class="variable">x</span> * <span class="variable">x</span>;
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">int</span> <span class="variable">x</span>)
{
    <span class="control">return</span> <span class="variable">x</span> * <span class="variable">x</span>;
}
</code></pre></td>
</tr>
</table>
<h5>C# 7.0</h5>
<table>
<tr>
<th>構文</th>
<th>新しい書き方</th>
<th>以前の書き方</th>
</tr>
<tr>
<td><a href="/study/csharp/st_function.html#sec-expression-bodied">式形式メンバー(追加)</a></td>
<td><pre class="source" title="">
<code><span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X, Y;
    <span class="reserved">public</span> <span class="method">Point</span>(<span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>)
        =&gt; (X, Y) = (<span class="variable">x</span>, <span class="variable">y</span>);
}
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X, Y;
    <span class="reserved">public</span> <span class="method">Point</span>(<span class="reserved">int</span> <span class="variable">x</span>, <span class="reserved">int</span> <span class="variable">y</span>)
    {
        X = <span class="variable">x</span>;
        Y = <span class="variable">y</span>;
    }
}
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/oo_exception.html#throwexpr">throw 式</a></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">string</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">s</span>)
        =&gt; <span class="variable">s</span> ?? <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">string</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">s</span>)
{
    <span class="control">if</span> (<span class="variable">s</span> == <span class="reserved">null</span>) <span class="control">throw</span> <span class="reserved">new</span> <span class="type">Exception</span>();
    <span class="control">return</span> <span class="variable">s</span>;
}
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/sp_ref.html#out-var">出力変数宣言</a></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">s</span>)
         =&gt; <span class="reserved">int</span>.<span class="method">TryParse</span>(<span class="variable">s</span>, <span class="reserved">out</span> <span class="reserved">var</span> <span class="variable">x</span>) ? <span class="variable">x</span> : -1;
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">string</span> <span class="variable">s</span>)
{
    <span class="reserved">int</span> <span class="variable">x</span>;
    <span class="control">if</span> (<span class="reserved">int</span>.<span class="method">TryParse</span>(<span class="variable">s</span>, <span class="reserved">out</span> <span class="variable">x</span>)) <span class="control">return</span> <span class="variable">x</span>;
    <span class="control">else</span> <span class="control">return</span> -1;
}
</code></pre></td>
</tr>
<tr>
<td><a href="/study/csharp/datatype/patterns/#declaration">宣言パターン</a></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
        =&gt; <span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">string</span> <span class="variable">s</span> ? <span class="variable">s</span>.Length : 0;
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">object</span> <span class="variable">x</span>)
{
    <span class="reserved">var</span> <span class="variable">s</span> = <span class="variable">x</span> <span class="reserved">as</span> <span class="reserved">string</span>;
    <span class="control">if</span> (<span class="variable">s</span> != <span class="reserved">null</span>) <span class="control">return</span> <span class="variable">s</span>.Length;
    <span class="control">return</span> 0;
}
</code></pre></td>
</tr>
</table>
<h5>C# 8.0</h5>
<table>
<tr>
<th>構文</th>
<th>新しい書き方</th>
<th>以前の書き方</th>
</tr>
<tr>
<td><a href="">switch 式</a></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">int</span>? <span class="variable">x</span>, <span class="reserved">int</span>? <span class="variable">y</span>)
    =&gt; (<span class="variable">x</span>, <span class="variable">y</span>) <span class="reserved">switch</span>
    {
        (<span class="reserved">null</span>, <span class="reserved">null</span>) =&gt; 0,
        (<span class="reserved">null</span>, { }) =&gt; 1,
        ({ }, <span class="reserved">null</span>) =&gt; -1,
        (<span class="reserved">int</span> <span class="variable">i</span>, <span class="reserved">int</span> <span class="variable">j</span>) =&gt; <span class="variable">i</span>.<span class="method">CompareTo</span>(<span class="variable">j</span>),
    };
</code></pre></td>
<td><pre class="source" title="">
<code><span class="reserved">static</span> <span class="reserved">int</span> <span class="method">M</span>(<span class="reserved">int</span>? <span class="variable">x</span>, <span class="reserved">int</span>? <span class="variable">y</span>)
{
    <span class="control">if</span> (<span class="variable">x</span> <span class="reserved">is</span> <span class="reserved">int</span> <span class="variable">i</span>)
    {
        <span class="control">if</span> (<span class="variable">y</span> <span class="reserved">is</span> <span class="reserved">int</span> <span class="variable">j</span>) <span class="control">return</span> <span class="variable">i</span>.<span class="method">CompareTo</span>(<span class="variable">j</span>);
        <span class="control">else</span> <span class="control">return</span> -1;
    }
    <span class="control">else</span>
    {
        <span class="control">if</span> (<span class="variable">y</span> <span class="reserved">is</span> <span class="reserved">int</span>) <span class="control">return</span> 1;
        <span class="control">else</span> <span class="control">return</span> 0;
    }
}
</code></pre></td>
</tr>
</table> ]]></description>
				<pubDate>Mon, 26 Sep 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>複合型の分解</title>
				<link>http://www.ufcpp.net/study/csharp/datatype/deconstruction/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<h5 class="version version7">Ver. 7</h5>
<p><a href="http://ufcpp.net/study/csharp/data/tuples/#key-tuple">タプル</a>から値を取り出す際には、メンバーを直接、それぞれバラバラに受け取りたくなることがあります。</p>
<p>「<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/">名前のない複合型</a>」で説明したように、
メンバー名だけ見ればその型が何を意味するか分かるからこそ型に名前が付かないわけです。
このとき、その型を受け取る変数にも、よい名前が浮かばなくなるはずです。</p>
<p>そこでC# 7では、タプルと同時に、分解(deconstruction)のための構文が追加されました。</p>
<h2><a id="deconstruction">分解</h2>
<p>以下のような、整数列の個数(count)と和(sum)を同時に計算するメソッドがあったとします。
「<a href="http://ufcpp.net/study/csharp/structured/st_anonymoustype/">名前のない複合型</a>」で説明したように、
戻り値の型として「個数と和」みたいな名前(<code>CountAndSum</code>とか)しか思い浮かばないようなものです。</p>
<pre class="source" title="個数と和を返すメソッド">
<code><span class="reserved">static</span> (<span class="reserved">int</span> count, <span class="reserved">int</span> sum) Tally(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; items)
{
    <span class="reserved">var</span> count = 0;
    <span class="reserved">var</span> sum = 0;
    <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> items)
    {
        sum += x;
        count++;
    }

    <span class="reserved">return</span> (count, sum);
}
</code></pre>
<p>そうなると、この結果を受け取る変数名も、「個数と和」以上の名前はつかないでしょう。
通常、ローカル変数であれば適当な名前でもそこまで問題ではないので、
<code>x</code>とか<code>y</code>とか、本当に意味がない名前を付けることになると思います。</p>
<pre class="source" title="個数と和の受け取り">
<code><span class="reserved">var</span> x = Tally(<span class="reserved">new</span>[] { 1, 2, 3, 4, 5 });
<span class="type">Console</span>.WriteLine(x.count);
<span class="type">Console</span>.WriteLine(x.sum);
</code></pre>
<p>実際にほしい名前は<code>count</code>と<code>sum</code>だけです。
であれば、最初から<code>count</code>変数と<code>sum</code>変数に分解して受け取りたいと思うでしょう。
要するに、以下のようなことを1行で書ける構文がほしいです。</p>
<pre class="source" title="タプルの分解">
<code><comment></span><span class="comment">// この3行に相当する構文がほしい</span>
<span class="reserved">var</span> x = Tally(<span class="reserved">new</span>[] { 1, 2, 3, 4, 5 });
<span class="reserved">var</span> count = x.count;
<span class="reserved">var</span> sum = x.sum;
<span class="comment">// 以後、もう x は使わない</span>

<span class="type">Console</span>.WriteLine(count);
<span class="type">Console</span>.WriteLine(sum);
</code></pre>
<p>タプルのような名前の決まらない型は、この例のように分解して使うのが前提と言えます。</p>
<p>そこで、C# 7では、タプルと一緒に、以下のような分解のための構文を追加しました。</p>
<pre class="source" title="分解代入構文">
<code>(<span class="reserved">var</span> count, <span class="reserved">var</span> sum) = Tally(<span class="reserved">new</span>[] { 1, 2, 3, 4, 5 });
<span class="type">Console</span>.WriteLine(count);
<span class="type">Console</span>.WriteLine(sum);
</code></pre>
<p>ちなみに、この分解構文は、タプルか、後述する<code>Deconstruct</code>メソッドを持つ任意の型に対して使えます。</p>
<h3><a id="deconstruction-declaration">分解宣言</h3>
<p>以下のような書き方で、分解と同時に変数を宣言できます。
これを分解宣言(deconstruction declaration)と言います。</p>
<pre class="source" title="分解宣言">
<code><span class="comment">// count, sum を宣言しつつ、タプルを分解</span>
(<span class="reserved">int</span> count, <span class="reserved">int</span> sum) = Tally(items);

<span class="comment">// ↓こう書くとタプル型の変数の宣言</span>
<span class="comment">// (int count, int sum) t = Tally(items);</span>
</code></pre>
<p>この例の後半のコメントのように、分解宣言はタプルの型宣言の書き方によく似ています。
ただ、タプルの型宣言と違って、型推論の<code>var</code>が使えます。</p>
<pre class="source" title="var での型推論付きの分解宣言">
<code><span class="comment">// 型推論で count, sum を宣言しつつ、タプルを分解</span>
(<span class="reserved">var</span> count, <span class="reserved">var</span> sum) = Tally(items);

<span class="comment">// ↓タプルだと var は使えない。これはコンパイル エラー</span>
<span class="comment">// (var count, var sum) t = Tally(items);</span>
</code></pre>
<p>このとき、部分的に型推論(<code>var</code>)を使うこともできます。</p>
<pre class="source" title="部分的に var を使う">
<code><span class="comment">// 部分的に var を使う</span>
(<span class="reserved">var</span> count, <span class="reserved">long</span> sum) = Tally(items);
</code></pre>
<p>一方で、宣言したいすべての変数を型推論する場合であれば、先頭に1つだけ <code>var</code> キーワードを書く以下のような書き方もできます。</p>
<pre class="source" title="var + 変数リスト">
<code><span class="comment">// 「var + 変数リスト」でタプルを分解</span>
<span class="reserved">var</span> (count, sum) = Tally(items);
</code></pre>
<p>この書き方は、<code>foreach</code>、<code>for</code>などでの変数宣言でも使えます。</p>
<pre class="source" title="foreachやforの中で分解宣言">
<code>(<span class="reserved">int</span> x, <span class="reserved">int</span> y)[] array = <span class="reserved">new</span>[] { (1, 2), (3, 4) };

<span class="reserved">foreach</span> (<span class="reserved">var</span> (x, y) <span class="reserved">in</span> array)
{
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{x}<span class="string">, </span>{y}<span class="string">"</span>);
}

<span class="reserved">for</span> ((<span class="reserved">int</span> i, <span class="reserved">int</span> j) = (0, 0); i &lt; 10; i++, j--)
{
    <span class="type">Console</span>.WriteLine(<span class="string">$"</span>{i}<span class="string">, </span>{j}<span class="string">"</span>);
}
</code></pre>
<p>(仕様書状はクエリ式の<code>let</code>、<code>from</code> でも使えることになっているものの、プレビュー版である現在は未実装。)</p>
<h3><a id="deconstruction-assignment">分解代入</h3>
<p>既存の変数を使って分解することもできます。
こちらは分解代入(deconstruction assignment)といいます。</p>
<pre class="source" title="分解代入">
<code><span class="reserved">int</span> x, y;

<span class="comment">// 既存の変数を使って分解</span>
(x, y) = Tally(items);
</code></pre>
<p>文法説明のために簡素化したものとはいえ、この例では分解宣言で十分で、
再代入(既存の変数<code>x</code>、<code>y</code>の書き換え)の必要性があまりありません。
実際は、以下の例のように、ループで書き換えたりすることになるでしょう。</p>
<pre class="source" title="分解代入で変数を書き換え">
<code><span class="reserved">var</span> x = 1.0;
<span class="reserved">var</span> y = 5.0;

<span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 100; i++)
{
    (x, y) = ((x + y) / 2, <span class="type">Math</span>.Sqrt(x * y));
}
</code></pre>
<p>分解代入の左辺には、書き換え可能なものであれば何でも書けます。
例えば、配列アクセスや参照戻り値などを分解代入の左辺に書けます。</p>
<pre class="source" title="配列アクセスや参照戻り値を使って分解代入">
<code><span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">void</span> DeconstractionAssingment()
{
    <span class="reserved">var</span> a = <span class="reserved">new</span>[] { 1, 2 };

    <span class="comment">// 配列アクセス</span>
    <span class="reserved">var</span> b = <span class="reserved">new</span> <span class="reserved">int</span>[a.Length];
    (b[1], b[0]) = (a[0], a[1]);

    <span class="comment">// 参照戻り値</span>
    <span class="reserved">var</span> c = <span class="reserved">new</span> <span class="reserved">int</span>[a.Length];
    (Mod(c, 5), Mod(c, 8)) = (a[0], a[1]);

    <span class="type">Console</span>.WriteLine(<span class="reserved">string</span>.Join(<span class="string">", "</span>, b));
    <span class="type">Console</span>.WriteLine(<span class="reserved">string</span>.Join(<span class="string">", "</span>, c));
}

<span class="reserved">static</span> <span class="reserved">ref</span> <span class="type">T</span> Mod&lt;<span class="type">T</span>&gt;(<span class="type">T</span>[] array, <span class="reserved">int</span> index) =&gt; <span class="reserved">ref</span> array[index % array.Length];
</code></pre>
<p>フィールドに対しても使えるので、
例えば以下のように、コンストラクターを記述を簡素にできたりもします。</p>
<pre class="source" title="分解代入を使ったコンストラクターの簡素化の例">
<code><span class="reserved">struct</span> <span class="type">Point</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X;
    <span class="reserved">public</span> <span class="reserved">int</span> Y;
    <span class="reserved">public</span> <span class="type">Point</span>(<span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; (X, Y) = (x, y);
    <span class="reserved">public</span> <span class="reserved">void</span> Deconstruct(<span class="reserved">out</span> <span class="reserved">int</span> x, <span class="reserved">out</span> <span class="reserved">int</span> y) =&gt; (x, y) = (X, Y);
}
</code></pre>
<h3><a id="deconstruction-expression">タプル構築と分解の混在</h3>
<p>タプルを作る構文と分解代入の構文は似ているわけですが、これらは、以下のようにつなげて書くこともできます。</p>
<pre class="source" title="分解、かつ、タプル構築">
<code><span class="reserved">int</span> x, y;
<span class="reserved">var</span> t = (x, y) = (1, 2);
</code></pre>
<p>これは、以下のように、分解後に改めてタプルを作るのと同じ意味になります。</p>
<pre class="source" title="分解 → タプル構築">
<code><span class="reserved">int</span> x, y;
(x, y) = (1, 2); <span class="comment">// 分解代入</span>
<span class="reserved">var</span> t = (x, y);  <span class="comment">// 改めてタプルを構築</span>
</code></pre>
<h3><a id="mixed-deconstruction">分解宣言と分解代入の混在</h3>
<h5 class="version version10">Ver. 10</h5>
<p>C# 10.0 では以下のように、分解代入と分解宣言の混在もできるようになりました。</p>
<pre class="source" title="分解宣言と分解代入の混在">
<code><span class="reserved">int</span> x;
(x, <em><span class="reserved">var</span> u</em>) = (1, 2);
</code></pre>
<p>ただし、式の途中に分解宣言 (var 付きの宣言) が来るようなコードは C# 10.0 でも書けません。</p>
<pre class="source" title="ただし、分解宣言は式の途中には書けない">
<code><span class="reserved">int</span> x, y;
(x, <span class="reserved">var</span> u) = (<span class="error"><span class="reserved">var</span> v</span>, y) = (1, 2);
</code></pre>
<h2><a id="conversion">分解時の型変換</h2>
<p>分解時には、<a href="http://ufcpp.net/study/csharp/data/tuples/#conversion">タプル間の型変換</a>と同じルールで暗黙の型変換が働きます。
すなわち、宣言位置で分解されます(メンバー名は見ない)し、メンバーごとに暗黙的型変換が効くなら分解でも暗黙的型変換が効きます。</p>
<pre class="source" title="分解時の型変換">
<code><span class="comment">// Tally の戻り値は (count, sum) の順</span>
<span class="reserved">var</span> t = Tally(<span class="reserved">new</span>[] { 1, 2, 3, 4, 5 });

<span class="comment">// sum = t.count, count = t.sum の意味になるので注意が必要</span>
(<span class="reserved">int</span> sum, <span class="reserved">int</span> count) = t;
<span class="type">Console</span>.WriteLine(sum);   <span class="comment">// 5</span>
<span class="type">Console</span>.WriteLine(count); <span class="comment">// 15</span>

<span class="comment">// int → object も int → long も暗黙的に変換可能</span>
<span class="comment">// なので、分解もでもこの変換が暗黙的に可能</span>
(<span class="reserved">object</span> x, <span class="reserved">long</span> y) = t;
</code></pre>
<h2><a id="arbitrary-types">任意の型を分解</h2>
<p>C#の言語機能としてのタプルの他にも、
タプルに類する型はあります。
すなわち、意味のある変数が作れず、分解して使う前提の型です。</p>
<p>代表例は<code>KeyValuePair</code>構造体(<code>System.Collections.Generic</code>名前空間)でしょう。
<code>key</code>と<code>value</code>という変数で分解して受け取りたいです。</p>
<p>また、C#の構文としてタプルが導入される以前に使っていた型ですが、
<code>Tuple</code>クラス(<code>System</code>名前空間)というものがあります。
メンバー名まで紛失してしまうので使い勝手はよくありませんが、
「型名がうまく付けられない時に使う型」です。</p>
<p>これらの型に対しても分解構文を使いたいです。
そこで、C# 7では、<code>Deconstruct</code>という名前のインスタンス メソッド、もしくは、拡張メソッドさえ持っていれば、
どんな型でも分解構文使えるようにしました。
例として<code>KeyValuePair</code>と<code>Tuple</code>に対する<code>Deconstruct</code>の書き方を示しましょう。
以下のような拡張メソッドがあれば分解できます。</p>
<pre class="source" title="KeyValuePairとTupleの分解用のDeconstructメソッド">
<code><span class="reserved">static</span> <span class="reserved">class</span> <span class="type">Extensions</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> Deconstruct&lt;<span class="type">T</span>, <span class="type">U</span>&gt;(<span class="reserved">this</span> <span class="type">KeyValuePair</span>&lt;<span class="type">T</span>, <span class="type">U</span>&gt; pair, <span class="reserved">out</span> <span class="type">T</span> key, <span class="reserved">out</span> <span class="type">U</span> value)
    {
        key = pair.Key;
        value = pair.Value;
    }

    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> Deconstruct&lt;<span class="type">T1</span>, <span class="type">T2</span>&gt;(<span class="reserved">this</span> <span class="type">Tuple</span>&lt;<span class="type">T1</span>, <span class="type">T2</span>&gt; x, <span class="reserved">out</span> <span class="type">T1</span> item1, <span class="reserved">out</span> <span class="type">T2</span> item2)
    {
        item1 = x.Item1;
        item2 = x.Item2;
    }
}
</code></pre>
<p>(ちなみに、.NET Core 2.0 以降か .NET Standard 2.1 以降であれば、<code>KeyValuePair</code> にはインスタンス メソッドとして標準で<code>Deconstruct</code>メソッドが追加されています。
<code>Tuple</code> の方は .NET Standard 2.0 以降であれば拡張メソッドとして<code>Deconstruct</code>メソッドがあります。)</p>
<p>これで、<code>KeyValuePair</code>と<code>Tuple</code>に対して分解構文が使えます。以下のようなコードが書けます。</p>
<pre class="source" title="任意の型に対する分解宣言">
<code><span class="reserved">var</span> pair = <span class="reserved">new</span> <span class="type">KeyValuePair</span>&lt;<span class="reserved">string</span>, <span class="reserved">int</span>&gt;(<span class="string">"one"</span>, 1);
<span class="reserved">var</span> (k, v) = pair;
<span class="comment">// 以下のようなコードに展開される</span>
<span class="comment">// string k;</span>
<span class="comment">// int v;</span>
<span class="comment">// pair.Deconstruct(out k, out v);</span>

<span class="reserved">var</span> tuple = <span class="type">Tuple</span>.Create(<span class="string">"abc"</span>, 100);
<span class="reserved">var</span> (x, y) = tuple;
<span class="comment">// 以下のようなコードに展開される</span>
<span class="comment">// string x;</span>
<span class="comment">// int y;</span>
<span class="comment">// tuple.Deconstruct(out x, out y);</span>
</code></pre>
<h3><a id="deconstruct-overload">引数の数が同じオーバーロード不可</h3>
<p>分解構文では、引数の数が同じ<code>Deconstruct</code>メソッドを呼び分けることができません。
例えば以下の例のように、引数の型が<code>double, double</code>のものと、<code>double, Radian</code>のものという2つの<code>Deconstruct</code>メソッドを定義してしまうと、2変数の分解ができなくなります。</p>
<pre class="source" title="Deconstructメソッドの呼び分けができない(引数の数が同じ)例">
<code><span class="reserved">using</span> <span class="reserved">static</span> System.<span class="type">Math</span>;

<span class="reserved">struct</span> <span class="type">Radian</span>
{
    <span class="reserved">public</span> <span class="reserved">double</span> Value { <span class="reserved">get</span>; }
    <span class="reserved">public</span> Radian(<span class="reserved">double</span> value) =&gt; Value = value;
}

<span class="reserved">struct</span> <span class="type">Vector2D</span>
{
    <span class="reserved">public</span> <span class="reserved">double</span> X { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">double</span> Y { <span class="reserved">get</span>; }

    <span class="comment">// コンストラクターは当然、個数が同じでも、型が違えば呼び分けができる</span>
    <span class="reserved">public</span> Vector2D(<span class="reserved">double</span> x, <span class="reserved">double</span> y) =&gt; (X, Y) = (x, y);
    <span class="reserved">public</span> Vector2D(<span class="reserved">double</span> radius, <span class="type">Radian</span> angle)
        : <span class="reserved">this</span>(radius * Cos(angle.Value), radius * Sin(angle.Value)) { }

    <span class="comment">// 引数の数が同じ Deconstruct が2つある</span>
    <span class="comment">// 片方だけならいいけど、2つあると分解ができなくなる</span>
    <span class="reserved">public</span> <span class="reserved">void</span> Deconstruct(<span class="reserved">out</span> <span class="reserved">double</span> x, <span class="reserved">out</span> <span class="reserved">double</span> y) =&gt; (x, y) = (X, Y);
    <span class="reserved">public</span> <span class="reserved">void</span> Deconstruct(<span class="reserved">out</span> <span class="reserved">double</span> radius, <span class="reserved">out</span> <span class="type">Radian</span> angle)
        =&gt; (radius, angle) = (Sqrt(X * X + Y * Y), <span class="reserved">new</span> <span class="type">Radian</span>(Atan2(Y, X)));
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// コンストラクターの呼び分け</span>
        <span class="reserved">var</span> p = <span class="reserved">new</span> <span class="type">Vector2D</span>(1, 2);
        <span class="reserved">var</span> q = <span class="reserved">new</span> <span class="type">Vector2D</span>(10, <span class="reserved">new</span> <span class="type">Radian</span>(PI / 5));

        <span class="comment">// 分解は呼び分けできない</span>
        (<span class="reserved">double</span> x, <span class="reserved">double</span> y) = <span class="error">q</span>; <span class="comment">// コンパイル エラー</span>
        (<span class="reserved">double</span> r, <span class="type">Radian</span> a) = <span class="error">p</span>; <span class="comment">// コンパイル エラー</span>
    }
}
</code></pre>
<p>一方で、引数の数が違えば複数の<code>Deconstruct</code>メソッドがあっても大丈夫です。
例えば以下のようなコードであれば、ちゃんと分解が使えます。</p>
<pre class="source" title="Deconstructメソッドの呼び分けができる(引数の数が違う)例">
<code><span class="reserved">struct</span> <span class="type">Vector3D</span>
{
    <span class="reserved">public</span> <span class="reserved">double</span> X { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">double</span> Y { <span class="reserved">get</span>; }
    <span class="reserved">public</span> <span class="reserved">double</span> Z { <span class="reserved">get</span>; }
    <span class="reserved">public</span> Vector3D(<span class="reserved">double</span> x, <span class="reserved">double</span> y, <span class="reserved">double</span> z) =&gt; (X, Y, Z) = (x, y, z);

    <span class="comment">// 引数の数が違えば大丈夫</span>
    <span class="reserved">public</span> <span class="reserved">void</span> Deconstruct(<span class="reserved">out</span> <span class="reserved">double</span> x, <span class="reserved">out</span> <span class="reserved">double</span> y, <span class="reserved">out</span> <span class="reserved">double</span> z) =&gt; (x, y, z) = (X, Y, Z);
    <span class="reserved">public</span> <span class="reserved">void</span> Deconstruct(<span class="reserved">out</span> <span class="reserved">double</span> first, <span class="reserved">out</span> <span class="type">Vector2D</span> rest) =&gt; (first, rest) = (X, <span class="reserved">new</span> <span class="type">Vector2D</span>(Y, Z));
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> p = <span class="reserved">new</span> <span class="type">Vector3D</span>(1, 2, 3);

        <span class="comment">// 分解可能</span>
        <span class="reserved">var</span> (first, rest) = p;
        <span class="reserved">var</span> (x, y, z) = p;
    }
}
</code></pre>
<h3><a id="tuple-optimization">タプルの構築や分解の最適化</h3>
<p>分解構文は、基本的には<code>Deconstruct</code>メソッドの呼び出しに展開されます。
しかし、タプルに対しては、<code>Deconstruct</code>メソッドやコンストラクター呼び出しをなくす最適化が掛かります。</p>
<p>例えば以下のようなコード(いわゆるSwap処理)を書いたとします。</p>
<pre class="source" title="タプル構築後にすぐに分解する例(swap)">
<code><span class="reserved">var</span> x = 1;
<span class="reserved">var</span> y = 2;
(x, y) = (y, x);
</code></pre>
<p>もしタプルが一般の型と同列に扱われるのなら、
「<a href="http://ufcpp.net/study/csharp/datatype/tuples/?p=2#tuple-ValueTuple">ValueTuple構造体への展開</a>」で説明した内容や、
前述の<code>Deconstruct</code>に展開される仕様を考えると、
これは以下のような意味にとることができます。</p>
<pre class="source" title="(一般の型の分解と同列に考える場合の)タプル構築と分解の展開結果">
<code><span class="reserved">var</span> t = <span class="reserved">new</span> ValueTuple&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt;(y, x);
t.Deconstruct(<span class="reserved">out</span> x, <span class="reserved">out</span> y);
</code></pre>
<p>しかし、タプルに限り、単なる一時変数の追加やメンバーアクセスに展開され得ます<sup>※</sup>。
上記の <code>(x, y) = (y, x)</code> は、以下のように展開できます。</p>
<pre class="source" title="タプルの場合は構築も分解も最適化で消える">
<code><span class="reserved">var</span> t1 = y; <span class="comment">// この t1 の方はさらに最適化で消える可能性あり</span>
<span class="reserved">var</span> t2 = x;
x = t1;
y = t2;
</code></pre>
<p><sup>※</sup>実際にどこまで最適化されるかは実装依存です。
例えば、C# 7.0の頃には <code>new ValueTuple&lt;int, int&gt;(x, y)</code> が一度作られていましたし、
現在の実装では <code>t1</code> も消えて <code>var t = x; x = y; y = t;</code> 相当のコードが出力されます。</p>
<h3><a id="ValueTuple">余談: System.ValueTuple 構造体を要求される</h3>
<p>タプルによる分解を使う場合、C# コンパイラーは常に<code>ValueTuple</code>構造体を要求します(<a href="https://www.nuget.org/packages/System.ValueTuple/">System.ValueTuple</a>パッケージの参照が必要)。</p>
<p>「常に」というところが少し曲者です。
例えば以下のような2つのステートメントを考えます。</p>
<pre class="source" title="タプル構築と、タプル構築＋分解">
<code><span class="comment">// タプルの仕様上、ValueTuple&lt;int, int&gt; 構造体が作られる</span>
<span class="reserved">var</span> t = (1, 2);

<span class="comment">// 前述の通り、最適化が掛かるので ValueTuple は不要なはず</span>
<span class="reserved">var</span> (x, y) = (1, 2);
</code></pre>
<p>前者は実際に<code>ValueTuple</code>構造体を必要としているので問題はありません。必要なものの参照を要求しているだけです。
一方、後者は<code>ValueTuple</code>構造体を使わないにも関わらず、C# コンパイラーは<code>ValueTuple</code>構造体の参照を求めます。</p>
<p>このコードから「すぐに分解するから最適化で消える」というの判定するのはコンパイラーにとっては意外と大変らしく、
「頑張っても見合わない」とのことで、この仕様を変えるつもりは今のところないようです。</p>
<h2><a id="evaluation">分解の評価のされ方</h2>
<p>分解構文では、メンバーごとにそれぞれ代入するような結果を生みます。
このとき、以下のようなルールが働きます。</p>
<ul>
<li>メンバーの評価は左から順</li>
<li>メンバーの書き換えは同時に起こる</li>
</ul>
<p>単純な場合、例えば<code>(a, b) = (x, y);</code>のような時にはこんなルールを気にするまでもなく、<code>a = x; b = y;</code>と同じ結果になります。
ここで、もう少し複雑な場合を考えてみましょう。</p>
<p>まず、左右で同じ変数が出てくる場合についてです。
分解構文では、各メンバーへの代入が同時に行われるかのような結果を生みます。
例えば、<code>x</code>と<code>y</code>という2つの変数の値を入れ替え(swap)ようとするとき、逐次実行であれば、以下のような書き方は間違いです。</p>
<pre class="source" title="逐次実行でのswap">
<code><span class="reserved">var</span> x = 1;
<span class="reserved">var</span> y = 2;

y = x;
x = y; <span class="comment">// 上の行で y が書き換わっているので、値の入れ替えにはならない</span>

<span class="type">Console</span>.WriteLine(x); <span class="comment">// 1</span>
<span class="type">Console</span>.WriteLine(y); <span class="comment">// 1</span>

<span class="comment">// 正しくは以下のように書く</span>
<span class="comment">// var temp = y;</span>
<span class="comment">// y = x;</span>
<span class="comment">// x = temp;</span>
</code></pre>
<p>これが、分解代入を使って以下のように書くと、正しく値が入れ替わります。</p>
<pre class="source" title="分解代入を使ったswap">
<code><span class="reserved">var</span> x = 1;
<span class="reserved">var</span> y = 2;

<span class="comment">// 分解代入であれば、値の書き換えは同時に起こる</span>
(y, x) = (x, y);

<span class="type">Console</span>.WriteLine(x); <span class="comment">// 2</span>
<span class="type">Console</span>.WriteLine(y); <span class="comment">// 1</span>
</code></pre>
<p>値が並行して同時に書き換わっているような結果を得るために、一時変数が挟まります。</p>
<pre class="source" title="実際の評価のされ方">
<code><span class="comment">// 左辺の (y, x) を受け取る一時変数をまず用意</span>
<span class="reserved">var</span> t1 = y;
<span class="reserved">var</span> t2 = x;
<span class="comment">// 一時変数から改めて代入</span>
x = t1;
y = t2;
</code></pre>
<p>さらに複雑になるのは、式が副作用を持つ場合です。
例として、分解代入の両辺に、悪名高いインクリメント演算を混ぜてみましょう。
各メンバーは、左から順に評価されます。</p>
<pre class="source" title="分解代入の両辺にインクリメントを混ぜてみる">
<code><span class="reserved">var</span> a = <span class="reserved">new</span>[] { 0, 1, 2, 3 };
<span class="reserved">var</span> i = 0;

(a[i++], a[i++]) = (a[i++], a[i++]);

<span class="type">Console</span>.WriteLine(<span class="reserved">string</span>.Join(<span class="string">", "</span>, a)); <span class="comment">// 2, 3, 2, 3</span>
<span class="comment">// つまり、以下の評価を受けてる</span>
<span class="comment">// (a[0], a[1]) = (a[2], a[3]);</span>
</code></pre>
<p>これと同じ動作をタプルと分解なしで書くと、以下のようなコードになります。</p>
<pre class="source" title="左から順に評価するため、一時変数が挟まる">
<code><span class="reserved">var</span> a = <span class="reserved">new</span>[] { 0, 1, 2, 3 };
<span class="reserved">var</span> i = 0;

<span class="reserved">ref</span> <span class="reserved">var</span> l1 = <span class="reserved">ref</span> a[i++];
<span class="reserved">ref</span> <span class="reserved">var</span> l2 = <span class="reserved">ref</span> a[i++];
<span class="reserved">var</span> r1 = a[i++];
<span class="reserved">var</span> r2 = a[i++];

l1 = r1;
l2 = r2;
</code></pre><p>２</p>
 ]]></description>
				<pubDate>Mon, 22 Aug 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>複合型のレイアウト</title>
				<link>http://www.ufcpp.net/study/csharp/interop/memorylayout/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>複合型(クラスや構造体)では、フィールドをメモリ上にどうレイアウト(layout: 配置)するかという問題があります。</p>
<p>通常、メモリ上のレイアウトがどうなっているのかをプログラマーが気にする必要はありません。
大体はコンパイラーが最適な仕事をしてくれます。</p>
<p>それでも、時々、レイアウト方法を明示的に指定したい場合があります
(おそらく、そのほとんどはC++などで書かれたネイティブ コードとの相互運用です)。
そこで、プログラミング言語によってはレイアウトをカスタマイズするための機能を提供しているものもあります。</p>
<p>C#では、クラスと構造体に対してレイアウトのカスタマイズ機能を提供しています。
<code>StructLayout</code>属性を付けることでカスタマイズ可能です。</p>
<h2><a id="alignment">アラインメント</h2>
<p>「最適なレイアウト」について説明するためには、まず、メモリの<strong id="key-alignment" class="keyword">アラインメント</strong>(alignment: 整列、調整)について知る必要があります。</p>
<p>一般に、メモリの読み書きは、<a href="http://ufcpp.net/study/computer/memory.html#address">アドレス</a>が4の倍数や8の倍数になっている方が高速です。
(1命令で読み出せるのは倍数ピッタリの場所だけなCPUもあります。
最悪、2命令で隣り合った場所を読み込んで、繋ぎなおすような処理が必要になります。)</p>
<p>そこで、多くのプログラミング言語で、アドレスがきれいな倍数になるように、フィールドとフィールドの間に隙間を空けたり、フィールドを並べ替えたりしています。この、所定の倍数の位置にフィールドを並べる処理をアラインメントと呼びます。</p>
<p>例えば、以下のような構造体を書いたとします。A, C (<code>byte</code>型)が1バイト、B (<code>long</code>型)が8バイトのデータです。</p>
<pre class="source" title="アラインメント説明用のサンプル構造体">
<code><reserved></span><span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}
</code></pre>
<p>アラインメントの間隔はコンパイラーやCPUによって変わりますが、一例として、この構造体のメモリ レイアウトは以下のようになります。</p>
<p><img src="/media/1082/sequentiallayout.png" alt="Sample構造体のレイアウト" /></p>
<p>フィールドすべてが8の倍数アドレスに並ぶように、8バイト間隔でフィールドが並びます。
また、末尾にも、全体が8の倍数になるように未使用領域が追加されます。</p>
<h2><a id="inspection">C#でレイアウトを調べてみる</h2>
<p>C#でも、<a href="http://ufcpp.net/study/csharp/sp_unsafe.html#unsafe">unsafe</a>コードを使えば、構造体のレイアウトを調べることができます。
以下のように、ポインターを使って、構造体の先頭と、各フィールドのアドレスの差を見れば、レイアウトがわかります。</p>
<pre class="source" title="ポインターを使ってレイアウトを調べるコード">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">unsafe</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> a = <span class="reserved">default</span>(<span class="type">Sample</span>);
        <span class="reserved">var</span> p = &amp;a;
        <span class="reserved">var</span> pa = &amp;a.A;
        <span class="reserved">var</span> pb = &amp;a.B;
        <span class="reserved">var</span> pc = &amp;a.C;

        <span class="type">Console</span>.WriteLine(<span class="string">$@"サイズ: </span>{<span class="reserved">sizeof</span>(<span class="type">Sample</span>)}
<span class="string">A: </span>{(<span class="reserved">long</span>)pa - (<span class="reserved">long</span>)p}
<span class="string">B: </span>{(<span class="reserved">long</span>)pb - (<span class="reserved">long</span>)p}
<span class="string">C: </span>{(<span class="reserved">long</span>)pc - (<span class="reserved">long</span>)p}
<span class="string">"</span>);
    }
}
</code></pre>
<p>ただし、1つ注意があります。C#では、たとえunsafeコード内であっても、参照型のアドレスは取れないようになっています。
そのため、参照型や、参照型を含んだ構造体の場合はレイアウトを調べられません。</p>
<pre class="source" title="参照型のアドレスは取れないので、レイアウトも調べられない">
<code><span class="reserved">using</span> System;

<span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> I;
    <span class="reserved">public</span> <span class="reserved">string</span> S;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">unsafe</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> a = <span class="reserved">default</span>(<span class="type">Sample</span>);
        <span class="reserved">var</span> p = &amp;a;    <span class="comment">// コンパイル エラー: 参照型を含んだ構造体はアドレス取れない</span>
        <span class="reserved">var</span> pi = &amp;a.I;
        <span class="reserved">var</span> ps = &amp;a.S; <span class="comment">// コンパイル エラー: 参照型メンバーのアドレスは取れない</span>

        <span class="type">Console</span>.WriteLine((<span class="reserved">long</span>)pi - (<span class="reserved">long</span>)p);
        <span class="type">Console</span>.WriteLine((<span class="reserved">long</span>)ps - (<span class="reserved">long</span>)p);
    }
}
</code></pre>
<h2><a id="layout-kind">レイアウトの指定</h2>
<p>C#では、<code>StructLayout</code>属性(<code>System.Runtime.InteropServices</code>名前空間)を付けることで、レイアウト方式をカスタマイズ可能です。</p>
<p>以下の3種類のレイアウト方式を選択できます。</p>
<ul>
<li>Sequential: フィールドを宣言した順番通りに並べる</li>
<li>Auto: コンパイラー裁量で並び替えを認める</li>
<li>Explicit: 複合型の作者が明示的に位置を指定する</li>
</ul>
<p>ちなみに、何も指定しない場合、構造体はSequentialレイアウト、クラスはAutoレイアウトになります。</p>
<p>また、フィールドとフィールドに何バイトの間隔を空けるか(Pack)を指定することもできます。</p>
<h3><a id="sequential-layout">Sequentialレイアウト</h3>
<p>Sequentialレイアウトでは、複合型のフィールドは宣言した順序通りにレイアウトされます。
<code>StructLayout</code>属性の引数に、<code>LayoutKind.Sequential</code>を渡します。</p>
<pre class="source" title="Sequentialレイアウトの例">
<code><span class="reserved">using</span> System.Runtime.InteropServices;

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Sequential)]
<span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}
</code></pre>
<p>アラインメントの説明で挙げたのと同じ絵になりますが、このコードは以下のようなレイアウトになります。</p>
<p><img src="/media/1082/sequentiallayout.png" alt="Sequentialレイアウトの例" /></p>
<p>構造体では、特に何も指定しないとSequentialレイアウトになります。
順序通りに並べるとコンパイラーごとの差異が生まれにくく、相互運用がしやすいからでしょう
(構造体はネイティブコードとの相互運用に使うことが結構多い)。</p>
<h3><a id="pack">Pack指定</h3>
<p>間隔の開け方(Pack)は、通常は、32ビットCPUであれば4 (4バイト = 32ビット)、64ビットCPUであれば8 (8バイト = 64ビット)です
(それが一番高速になる可能性が高い)。</p>
<p>Packを明示的に指定したい場合には、以下のように、<code>StructLayout</code>属性の<code>Pack</code>プロパティに数値を与えます。</p>
<pre class="source" title="StructLayout属性のPackプロパティを指定">
<code><span class="reserved">using</span> System.Runtime.InteropServices;

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Sequential, Pack = 8)]
<span class="reserved">struct</span> <span class="type">Pack8</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Sequential, Pack = 4)]
<span class="reserved">struct</span> <span class="type">Pack4</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Sequential, Pack = 2)]
<span class="reserved">struct</span> <span class="type">Pack2</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Sequential, Pack = 1)]
<span class="reserved">struct</span> <span class="type">Pack1</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}
</code></pre>
<p>これで、以下のようなレイアウトになります。</p>
<p><img src="/media/1083/structpack.png" alt="Pack指定した結果のレイアウト" /></p>
<h3><a id="auto-layout">Autoレイアウト</h3>
<p>Autoレイアウトでは、コンパイラー裁量でフィールドの順序変更を許します。
<code>StructLayout</code>属性の引数に、<code>LayoutKind.Auto</code>を渡します。</p>
<p>通常、<code>int</code>型(4バイト)は4の倍数に、<code>long</code>型(8バイト)は8の倍数位置に並ぶようにしつつ、
隙間をより小さい型で埋めたりして、型のサイズが最小になるように並び替えが行われます。</p>
<p>例えば、以下のような構造体を書いた場合を考えます。</p>
<pre class="source" title="Autoレイアウトの例">
<code><reserved></span><span class="reserved">using</span> System.Runtime.InteropServices;

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Auto, Pack = 8)]
<span class="reserved">struct</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}
</code></pre>
<p>この場合、
<code>byte</code>型のフィールド2つを固めて後ろに持っていくことで、<code>long</code>型のBのアラインメントは揃えつつ、構造体のサイズを小さくします。
結果、以下のような12バイトのレイアウトになります。</p>
<p><img src="/media/1084/autolayout.png" alt="Autoレイアウトの例" /></p>
<p>(ただし、32ビット CPU の場合。これが64ビットCPUの場合はアラインメントが8バイト単位になって、 <code>Sample</code> 構造体は16バイトになります。)</p>
<p>ちなみに、クラスでは、特に何も指定しないとAutoレイアウトになります。</p>
<h3><a id="explicit-layout">Explicitレイアウト</h3>
<p><code>StructLayout</code>属性の引数に、<code>LayoutKind.Explicit</code>を指定して、
フィールドに<code>FieldOffset</code>属性を付けることで、
フィールドの位置を明示的に指定することができます。</p>
<p>例えば、以下のような構造体を書いた場合を考えます。</p>
<pre class="source" title="Explicitレイアウトの例">
<code><span class="reserved">using</span> System.Runtime.InteropServices;

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Explicit)]
<span class="reserved">struct</span> <span class="type">Sample</span>
{
    [<span class="type">FieldOffset</span>(1)]
    <span class="reserved">public</span> <span class="reserved">byte</span> A;
    [<span class="type">FieldOffset</span>(4)]
    <span class="reserved">public</span> <span class="reserved">long</span> B;
    [<span class="type">FieldOffset</span>(15)]
    <span class="reserved">public</span> <span class="reserved">byte</span> C;
}
</code></pre>
<p>以下のような変な隙間が空いたレイアウトになります。</p>
<p><img src="/media/1085/explicitlayout.png" alt="Explicitレイアウトの例" /></p>
<h4><a id="union">フィールドの位置を重ねる</h4>
<p>Explicitレイアウトを使うと、複数のフィールドの位置を重ねることもできます。
すなわち、C言語のunionのようなことができます。</p>
<p>例えば、以下のようなことができます。</p>
<pre class="source" title="union的な使い方の例">
<code><reserved></span><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.InteropServices;

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Explicit)]
<span class="reserved">struct</span> <span class="type">Union</span>
{
    [<span class="type">FieldOffset</span>(0)]
    <span class="reserved">public</span> <span class="reserved">byte</span> A;

    [<span class="type">FieldOffset</span>(1)]
    <span class="reserved">public</span> <span class="reserved">byte</span> B;

    [<span class="type">FieldOffset</span>(2)]
    <span class="reserved">public</span> <span class="reserved">byte</span> C;

    [<span class="type">FieldOffset</span>(3)]
    <span class="reserved">public</span> <span class="reserved">byte</span> D;

    [<span class="type">FieldOffset</span>(0)] <span class="comment">// A と一緒</span>
    <span class="reserved">public</span> <span class="reserved">int</span> N;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="reserved">var</span> x = <span class="reserved">new</span> <span class="type">Union</span> { N = 0x12345678 };
        <span class="type">Console</span>.WriteLine(x.A.ToString(<span class="string">"x"</span>)); <span class="comment">// 78</span>
        <span class="type">Console</span>.WriteLine(x.B.ToString(<span class="string">"x"</span>)); <span class="comment">// 56</span>
        <span class="type">Console</span>.WriteLine(x.C.ToString(<span class="string">"x"</span>)); <span class="comment">// 34</span>
        <span class="type">Console</span>.WriteLine(x.D.ToString(<span class="string">"x"</span>)); <span class="comment">// 12</span>
    }
}
</code></pre>
<pre class="console" title="実行結果">
<code>78
56
34
12
</code></pre>
<p><code>int</code>型のフィールド<code>N</code>に書き込んだ結果を、1バイト1バイト、個別に取り出しています。</p>
<p>ちなみに、下位バイト(この例では78)が先頭(フィールド<code>A</code>)に来るか末尾(フィールド<code>D</code>)に来るかはCPUによります(「エンディアン(endian)」と言います)。
Intel CPUの場合は先頭に来ます(little endianと言います。この逆はbig endian)。</p>
<h4><a id="abuse-union">余談: Explicitレイアウトの悪用例</h4>
<p>C# 8.0 で挙動が変わったんですが、昔の C# では、「true でも false でもない bool 型」を作ることができました。
(詳しくは「<a href="/study/csharp/datatype/typeswitch/?p=5#bool-exhaustiveness">余談: bool の網羅性</a>」で説明しています。)</p>
<p>以前の C# では、Explicit レイアウトを悪用して、(<a href="/study/csharp/sp_unsafe.html">unsafe</a> すら要らずに)この「true でも false でもない bool 型」を作れて、switch ステートメントで変な挙動を起こしていました。</p>
<p><span class="expand-button" title="展開/折畳">（古い C# での挙動）</span></p>
<div class="expand-panel" title="（古い C# での挙動）">
<p>Explicitレイアウトでフィールドの位置を重ねられることで、
結構たちが悪い悪用ができたりします。
例えば、本来あり得ない値を作ったりできます。</p>
<p>通常、C#の<code>bool</code>型が<code>true</code>か<code>false</code>の2つの値しかとりません。
しかし、別の型のフィールドと重ねて、無理やり上書きすることで、他の値にできます。
例えば以下のようなコードが書けます。</p>
<pre class="source" title="Explicitレイアウトの悪用例">
<code><reserved></span><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Runtime.InteropServices;

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Explicit)]
<span class="reserved">struct</span> <span class="type">Union</span>
{
    [<span class="type">FieldOffset</span>(0)]
    <span class="reserved">public</span> <span class="reserved">bool</span> Bool;

    [<span class="type">FieldOffset</span>(0)] <span class="comment">// Bool と同じ場所</span>
    <span class="reserved">public</span> <span class="reserved">byte</span> Byte;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        Write(<span class="reserved">false</span>);   <span class="comment">// False</span>
        Write(<span class="reserved">true</span>);    <span class="comment">// True</span>

        Write(Bool(0)); <span class="comment">// False … false と一緒</span>
        Write(Bool(1)); <span class="comment">// True … true と一緒</span>
        Write(Bool(2)); <span class="comment">// Other!</span>
    }

    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">bool</span> Bool(<span class="reserved">byte</span> value)
    {
        <span class="reserved">var</span> union = <span class="reserved">new</span> <span class="type">Union</span>();
        union.Byte = value;
        <span class="reserved">return</span> union.Bool;
    }

    <span class="reserved">static</span> <span class="reserved">void</span> Write(<span class="reserved">bool</span> x)
    {
        <span class="reserved">switch</span> (x)
        {
            <span class="reserved">case</span> <span class="reserved">true</span>:
                <span class="type">Console</span>.WriteLine(<span class="string">"True"</span>);
                <span class="reserved">break</span>;
            <span class="reserved">case</span> <span class="reserved">false</span>:
                <span class="type">Console</span>.WriteLine(<span class="string">"False"</span>);
                <span class="reserved">break</span>;
            <span class="reserved">default</span>:
                <span class="type">Console</span>.WriteLine(<span class="string">"Other!"</span>);
                <span class="reserved">break</span>;
        }
    }
}
</code></pre>
<pre class="console" title="実行結果">
<code>False
True
False
True
Other!
</code></pre>
<p>C#の<code>true</code>、<code>false</code>は、内部的にはそれぞれ1, 0の数値になっていることが分かります。
そして、それ以外の数値を指定すると、<code>switch</code>の飛び先が変わります。</p>
<p>ちなみに、0以外の数値は、真偽判定(<code>if</code>ステートメントの条件式内とか)で使うと<code>true</code>扱いになります。
<code>ToString</code>の結果も<code>True</code>です。
<code>switch</code>ステートメントでだけ変な結果を起こせます。</p>
</div>
<h4><a id="illegal-layout">余談: 値と参照を重ねる</h4>
<p>Explicitレイアウトには1つ制限があります。
値型のフィールドと参照型のフィールドを同じ位置に重ねてレイアウトすることはできません。</p>
<p>ただし、コンパイル エラーにはならず、実行時エラーです。
(C#の制限ではなくて、.NETランタイムの制限なので、実行時にしかエラーを拾えない。)
例えば、以下のようなコードを書くと、<code>TypeLoadException</code>が発生します。</p>
<pre class="source" title="Explicitレイアウトで値と参照を重ねる例">
<code><span class="reserved">using</span> System.Runtime.InteropServices;

[<span class="type">StructLayout</span>(<span class="type">LayoutKind</span>.Explicit)]
<span class="reserved">struct</span> <span class="type">Sample</span>
{
    [<span class="type">FieldOffset</span>(0)]
    <span class="reserved">public</span> <span class="reserved">int</span> A;

    <span class="comment">// 値と参照を同じ場所にレイアウト</span>
    <span class="comment">// コンパイル エラーにはならない</span>
    [<span class="type">FieldOffset</span>(0)]
    <span class="reserved">public</span> <span class="reserved">object</span> B;
}

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">unsafe</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// Sample 型に触れた瞬間、実行時エラーになる</span>
        <span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>();
    }
}
</code></pre>
<p>この制限は、<a href="http://ufcpp.net/study/computer/MemoryManagement.html#garbage-collection">ガベージ コレクション</a>の都合です。
ガベージ コレクションは、参照をたどって誰からも参照されていないオブジェクトを探索するわけですが、
ここで、本当に参照なのかどうかがわからないものがあると探索に支障をきたします。
値と参照が重なっていると、この状態が生まれます。</p>
<p>ちなみに、プログラミング言語によっては、同じメモリ領域に値と参照をどちらでも格納できるものもあります。
そういう言語の場合は、以下のいずれかの処理を行っています。</p>
<ul>
<li>ガベージ コレクションを持たない</li>
<li>
すべて参照扱いにしてガベージ コレクションを走らせる
<ul>
<li>もちろん、本来参照じゃない場所まで参照扱いするので、回収漏れがあり得ます</li>
</ul>
</li>
<li>
値か参照かを弁別のために、メモリ領域の最上位ビットとかをフラグとして使う
<ul>
<li>こういう言語では、整数が31ビットしか使えなかったりします(C#みたいな言語の半分の大きさ)</li>
</ul>
</li>
</ul>
 ]]></description>
				<pubDate>Tue, 14 Jun 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C# 1.0</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/ap_ver1/</link>
				<description><![CDATA[ <h2>C# 1.0</h2>
<table>
<tr>
<th>リリース時期</th>
<td>2002/2</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>Visual Studio .NET 2002</li>
<li>.NET Framework 1.0</li>
<li>Visual Basic 7</li>
</td>
</tr>
</table>
<p>C#は2000年6月に発表され、それから間もなくプレビュー版が公開されました。その後、2002年に正式リリースになっています。</p>
<p>当時、C#開発の指揮を取っていたAnders Hejlsbergは、元々Borland社でTurbo PascalやDelphiを作っていました。
マイクロソフトに移籍したのちはJ++ (Windows向けのJava拡張言語)に関わっています。
その後、大人の事情でマイクロソフトがJavaから撤退することになって、代わりに生まれたのがC#と言えます。</p>
<p>また、それ以前のWindows開発と言えば、主にC++かVisual Basicが用いられていました。
そこで、新言語であるC#の目標は、「C++の性能と、Visual Basicの生産性を兼ね備えた言語」でした。</p>
<p>このような背景から、C#は、Java、Delphi、Visual Basic、C++などから影響を受けた言語になっています。
C# 1.0時代は、Javaが一番近い言語でした。
そのJavaと比べてC#が特徴的だったのは以下のような機能です。</p>
<ul>
<li>
他の言語からの影響
<ul>
<li><a href="http://ufcpp.net/study/csharp/sp_delegate.html">デリゲート</a></li>
<li><a href="http://ufcpp.net/study/csharp/oo_property.html">プロパティ</a></li>
<li><a href="http://ufcpp.net/study/csharp/oo_operator.html">演算子</a></li>
</ul>
</li>
<li>
性能面の向上
<ul>
<li><a href="http://ufcpp.net/study/csharp/oo_reference.html">値型</a></li>
<li><a href="http://ufcpp.net/study/csharp/sp_unsafe.html">unsafe</a></li>
</ul>
</li>
<li>
過去の資産との相互運用
<ul>
<li><a href="http://ufcpp.net/study/csharp/interop/sp_pinvoke/">P/Invoke</a></li>
<li><a href="http://ufcpp.net/study/csharp/sp4_cominterop.html">COM相互運用</a></li>
</ul>
</li>
</ul>
<p>また、Javaでいうところの「Java言語」と「Java仮想マシン」のレイヤーがはっきりと分かれています
(Java言語にあたるのがC#、Java仮想マシンにあたるのが.NET Frameworkです)。
これは、同じ仮想マシン上に異なるプログラミング言語(当時で言うと、Visual BasicとC++/CLI)を実装しているためです。
C++/CLIで書いたクラスを、Visual Basicで継承して、それをC#から使うといったようなことができます。</p>
<h2>C# 1.1？ C# 1.2？</h2>
<table>
<tr>
<th>リリース時期</th>
<td>2003/4</td>
</tr>
<tr>
<th>同世代技術</th>
<td>
<ul>
<li>Visual Studio .NET 2003</li>
<li>.NET Framework 1.1</li>
<li>Visual Basic 7.1</li>
</td>
</tr>
</table>
<p>新しい技術にはバグがつきもので、Visual Studio .NET 2002から、たった1年で大幅なバグ修正が行われ、Visual Studio .NET 2003がリリースされました。
この際、C#にもほんの少しだけ手が入っています。</p>
<p>.NET Frameworkのバグ修正版が「.NET Framework 1.1」なので、それに合わせてC# 1.1と呼ばれることもあります。
一方で、仕様書的にはこれ以前に1度出し直しがあったようで、2003年の時点で「C# Language Specification 1.2」となっていることから、C# 1.2とも呼ばれます。
しかも、大した機能追加がないのでこのバージョンが言及される機会も少なく、正式にはC# 1.1なのかC# 1.2なのかははっきりしません<sup>※</sup>。</p>
<p>「2003年以前に1度出し直し」で、以下の2つが追加されています。</p>
<ul>
<li><code>string</code> を <code>foreach</code> した時に最適化が掛かる(必ずしも <code>GetEnumerator</code>が呼ばれない)</li>
<li><code>foreach</code> の最後で <code>Dispose</code> メソッドが呼ばれる</li>
</ul>
<p>また、「C# Language Specification 1.2」で追加されたのは以下の2つです。</p>
<ul>
<li><code>#line hidden</code>ディレクティブ (参考: <a href="http://ufcpp.net/study/csharp/sp_preprocess.html#prepro">プリプロセス命令</a>)</li>
<li><code>/** */</code> 形式のドキュメント コメント (参考: <a href="http://ufcpp.net/study/csharp/sp_xmldoc.html#doc">Documentation Comment</a>)</li>
</ul>
<p><sup>※</sup> 1.1と1.2の両方の記述が見つかるし、「Visual Studio .NET 2003におけるC#の新機能」みたいな書き方でバージョンが明記されていなかったりするし。</p>
 ]]></description>
				<pubDate>Sat, 11 Jun 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>数値</title>
				<link>http://www.ufcpp.net/study/csharp/start/stnumber/</link>
				<description><![CDATA[ <h2><a id="abstract">概要</h2>
<p>本項では、<a href="http://ufcpp.net/study/csharp/st_embeddedtype.html">組み込み型</a>の補足として、<a href="http://ufcpp.net/study/csharp/st_embeddedtype.html#integer">整数型</a>や<a href="http://ufcpp.net/study/csharp/st_embeddedtype.html#float">浮動小数点数型</a>など、いわゆる「数値」がらみの少し細かい話をします。</p>
<h2><a id="int-double">int型とdouble型</h2>
<p>C#の数値型には、使用する記憶領域サイズ違いのものがいくつかあります。その中で代表的な位置づけにあるのは、整数では<code>int</code>型(4バイト)、浮動小数点数では<code>double</code>型(8バイト)です。</p>
<p>どう「代表的」かというと以下のような感じです。</p>
<ul>
<li><code>int</code>型より小さいサイズの整数は、計算時にいったん<code>int</code>扱いされる</li>
<li>浮動小数点数は、計算時にいったん<code>double</code>扱いされる</li>
<li>リテラルも、数字だけを書くと基本的に<code>int</code>、<code>double</code>扱い</li>
</ul>
<p>例えば、下図のように、<code>short</code>型(2バイト)同士の計算をすると、結果が<code>int</code>型になります。</p>
<p><img src="/media/1077/int.png" alt="整数型同士の計算結果はintに" /></p>
<p>これは、大体必要とされる桁数が<code>int</code>型か<code>double</code>型で十分まかなえるため、これらの計算が一番高速になるようなCPUが多いという理由があります。
(実際にはいろんな要因がからんで、<code>int</code>型か<code>double</code>型を使っておけば安泰というわけでもなく、何が最適かは状況によります。
CPU構造の流行など、時代による差もあったりします。最近だと<code>double</code>型(8バイト)よりも<code>float</code>型の方が有利になる場面も多いです。)</p>
<h2><a id="base">10進数以外の数値</h2>
<p>普通に整数リテラルを書くと10進数なわけですが、その他に、16進数と2進数で書くことができます。</p>
<p>16進数や2進数については「<a href="http://ufcpp.net/study/computer/DigitsInComputer.html#bin-oct-hex">コンピューターでよく使う数字</a>」を参照してください。</p>
<h3><a id="hexadecimal">16進数リテラル</h3>
<p>普通に数字を並べると10進数扱いされますが、先頭に<code>0x</code>を付けると16進数で数値を書けるようになります(hexadecimal literals)。</p>
<pre class="source" title="16進数リテラル">
<code><span class="reserved">var</span> x = 0xFF;       <span class="comment">// 16進数のFF = 15×16 + 15 = 10進数だと 255</span>
<span class="reserved">var</span> y = 0XabcdABCD; <span class="comment">// 0X や、A～F の記号は大文字・小文字どちらでもOK</span>
</code></pre>
<h3><a id="binary">2進数リテラル</h3>
<h5 class="version version7">Ver. 7</h5>
<p>C# 7で、2進数でもリテラルを書けるようになりました(binary literals)。
先頭に<code>0b</code>を付けると2進数リテラルになります。</p>
<pre class="source" title="2進数リテラル">
<code><span class="reserved">var</span> x = 0b10010101; <span class="comment">// 2進数の10010101 = 128 + 16 + 4 + 1 = 10進数だと 149</span>
<span class="reserved">var</span> y = 0B1111;     <span class="comment">// b は大文字・小文字どちらでもOK</span>
</code></pre>
<p>よくある用途としては、「フラグ」があります。
以下のように、ビットごとに意味があって、ビットの組み合わせを表したい場合です。</p>
<pre class="source" title="2進数リテラルのフラグ利用">
<code><reserved></span><span class="reserved">enum</span> <span class="type">ColorFlags</span>
{
    Black = 0,

    Red = 1,
    Green = 0b10,
    Blue = 0b100,

    Yellow = Red | Green,
    Cyan = Green | Blue,
    Magenta = Blue | Red,

    White = Red | Green | Blue,
}
</code></pre>
<p>この例では、1ビット目が赤(red)、2ビット目が緑(green)、3ビット目が青(blue)を表していて、
「赤と緑の組み合わせが黄色(yellow)」というのを、1ビット目と2ビット目が1なので、2進数で11(つまり、10進数で3)という数値で表しています。
こういう表し方を、特定の場所に旗(flag)を立てて目印にするのに例えて、「フラグ」と呼びます。</p>
<h3><a id="initial0">数値リテラルの先頭は 0～9</h3>
<p>16進数リテラルも2進数リテラルも、どちらも0から始まります(それぞれ、<code>0x</code>か<code>0b</code>始まり)。
10進数リテラルも数字(0～9のいずれか)から始まるわけで、数値リテラルは常に数字始まりです。</p>
<p>一方で、C#では識別子(変数名などに使える名前)に数字始まりを認めていません。例えば0から始まる名前の変数は作れません。
最初の1文字だけを見て、それが識別子なのか数値リテラルなのかを判別できます。</p>
<p>C#で書かれたソースコードの解釈を高速に行うためにこういう仕様になっています。</p>
<h2><a id="digit-separator">数字区切り文字</h2>
<h5 class="version version7">Ver. 7</h5>
<p>C# 7では、数値リテラルの数字と数字の間に、<code>_</code>で区切りを入れれるようになりました。
リテラルの桁数が大きい時に便利です。</p>
<pre class="source" title="digit separators">
<code><reserved></span><span class="reserved">var</span> million = 1_000_000;
<span class="reserved">var</span> abcd = 0b1010_1011_1100_1101; <span class="comment">// 特に2進数リテラルで有用</span>
<span class="reserved">var</span> abcd2 = 0xab_cd;              <span class="comment">// 16進数リテラルにも使える</span>
<span class="reserved">var</span> x = 1.123_456_789;            <span class="comment">// 浮動小数点数リテラルにも使える</span>
</code></pre>
<p>特に2進数リテラルを使うと桁が大きくなりがちなので、<a href="http://ufcpp.net/study/csharp/start/stnumber/#binary">2進数リテラル</a>との組み合わせが便利でしょう。</p>
<p>ちなみに、末尾や先頭、小数点の前後に <code>_</code> を書くことはできません。以下のコードは全行でコンパイル エラーになります。</p>
<pre class="source" title="_ を挟めない個所">
<code><reserved></span><span class="reserved">var</span> a = _10;
<span class="reserved">var</span> b = 10_;
<span class="reserved">var</span> c = 1._0;
<span class="reserved">var</span> d = 1_.0;

<span class="comment">// (以下の2つは C# 7.2 以降であれば書ける)</span>
<span class="reserved">var</span> e = 0x_10;
<span class="reserved">var</span> f = 0b_10;
</code></pre>
<h3><a id="leading-separator">先頭区切り文字</h3>
<h5 class="version version7_1">Ver. 7.2</h5>
<p>C# 7.2で、<code>0b</code>、<code>0x</code>の直後に区切り文字の <code>_</code> を入れることができるようになりました。</p>
<pre class="source" title="">
<code><span class="comment">// C# 7.0 から書ける</span>
<span class="reserved">var</span> b1 = 0b1111_0000;
<span class="reserved">var</span> x1 = 0x0001_F408;

<span class="comment">// C# 7.2 から書ける</span>
<span class="comment">// b, x の直後に _ 入れてもOKに</span>
<span class="reserved">var</span> b2 = 0b_1111_0000;
<span class="reserved">var</span> x2 = 0x_0001_F408;
</code></pre>
<p>C# 7.2で認められたのはあくまで <code>0b</code> と <code>0x</code> の直後だけです。
以下の4つは C# 7.2 であっても書けません。</p>
<pre class="source" title="C# 7.2 でも _ を挟めない個所">
<code><reserved></span><span class="reserved">var</span> a = _10;
<span class="reserved">var</span> b = 10_;
<span class="reserved">var</span> c = 1._0;
<span class="reserved">var</span> d = 1_.0;
</code></pre>
<p>「C# 7.0時点では迷ったので、入れない方に倒した」程度のものです。
(後から機能を追加するのは簡単にできますが、
1度入れてしまった機能は問題があってもなくすことができないため。)
迷った理由は、「数字(digit)の区切り」という割には<code>b</code>や<code>x</code>が数字ではないためと、
<code>_10</code> と書くと識別子扱いされるので <code>0b_10</code>や<code>0x_10</code>を認めるのに多少抵抗があったためだそうです。</p>
<h2><a id="plan">他、書く予定</h2>
<p>(書きかけ)</p>
<ul>
<li>科学表記リテラルについて多少詳しめに</li>
<li>浮動小数点数リテラルは <code>.</code> から始めてもOK</li>
<li>
整数サフィックスの<code>L</code>, <code>U</code>は大文字小文字、順序自由: <code>U</code> <code>u</code> <code>L</code> <code>l</code> <code>UL</code> <code>Ul</code> <code>uL</code> <code>ul</code> <code>LU</code> <code>Lu</code> <code>lU</code> <code>lu</code> どれでもOK
<ul>
<li>数字の1と紛らわしいので小文字の<code>l</code>はあんまり使わないけども</li>
</ul>
</li>
<li>
<a href="http://ufcpp.net/study/computer/FloatingPointNumber.html">浮動小数点数</a>に触れておく
<ul>
<li>無限大とNaN</li>
</ul>
</li>
<li>
IEEE 754規格
<ul>
<li>float, doubleはIEEE 754規格</li>
<li>decimalは規格に沿ってない(decimal向けのIEEE規格は、C#ができた当時にはなかった)</li>
</ul>
</li>
</ul>
 ]]></description>
				<pubDate>Sun, 22 May 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] 構文の進化</title>
				<link>http://www.ufcpp.net/study/csharp/misc/misclanguageevolution/</link>
				<description><![CDATA[ <p>この記事はソフトウェアデザインに寄稿した内容が元になっています。</p>
<blockquote>
<p>初出： 技術評論社刊『ソフトウェアデザイン 2016 年 4 月 号<br>
　　　　今すぐ実践できる良いプログラムの書き方<br>
　　　　C#編 言語機能の進化から学ぶ「良いコードの書き方」</p>
</blockquote>
<h2><a id="abstract">概要</h2>
<p>プログラムの「良い書き方」は時代とともに進歩しています。そして、それが定着するとともに、プログラミング言語にも「良い書き方」をサポートする新しい構文が徐々に追加されていきます。
ここでは、C#の<a href="http://ufcpp.net/study/csharp/oo_property.html">プロパティ</a>構文を例に、「良い書き方」とともに言語構文が進歩していった過程を紹介します。</p>
<p><a href="http://ufcpp.net/study/csharp/oo_property.html">プロパティ</a>は、クラスの実装側にとってはメソッドのような振る舞いを書け、クラスの利用側にとっては<a href="http://ufcpp.net/study/csharp/st_struct.html#field">フィールド</a>の読み書きのように書けるメンバーです。</p>
<p>C#のプロパティ構文は、C#のバージョンアップに伴い何度か機能追加されています。時とともに徐々に、より良い書き方や、典型的な書き方が明らかになった結果です。
そこでここでは、C#のプロパティ構文の変遷と、それがどういう要件に基づいているのかを説明していきます。</p>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/tree/master/Demo/2016/GoodCode/src/PropertySample">サンプル コード</a></li>
</ul>
<h2><a id="accessor">getter/setter</h2>
<p>C#以前からある良いとされる習慣の1つに、「クラスの持つデータは必ずメソッドを通して返せ、<a href="http://ufcpp.net/study/csharp/st_struct.html#field">フィールド</a>を公開するな」というものがあります。メソッドを通すことで以下のような利点があるためです。</p>
<ul>
<li>実装方法を選べる</li>
<li>単純なデータの読み書きだけではなく、追加の処理を挟める</li>
<li>実装方法を後から変えても、クラス利用側への影響が出ない</li>
<li>virtualにすることで、派生クラスで挙動を変更できる</li>
</ul>
<p>そこで、例えば<code>X</code>というデータを読み書きする際には、<code>GetX</code>, <code>SetX</code>というメソッドを介する習慣ができました。これらのメソッドをそれぞれgetter/setterといい、2つ合わせてアクセサー(accessor)と呼びます。単純なデータの読み書きであっても以下のように<code>Get</code>/<code>Set</code>メソッドを書くべきということです。</p>
<pre class="source" title="Get/Setメソッド">
<code><reserved></span><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> _x;
    <span class="reserved">public</span> <span class="reserved">int</span> <em>GetX</em>() { <span class="reserved">return</span> _x; }
    <span class="reserved">public</span> <span class="reserved">void</span> <em>SetX</em>(<span class="reserved">int</span> x) { _x = x; }
}
</code></pre>
<p>このような書き方には前述のようなメリットがある一方で、クラス利用側のコードが煩雑になるという問題があります。例えば、<code>X</code>の値に1加えるだけでも以下のような書き方が必要になります。</p>
<pre class="source" title="クラス利用側のGet/Setメソッド参照">
<code><reserved></span><span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>();
s.SetX(s.GetX() + 1);
</code></pre>
<p>そこで、C#では、プロパティという構文を用意しました。以下のように書きます。</p>
<pre class="source" title="C# 1.0のプロパティ">
<code><reserved></span><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> _x;
<em>    <span class="reserved">public</span> <span class="reserved">int</span> X
    {
        <span class="reserved">get</span> { <span class="reserved">return</span> _x; }
        <span class="reserved">set</span> { _x = <span class="reserved">value</span>; }
    }</em>
}
</code></pre>
<p><code>get</code>, <code>set</code>に続けて、メソッド的に振る舞いを書けます。一方で、利用側のコードは以下のように、フィールドの読み書きと同じように書けます。</p>
<pre class="source" title="クラス利用側のプロパティ参照">
<code><reserved></span><span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>();
<em>s.X += 1;</em>
</code></pre>
<h2><a id="set-accessibility">getterとsetterで異なるアクセシビリティ(C# 2.0)</h2>
<p>データに対して、読む(get)のと書く(set)のとではだいぶ重みが違います。一般に、書き込みの方が慎重に行う必要があります。多くの場合、読み取り(get)だけを公開(public)し、書き込み(set)はクラス内にとどめる(private)ことになるでしょう。</p>
<p>そこで、C# 2.0で、プロパティのgetとsetの<a href="http://ufcpp.net/study/csharp/oo_conceal.html#level">アクセシビリティ</a>を<a href="http://ufcpp.net/study/csharp/oo_property.html#level">別々に設定できる</a>ようになりました。例えばgetだけpublicにして、setをprivateにするには以下のような書き方をします。</p>
<pre class="source" title="getとsetで異なるアクセシビリティを指定">
<code><reserved></span><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">private</span> <span class="reserved">int</span> _x;
    <span class="reserved">public</span> <span class="reserved">int</span> X
    {
        <span class="reserved">get</span> { <span class="reserved">return</span> _x; }
        <em><span class="reserved">private</span> <span class="reserved">set</span></em> { _x = <span class="reserved">value</span>; }
    }
    <span class="reserved">public</span> Sample(<span class="reserved">int</span> x) { _x = x; }
}
</code></pre>
<h2><a id="auto-property">自動プロパティ(C# 3.0)</h2>
<p>あとから実装方法を変更するかもしれないのでメソッド(のように振る舞えるプロパティ)を使うべきといっても、実際のところ、これまでいくつか挙げたコード例がそうですが、ほとんどのプロパティは単純なフィールドの読み書きです。これらのような書き方は、「あとから変えるかもしれない」という心配のためだけに書くには少し煩雑過ぎます。</p>
<p>そこで、C# 3.0では、自動的に上記のようなフィールドとそれに対する読み書きを生成する<a href="http://ufcpp.net/study/csharp/oo_property.html#auto">自動プロパティ</a>(auto property)という機能が追加されました。以下のように、getやsetの後ろのブロックを省略することで自動プロパティになります。</p>
<pre class="source" title="自動プロパティ">
<code><reserved></span><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <em><span class="reserved">get</span>; <span class="reserved">private</span> <span class="reserved">set</span>;</em> }
    <span class="reserved">public</span> Sample(<span class="reserved">int</span> x) { X = x; }
}
</code></pre>
<p>単純なフィールドの読み書きでいい間はこの書き方をし、追加の処理が必要になった際には自動実装ではない以前通りのプロパティに変更します。</p>
<h2><a id="get-only-property">get-onlyプロパティ(C# 6)</h2>
<p>繰り返しになりますが、一般に、データの書き込みには慎重になるべきです。極端に言うと、コンストラクターでだけ値を代入して、他の場所では書き換えない方がいいことが多いです。こういう書き換え不能なデータのことをimmutable(変更不能)なデータと呼びます。</p>
<p>C# 5.0までは、immutableであることを確実に保証するためには以下のような書き方でプロパティを作る必要がありました。</p>
<pre class="source" title="C# 5.0までのimmutableプロパティの書き方">
<code><reserved></span><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">private</span> <span class="reserved">readonly</span> <span class="reserved">int</span> _x;
    <span class="reserved">public</span> <span class="reserved">int</span> X { <span class="reserved">get</span> { <span class="reserved">return</span> _x; } }
    <span class="reserved">public</span> Sample(<span class="reserved">int</span> x) { _x = x; }
}
</code></pre>
<p>時代とともに、データをimmutableにしておくことの良さが一般に広まってきました。C#でも、プロパティをimmutableに書くことが増えています。</p>
<p>そこで、C# 6ではimmutableなプロパティを書きやすくするため、<a href="http://ufcpp.net/study/csharp/oo_property.html#get-only">get-onlyプロパティ</a>という構文が追加されました。以下のように、getだけを書くことで、前述のようなreadonlyフィールドを自動生成してくれます。書き込みはコンストラクター内でだけ行えます。</p>
<pre class="source" title="get-onlyプロパティ">
<code><reserved></span><span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> X { <em><span class="reserved">get</span>;</em> }
    <span class="reserved">public</span> Sample(<span class="reserved">int</span> x) { X = x; }
}
</code></pre>
<h2><a id="record-type">レコード型(検討段階)</h2>
<p>immutableなプロパティは、値の初期化をコンストラクターで行う都合上、プロパティに対応するコンストラクター引数が必ず必要になります。前節の例でいうと、プロパティXに対して引数xがあります。これは、大文字・小文字が違うくらいで、ほぼ同じものを何度も書かされている状態です。</p>
<p>そこで、以下のような書き方で、コンストラクターとimmutableなプロパティを自動生成する構文の追加が検討がされています(C# 7には入らず、そのさらに先)。</p>
<pre class="source" title="レコード型(予定)">
<code><reserved></span><span class="reserved">class</span> <span class="type">Sample</span>(<span class="reserved">int</span> X);
</code></pre>
<p><code>X</code>以外のメンバーを書きたいときだけ追加でクラス本体を書きます。immutableなプロパティだけでいい場合には、この例のように;だけを書いて、本体を省略します。</p>
<p>この構文を<em>レコード型</em>(record type)と呼びます。ここでのレコード(record: 記録、1件のデータ)という言葉は、単純なプロパティしか持たず、純粋にデータを表現するための型という意味です。</p>
 ]]></description>
				<pubDate>Thu, 05 May 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] 小さな機能の組み合わせ</title>
				<link>http://www.ufcpp.net/study/csharp/data/datamodulararchitecture/</link>
				<description><![CDATA[ <p>この記事はソフトウェアデザインに寄稿した内容が元になっています。</p>
<blockquote>
<p>初出： 技術評論社刊『ソフトウェアデザイン 2016 年 4 月 号<br>
　　　　今すぐ実践できる良いプログラムの書き方<br>
　　　　C#編 言語機能の進化から学ぶ「良いコードの書き方」</p>
</blockquote>
<h2><a id="abstract">概要</h2>
<p>「<a href="http://ufcpp.net/study/csharp/sp3_linq.html">LINQ</a>」で説明した通り、C#にはLINQ(Language Integrated Queryの略語。リンクと読む)と呼ばれるデータ処理用の機能があります。
LINQは、正確に言うとデータ処理に関連する複数の構文やライブラリの組み合わせを指す言葉です。</p>
<p>「LINQとは何か」については<a href="http://ufcpp.net/study/csharp/sp3_linq.html">他のページで</a>で説明しますが、ここで重要なのは、「組み合わせ」という部分です。小さな機能を組み合わせて大きな目的を実現したり、汎用的な処理を組み合わせて複雑な処理を組み合わせたり、それぞれ別の担当者が書いた小さな部品を組み合わせてシステム全体を構築したり、様々な組み合わせが考えられます。</p>
<p>ここでは、C#でデータ処理を行う上で、「組み合わせ」がどう活きているかという話をしていきましょう。</p>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/tree/master/Demo/2016/GoodCode/src/LinqSample">サンプル コード</a></li>
</ul>
<h2><a id="input-process-output">入力、加工、出力</h2>
<p>1つ目は、データ列の入力元と出力先の組み合わせです。少し恣意的な例になりますが、「入力した整数列のうち、奇数のものだけ抜き出して、二乗したものを出力する」という処理を考えましょう。入力元・出力先が固定でいいならそう難しい話ではありません。例えば、コンソールからの入出力で考えると、以下のようになります。</p>
<pre class="source" title="入力から出力までを1つのメソッドで実装する例">
<code><reserved></span><span class="reserved">while</span> (<span class="reserved">true</span>)
{
    <span class="comment">// コンソールから入力</span>
    <span class="reserved">var</span> line = <span class="type">Console</span>.ReadLine();
    <span class="reserved">if</span> (<span class="reserved">string</span>.IsNullOrEmpty(line)) <span class="reserved">break</span>;
    <span class="reserved">var</span> x = <span class="reserved">int</span>.Parse(line);

    <span class="comment">// 条件選択</span>
    <span class="reserved">if</span> ((x % 2) == 1)
    {
        <span class="comment">// 値の変換</span>
        <span class="reserved">var</span> y = x * x;

        <span class="comment">// コンソールに出力</span>
        <span class="type">Console</span>.WriteLine(y);
    }
}
</code></pre>
<p>問題は、入力元/出力先はコンソールとは限らないことです。ファイルの読み書きであったり、ネット越しの受け渡しであったり、様々な入出力が考えられます。そのたびに、この例のような類のコードを書くのは非効率で、「奇数のものだけ抜き出して、二乗」という加工する部分だけを切り出して、様々な入出力と組み合わせて使えるようにすべきです。</p>
<p>これは、<code>IEnumerable&lt;T&gt;</code>(<code>System.Collections.Generic</code>名前空間)を受け取り、<code>IEnumerable&lt;T&gt;</code>を返すメソッドを作れば実現できます。<a href="http://ufcpp.net/study/csharp/sp2_iterator.html">イテレーター</a>を使えばそう難しくはありません。以下のような書き方ができます。</p>
<pre class="source" title="入力(Read)、加工(Filter)、出力(Write)の分離">
<code><comment></span><span class="comment">// コンソールから入力</span>
<span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; Read()
{
    <span class="reserved">while</span> (<span class="reserved">true</span>)
    {
        <span class="reserved">var</span> line = <span class="type">Console</span>.ReadLine();
        <span class="reserved">if</span> (<span class="reserved">string</span>.IsNullOrEmpty(line)) <span class="reserved">break</span>;
        <span class="reserved">yield</span> <span class="reserved">return</span> <span class="reserved">int</span>.Parse(line);
    }
}

<span class="comment">// 加工: 条件選択 + 変換</span>
<span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; Filter(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; source)
{
    <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> source)
        <span class="reserved">if</span> ((x % 2) == 1)
            <span class="reserved">yield</span> <span class="reserved">return</span> x * x;
}

<span class="comment">// コンソールに出力</span>
<span class="reserved">static</span> <span class="reserved">void</span> Write(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; source)
{
    <span class="reserved">foreach</span> (<span class="reserved">var</span> x <span class="reserved">in</span> source)
        <span class="type">Console</span>.WriteLine(x);
}
</code></pre>
<p>これで、下図に示すように、様々な入出力の組み合わせが使えるようになります。</p>
<p><img src="/media/1074/datapipeline.png" alt="入力、加工、出力の組み合わせ" /></p>
<h2><a id="data-pipeline">汎用処理の組み合わせ</h2>
<p>続いては小さな汎用処理の組み合わせで所望の処理を実現することについて考えます。前節の加工処理(サンプル コードの<code>Filter</code>メソッド)には、さらに細かく分けると以下の処理が含まれています。</p>
<ul>
<li>条件選択: 奇数だけ取り出す</li>
<li>変換: 二乗を計算する</li>
</ul>
<p>そして、一般に、多くのデータ処理がこの類型に当てはまります。すなわち、何らかの条件を与えて選択を行い、何らかの式に従って変換を行います。</p>
<p>実は、.NETには標準で、条件選択や変換のためのライブラリが含まれています。<code>Where</code>メソッドと<code>Select</code>メソッド(いずれも<code>System.Linq</code>名前空間の<code>Enumerable</code>クラスで定義されている<a href="http://ufcpp.net/study/csharp/oo_static.html">静的メソッド</a>)です。</p>
<ul>
<li><code>Where</code>: 条件を与えてデータを選択する</li>
<li><code>Select</code>: 式を与えてデータを変換する</li>
</ul>
<p>これらの名前は、SQLのキーワードに由来します。この他にも、<code>Enumerable</code>クラスには、データ加工用の様々なメソッドが用意されています。</p>
<p>これらを使って前節のコードと同じ処理を書き直すと、(コード中の<code>Read</code>, <code>Write</code>に対して)以下のような書き方ができます。</p>
<pre class="source" title="汎用処理の組み合わせ">
<code>Write(Read()
    .Where(x =&gt; (x % 2) == 1)
    .Select(x =&gt; x * x)
    );
</code></pre>
<p>ちなみに、<code>Where</code>, <code>Select</code>は、インスタンス メソッドと同じように<code>x.Where(...)</code>というような書き方をしていますが、実際に呼ばれるのは<code>Enumerable</code>クラスの<code>Where</code>静的メソッドです。これは、<a href="http://ufcpp.net/study/csharp/sp3_extension.html">拡張メソッド</a>と呼ばれる機能を 使っています。</p>
<p>これで、下図に示すように、汎用処理の組み合わせで所望の処理を実現できます。</p>
<p><img src="/media/1075/generaldatapipeline.png" alt="汎用処理の組み合わせ" /></p>
<h2><a id="contract-impl-process">契約、実装、処理</h2>
<p>前節で説明したような<code>IEnumerable&lt;T&gt;</code>を中心とした汎用処理には、下図に示すような3つの立場が絡みます。</p>
<p><img src="/media/1076/data3aspects.png" alt="規約、実装、処理" /></p>
<p>規約(contract)は、型が持つべきメンバーが何かを定めます。<code>IEnumerable&lt;T&gt;</code>の例でいうと、「データ列を得るためには<code>Current</code>プロパティや<code>MoveNext</code>メソッドが必要」というようなものです。これを定めるのがインターフェイスです。</p>
<p>実装(implementation)は、規約が定めるメンバーをどう実現するかです。同様の例でいうと、「配列やリストなどのクラスは<code>IEnumerable&lt;T&gt;</code>を実装しているのでデータ列を列挙できる。列挙の仕方はそれぞれのクラスによって異なる」となります。</p>
<p>そして最後に、この規約に沿えば実現できる処理(process)があります。今回の例でいうと、「<code>Where</code>や<code>Select</code>など、<code>IEnumerable&lt;T&gt;</code>から得られるデータ列を加工して、別の<code>IEnumerable&lt;T&gt;</code>を返すメソッドを作る」といったものです。</p>
<p>重要なのは、規約、実装、処理の3つは、それぞれ別の担当者が書く(ということがあるし、そうできるべき)ということです。これに対してありがちなミスは、実装クラス(ここでいう配列やリスト)に処理(ここでいう<code>Where</code>や<code>Select)</code>を含めてしまうというものです。そうやってしまうと、どんな実装にでも使えそうな汎用的な処理が特定の実装にだけ含まれることになって、組み合わせて使うことができなくなります。組み合わせを増やすために、規約、実装、処理の分離を意識しましょう。</p>
<h2><a id="modular-syntax">文法の組み合わせ</h2>
<p>この章の冒頭で「LINQとはデータ処理に関連する複数の構文の組み合わせ」という話をしました。データ処理はプログラミングにおいて重要なテーマの1つですが、それでも、汎用プログラミング言語にデータ処理専用の構文を導入するのはやりすぎでしょう(「汎用」でなくなる)。しかし、それぞれ汎用に使える小さな構文の組み合わせで実現できるなら話は別で、汎用プログラミング言語に導入する価値が高くなります。</p>
<p>詳細はそれぞれのリンク先を見てもらうとして、LINQは以下のような構文の組み合わせで実現されています。これらはすべて、C# 3.0で追加され、データ処理以外のことに対しても有用です。</p>
<ul>
<li><a href="http://ufcpp.net/study/csharp/oo_construct.html#member_initializer">オブジェクト初期化子</a></li>
<li><a href="http://ufcpp.net/study/csharp/sp3_lambda.html">ラムダ式</a></li>
<li><a href="http://ufcpp.net/study/csharp/sp3_extension.html">拡張メソッド</a></li>
<li><a href="http://ufcpp.net/study/csharp/st_variable.html#infer">変数の型推論(var)</a></li>
<li><a href="http://ufcpp.net/study/csharp/oo_class.html#anonymous">匿名型</a></li>
</ul>
 ]]></description>
				<pubDate>Wed, 04 May 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>C#スクリプト実行</title>
				<link>http://www.ufcpp.net/study/csharp/cheatsheet/apscripting/</link>
				<description><![CDATA[ <p>C#をスクリプト言語的に実行したり、インタラクティブ実行したりできるようになりました。
その実行方法や、通常の(コンパイルして使う)C#にはないスクリプト専用機能などについて説明します。</p>
<h2><a id="abstract">概要</h2>
<p>2015年末頃、ついにC#をスクリプト言語的に実行したり、インタラクティブに実行したりできるようになりました。すなわち、以下のようなことができるようになりました。</p>
<ul>
<li>
アプリへの組み込み
<ul>
<li>アプリに組み込んで、そのアプリ用のマクロ言語としてC#を使う</li>
<li>アプリを実行したままC#スクリプトを読み直して、動的にアプリの挙動を変える</li>
</ul>
</li>
<li>
REPL(Read Eval Print Loop)実行
<ul>
<li>1行1行、都度(インタラクティブに)結果を見ながらC#を書く</li>
</ul>
</li>
<li>
スクリプト実行
<ul>
<li>コマンド ライン ツールにC#スクリプト ファイルを渡して実行する</li>
<li><code>class Program { static void Main() { } }</code>みたいなノイズなしに、1行目から式やステートメントを書ける</li>
</ul>
</li>
</ul>
<p>以下、これらを総称して「スクリプト実行」と呼びます。</p>
<p>通常の(コンパイルして使う)C#で書けるものは大体はスクリプト実行できます。また、スクリプト実行時にのみ許される構文や、スクリプト実行時特有の動作がいくつかあります。</p>
<h2><a id="variety">いくつかの実行形態</h2>
<p>概要で一覧を出したように、いくつかの方法でC#スクリプト実行できます。</p>
<h3><a id="hosting">アプリへの組み込み</h3>
<p><a href="https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp.Scripting">Microsoft.CodeAnalysis.CSharp.Scripting</a>ライブラリを参照することで、自作のアプリにC#スクリプトを組み込めます。
例えば、以下のようなコードが書けます。</p>
<p>サンプル コード: <a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Scripting/src/Scripting">https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Scripting/src/Scripting</a></p>
<pre class="source" title="C#スクリプト ライブラリの利用例">
<code><reserved></span><span class="reserved">using</span> Microsoft.CodeAnalysis.CSharp.Scripting;
<span class="reserved">using</span> System;
<span class="reserved">using</span> System.Threading.Tasks;

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
    {
        MainAsync().Wait();
    }

    <span class="reserved">private</span> <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> MainAsync()
    {
        <span class="reserved">var</span> result = <span class="reserved">await</span> <span class="type">CSharpScript</span>.EvaluateAsync&lt;<span class="reserved">int</span>&gt;(<span class="string">@"
var x = 1;
var y = 2;
x + y
"</span>);
        <span class="type">Console</span>.WriteLine(result);
    }
}
</code></pre>
<h4><a id="script-globals"> スクリプトとアプリとのやり取り</h4>
<p>アプリに組み込む以上は、アプリに対する命令みたいなものをスクリプトに対して公開する必要があるわけですが、
それはこの<code>EvaluateAsync</code>などのメソッドの引数の<code>globals</code>に対してオブジェクトを渡すことで実現できます。</p>
<p>例えば、以下のようなクラスを用意します。</p>
<pre class="source" title="globalsに渡す用のコマンド発行クラス">
<code><inactive></span><span class="inactive">///</span><span class="comment"> </span><span class="inactive">&lt;summary&gt;</span>
<span class="inactive">///</span><span class="comment"> コマンド発行クラス。</span>
<span class="inactive">///</span><span class="comment"> C# スクリプトのglobalsとして渡して、スクリプトからコマンドを発行するのに使う。</span>
<span class="inactive">///</span><span class="comment"> </span><span class="inactive">&lt;/summary&gt;</span>
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Commander</span>
{
    <span class="comment">// 中略</span>

    <span class="reserved">public</span> <span class="reserved">void</span> walk(<span class="reserved">double</span> distance) =&gt; _queue.Enqueue(<span class="type">Command</span>.Walk(distance));
    <span class="reserved">public</span> <span class="reserved">void</span> turn(<span class="reserved">double</span> angle) =&gt; _queue.Enqueue(<span class="type">Command</span>.Turn(angle));
    <span class="reserved">public</span> <span class="reserved">void</span> speed(<span class="reserved">double</span> speedDotPerSecond) =&gt; _queue.Enqueue(<span class="type">Command</span>.Speed(speedDotPerSecond));
    <span class="reserved">public</span> <span class="reserved">void</span> clear() =&gt; _queue.Enqueue(<span class="type">Command</span>.Clear());
}
</code></pre>
<p>これを、<code>EvaluateAsync</code>や<code>RunAsync</code>などのスクリプトAPIの<code>globals</code>引数に渡すことで、
C#スクリプト側から、<code>walk</code>, <code>turn</code>, <code>speed</code>, <code>clear</code>などのメソッドを呼び出せるようになります。</p>
<pre class="source" title="globalsへのオブジェクトの受け渡し">
<code>_state = <span class="reserved">await</span> CSharpScript.RunAsync(s, globals: ViewModel.Commander);
</code></pre>
<p>ちなみに、このコードは、C#スクリプトを使ってタートル グラフィックスをやってみるサンプル プログラムの一部です。
コード全体は、GitHubで公開しています。</p>
<p>サンプルコード: <a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Scripting/TurtleGraphics">https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Scripting/TurtleGraphics</a></p>
<p>実際に動かしている様子は以下の通りです。</p>
<iframe width="420" height="315" src="https://www.youtube.com/embed/uex74qGWLxE" frameborder="0" allowfullscreen></iframe>
<h3><a id="interactive-window">C# インタラクティブ ウィンドウ</h3>
<p>Visual Studio 2015 Update 1から、C#をREPL実行できる「C# インタラクティブ」というウィンドウが追加されました。</p>
<p>Visual Studioのメニューから下図のようにたどるか、
Visual Studio右上にある「クイック起動」欄に下図のように「C#」と打って検索することでウィンドウを開けます。</p>
<p><img src="/media/1063/vs-menu-csi.png" alt="メニューから、C#インタラクティブ ウィンドウを開く" /></p>
<p><img src="/media/1064/vs-quick-csi.png" alt="クイック起動から、C#インタラクティブ ウィンドウを開く" /></p>
<p>C#インタラクティブ ウィンドウ内では、下図のようにコード ハイライトやコード補完が効きます。</p>
<p><img src="/media/1065/csi-code-completion.png" alt="コードのハイライトや補完" /></p>
<p>REPL(Read Eval Print Loop)なので、1行1行コードを読んで(read)、評価して(eval)、その結果を出力(print)することができます。</p>
<p><img src="/media/1066/csi-repl.png" alt="C#インタラクティブ ウィンドウを使ったREPL実行" /></p>
<h3><a id="dotnet-cli">dotnetコマンド</h3>
<p><a href="http://ufcpp.net/study/csharp/devenv/ab_devenv/#dotnetcli">dotnetコマンド</a>の1機能として、REPL実行やスクリプト実行ができます。</p>
<p>下図のように、<code>dotnet repl</code>というサブコマンドを使うことでREPLが起動します。</p>
<p><img src="/media/1067/dotnet-repl.png" alt="dotnet replサブコマンド" /></p>
<p>ちなみに、<code>dotnet repl</code>は、既定動作がC# REPLの起動というだけで、引数で他の.NET言語も選べます。
(といっても、2016年1月時点ではC#のみに対応。計画としてはVisual BasicとF#への対応も考えている模様。Visual Basicはその作業真っ最中。)</p>
<p>1行1行書けるコードは<a href="#interactive-window">C#インタラクティブ ウィンドウ</a>と同じです。
ただ、C#インタラクティブ ウィンドウと違って、コード補完などは掛かりません。
Visual Studio 2015 Update 1以降を使えるのであれば、C#インタラクティブ ウィンドウを使う方が便利でしょう。
<code>dotnet</code>コマンドはクロスプラットフォームなコマンド ライン ツールなので、GUIのない環境でも使えるという利点はあります。</p>
<p>REPLで1行1行実行する他に、スクリプト ファイルを与えて実行するモードがあります。
下図のように、<code>dotnet repl</code>サブコマンドの引数にファイル名を指定します。</p>
<p><img src="/media/1068/dotnet-csx.png" alt="dotnet replサブコマンドにスクリプト ファイルを与えて実行" /></p>
<p>ちなみに第1引数はどの言語を使うかを指定します。(前述の通り2016年1月時点ではC#のみ。csiかcsharpを入力。)
そして、第2引数が実行したいC#スクリプトのファイル名です。</p>
<p>この例では、以下のようなC#スクリプトを与えています。</p>
<pre class="source" title="C#スクリプトの例">
<code><reserved></span><span class="reserved">using</span> System;

<span class="type">Console</span>.WriteLine(<span class="type">DateTime</span>.Now);
</code></pre>
<p>見てのとおり、通常の(コンパイルして使う)C#と違って、トップ レベルにステートメントを書いて実行できます。
<code>class Program</code>や<code>static void Main()</code>などのクラス/メソッドは必ずしも必要ありません。</p>
<h2><a id="script-syntax">スクリプト実行用の構文</h2>
<p>通常の(コンパイルして使う)C#の機能はほぼ全て使えます。
例えば以下のように、通常のC#コードをそのままC#インタラクティブ ウィンドウに張り付けて実行できます。</p>
<pre class="source" title="通常のC#コードをC#インタラクティブに貼り付け">
<code>&gt; <span class="reserved">using</span> System;
. 
. <span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
. {
.     <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> Main()
.     {
.         <span class="type">Console</span>.WriteLine(<span class="string">"Hello World!"</span>);
.     }
. }
. 
&gt; <span class="type">Program</span>.Main()
Hello World!
</code></pre>
<p>一方で、スクリプト実行でだけできる書き方がいくつかあります。</p>
<h3><a id="print-expression">結果の出力</h3>
<p>式を1つだけ書いて、<code>;</code>も入力せずに改行すると、その式の結果を出力します。
例えば、以下のようなコードでは、1行目は普通のC#と同じく代入ステートメント、2行目は<code>x * x</code>という式の計算結果の出力になります。</p>
<pre class="source" title="式の計算結果の出力">
<code>&gt; <span class="reserved">var</span> x = 10;
&gt; x * x
100
</code></pre>
<p>一方で、例えば以下のような書き方はできません。
<code>;</code> を付けたことで通常のC#構文として解釈されますが、式 + <code>;</code> という構文はC#にはないのでエラーになります。</p>
<pre class="source" title="式の後ろには ; は付けちゃダメ">
<code>&gt; x * x<em>;</em>
(1,1): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
</code></pre>
<h3><a id="top-level">トップ レベル</h3>
<p>通常のC#では、トップ レベル(ソースコードの一番上)に書けるものがかなり限られています。</p>
<ul>
<li><a href="http://ufcpp.net/study/csharp/sp_preprocess.html">プリプロセス ディレクティブ</a></li>
<li><a href="http://ufcpp.net/study/csharp/sp_namespace.html#using">using ディレクティブ</a></li>
<li><a href="http://ufcpp.net/study/csharp/oo_class.html">クラス</a></li>
<li><a href="http://ufcpp.net/study/csharp/sp_namespace.html#namespace">名前空間</a></li>
<li><a href="http://ufcpp.net/study/csharp/sp_attribute.html#target">アセンブリに対する属性</a></li>
</ul>
<p>このうち、名前空間とアセンブリに対する属性は、スクリプト実行では使えません。</p>
<pre class="source" title="スクリプト実行で使えない構文">
<code>&gt; <span class="reserved">namespace</span> Sample { }
(1,1): error CS7021: スクリプト コードで名前空間を宣言することはできません
&gt; [<span class="reserved">assembly</span>:System.Reflection.<span class="type">AssemblyTitle</span>(<span class="string">"test"</span>)]
(1,2): error CS7026: アセンブリ属性とモジュール属性は、このコンテキストでは許可されていません。
</code></pre>
<p>一方、スクリプト実行時には、トップ レベルに以下のようなものが書けます。</p>
<ul>
<li>ステートメント</li>
<li>式(結果の値が出力される)</li>
<li>クラスのメンバー(メソッド、プロパティなど)</li>
</ul>
<p>例えば以下のようなコードが書けます。</p>
<pre class="source" title="トップ レベルのステートメントやメンバーの例">
<code>&gt; <span class="reserved">var</span> x = 10;
&gt; <span class="reserved">var</span> y = 20;
&gt; <span class="reserved">int</span> Product =&gt; x * y;
&gt; Product
200
&gt; x = 15;
&gt; y = 25;
&gt; Product
375
</code></pre>
<p>トップ レベルで定義した変数は特殊なスコープを持ちます。
上記の例のように、トップ レベルに書いたメンバー内では参照(この例だと<code>Product</code>プロパティ内で、変数<code>x</code>, <code>y</code>を参照)できますが、
クラスを書くと、その中からは参照できません。</p>
<pre class="source" title="">
<code>&gt; <span class="reserved">var</span> x = 10;
&gt; <span class="reserved">int</span> X =&gt; x; <span class="comment">// これはOK</span>
&gt; <span class="reserved">class</span> <span class="type">C</span> { <span class="reserved">int</span> X =&gt; x; } <span class="comment">// クラス内からは x を使えない</span>
(1,20): error CS0120: 静的でないフィールド、メソッド、またはプロパティ 'x' で、オブジェクト参照が必要です
</code></pre>
<p>ちなみに、トップ レベルに拡張メソッドも書けます。</p>
<pre class="source" title="トップ レベルの拡張メソッド">
<code>&gt; <span class="reserved">static</span> <span class="reserved">int</span> Square(<span class="reserved">this</span> <span class="reserved">int</span> x) =&gt; x * x;
&gt; 10.Square()
100
</code></pre>
<p>また、トップ レベルは、通常のC#でいうところの<a href="http://ufcpp.net/study/csharp/sp5_async.html">非同期メソッド</a>と同じ状態になっていて、常に<code>await</code>演算子が使えます。</p>
<pre class="source" title="トップ レベルはawaitを使える">
<code>&gt; <span class="reserved">#r</span> <span class="string">"System.Net.Http"</span>
&gt; <span class="reserved">using</span> System.Net.Http;
&gt; <span class="reserved">var</span> c = <span class="reserved">new</span> <span class="type">HttpClient</span>();
&gt; <span class="reserved">var</span> res = <span class="reserved">await</span> c.GetAsync(<span class="string">"http://ufcpp.net"</span>);
&gt; <span class="reserved">var</span> content = <span class="reserved">await</span> res.Content.ReadAsStringAsync();
&gt; content.Substring(0, 50)
"\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"ja\" xmlns=\"http://w"
</code></pre>
<h3><a id="directive">スクリプト用ディレクティブ</h3>
<p>スクリプト実行時にだけ使えるものとして、<a href="http://ufcpp.net/study/csharp/sp_preprocess.html">プリプロセス ディレクティブ</a>と同じ <code>#</code> から始まるいくつかのディレクティブがあります。</p>
<p>現状では以下のようなものがあります。</p>
<table>
<thead>
<tr>
	<th>ディレクティブ</th>
	<th>説明</th>
</tr>
</thead>
<tbody>
<tr>
	<td><code>#help</code></td>
	<td>ヘルプを表示します。</td>
</tr>
<tr>
	<td><code>#cls</code>, <code>#clear</code></td>
	<td>ウィンドウ内のテキストをクリアします。</td>
</tr>
<tr>
	<td><code>#reset</code></td>
	<td>コンテキスト(定義した変数やメンバーなど)をクリアします。</td>
</tr>
<tr>
	<td><code>#r</code></td>
	<td>アセンブリを読み込みます。</td>
</tr>
<tr>
	<td><code>#load</code></td>
	<td>スクリプト ファイルを読み込みます。</td>
</tr>
</tbody>
</table>
<p>例えば、<code>a.csx</code>という名前で以下のようなファイルがあったとします。</p>
<pre class="source" title="a.csx スクリプト ファイル">
<code><reserved></span><span class="reserved">var</span> x = 10;
</code></pre>
<p>この状況下で、以下のようなスクリプトを実行できます。</p>
<pre class="source" title="a.csxをloadするスクリプト">
<code>&gt; <span class="reserved">#load</span> <span class="string">"a.csx"</span>
&gt; x
10
</code></pre>
<p>ディレクティブは、これからいくつか追加も予定されています。
<code>#help</code>と打つことでヘルプが表示されるので詳しくはそれを読んでみてください。</p>
 ]]></description>
				<pubDate>Sat, 16 Jan 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] 識別子のスコープとオブジェクトの寿命</title>
				<link>http://www.ufcpp.net/study/csharp/start/st_scope/</link>
				<description><![CDATA[ <p>本項では、識別子のスコープ(有効な範囲、異なるものに同じ名前を付けれない範囲)とオブジェクトの寿命(作ったオブジェクトがいつまで生きているか、ガベージ コレクションの対象外になっているか)について説明していきます。</p>
<p>※ 本項では、現時点までに説明していない概念がいくつか出てきます。現時点で説明済みのものは<a href="http://ufcpp.net/study/csharp/st_variable.html#variable">変数</a>くらいなので、とりあえず変数が絡むところだけ読んで、残りは後々読み直してください。</p>
<h2><a id="abstract">概要</h2>
<p>ローカル変数、メンバー名(メソッドなどの名前)、型名など、開発者が自由につけれる名前のことを<strong id="identifier" class="keyword">識別子</strong>(identifier)と言います。「識別」(identify)の名のとおり、一意に区別するためにつける名前なので、基本的には複数のものに同じ名前は付けれません。</p>
<p>ただし、識別子には有効は範囲があります。この範囲を識別子の<strong id="scope" class="keyword">スコープ</strong>(scope)と言い、スコープ内では識別子名は一意でなければならず、逆に、スコープが違えば、別のものに同じ名前を付けることができます。</p>
<p>また、スコープと関連して、以下のようなものがあります。</p>
<ul>
<li>
スコープ: 別のものに同じ名前を付けられない範囲
<ul>
<li>基本的には、その識別子を囲うブロック内がスコープです</li>
</ul>
</li>
<li>
変数に格納したオブジェクトの寿命
<ul>
<li>基本的に、変数のスコープを外れれば、そのオブジェクトは不要(<a href="http://ufcpp.net/study/csharp/rm_gc.html#garbage-collection">GC</a>の対象)になります</li>
<li>ただし、<a href="http://ufcpp.net/study/csharp/sp_delegate.html#anonymous">ラムダ式</a>や<a href="http://ufcpp.net/study/csharp/sp2_iterator.html#complied">イテレーター</a>、<a href="http://ufcpp.net/study/csharp/sp5_awaitable.html">非同期メソッド</a>など、オブジェクトの寿命を延ばしてしまう構文がいくつかあります</li>
</ul>
</li>
<li>
変数を使える範囲:
<ul>
<li>スコープ内で、かつ、変数宣言より下でだけ変数を使えます</li>
<li>さらに、変数に格納した値を読み出すためには、確実に初期化してからでなければいけません</li>
</ul>
</li>
</ul>
<p>本稿では、これらについて説明して行きます。</p>
<h2><a id="scope">識別子のスコープ</h2>
<p>C#の識別子のスコープは、原則として、<em>その識別子の定義場所を囲むブロック内</em>です。例えば以下のようになります。</p>
<p><img src="/media/1059/scope1.png" alt="識別子のスコープ = 囲むブロック内" /></p>
<p>この範囲では、基本的に同じ名前は使えないということになります。</p>
<h3><a id="nested-block">入れ子のブロック</h3>
<p>スコープの範囲は、ブロックが入れ子になっている個所も含めます。
すなわち、以下のようなコードはコンパイル エラーになります。</p>
<pre class="source" title="入れ子のブロックにもスコープは及ぶ">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M()
{
    <span class="reserved">int</span> x = 10;

    {
        <span class="reserved">int</span> x = 20; <span class="comment">// ここでエラー</span>
        <span class="type">Console</span>.WriteLine(x);
    }

    <span class="type">Console</span>.WriteLine(x);
}
</code></pre>
<p>この例では<code>x</code>という名前の変数が2つあります。1つ目の<code>x</code>(10を代入している方)のスコープはメソッド<code>M</code>全体になります。2つ目の<code>x</code>(20の方)のスコープはそれよりも1回り小さい内側のブロック内になりますが、この範囲は1つ目の<code>x</code>のスコープ内でもあります。
プログラミング言語によっては、この「入れ子のレベル違い」の同名識別子を認めているものもありますが、C#では認めません。
C#は、原則として<em>スコープ内で識別子の意味を変えない・上書かない</em>という方針をとっています。</p>
<p>逆に、以下のようなコードであれば、2つの<code>x</code>がそれぞれ直近のブロック内だけをスコープにしているので、エラーにはなりません。</p>
<pre class="source" title="2つの独立したブロックは別スコープ">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M()
{
    {
        <span class="reserved">int</span> x = 10;
        <span class="type">Console</span>.WriteLine(x);
    }

    {
        <span class="comment">// 別ブロック = 別スコープ。↑のxとは完全に別物</span>
        <span class="reserved">string</span> x = <span class="string">"a"</span>;
        <span class="type">Console</span>.WriteLine(x);
    }
}
</code></pre>
<p>もう1つ注意が必要なのは、変数の定義位置がどこであろうと、スコープは直近のブロック全体になるということです。
例えば以下のコードを見てください。</p>
<pre class="source" title="スコープはあくまで直近のブロック全体">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M3()
{
    {
        <span class="comment">// 下で定義されている string の方の x と名前被り</span>
        <span class="reserved">int</span> x = 20; <span class="comment">// コンパイル エラー</span>
        <span class="type">Console</span>.WriteLine(x);
    }

    <span class="comment">// string の方の x はここから下でしか使えない</span>
    <span class="comment">// にも関わらず、x のスコープはメソッド内全体</span>
    <span class="reserved">string</span> x = <span class="string">"a"</span>;
    <span class="type">Console</span>.WriteLine(x);
}
</code></pre>
<p>2つ目の<code>x</code>(<code>string</code>の方)は下の方で定義されていますが、これのスコープはブロックの先頭からになります。
その結果、1つ目の<code>x</code>は「スコープ被り」で、同名が許されず、コンパイル エラーになります。</p>
<h3><a id="member-local">例外1: メンバーとローカル変数</h3>
<p>「入れ子のもの含めて、スコープ内では同名不可」の原則には例外もあります。
1つは、以下のように、メンバーとローカル変数には同じ名前をつけれるということです。</p>
<pre class="source" title="メンバー名とローカル変数名は同じものを付けれる">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">int</span> x = 20;

    <span class="reserved">public</span> <span class="reserved">void</span> M()
    {
        <span class="reserved">int</span> x = 10;

        <span class="type">Console</span>.WriteLine(x);      <span class="comment">// ローカル変数の方の x = 10</span>
        <span class="type">Console</span>.WriteLine(<span class="reserved">this</span>.x); <span class="comment">// フィールドの方の x = 20</span>
    }
}
</code></pre>
<p>この場合、ローカル変数側が優先されます。フィールドの方を使うためには<code>this.</code>を付けるのが必須になります。</p>
<h3><a id="type-member">例外2: 型と名前空間</h3>
<p>もう1つの例外は、型と名前空間です。外で定義された型の名前と同名のメンバーやローカル変数が作れます。</p>
<pre class="source" title="型や名前空間と同じ名前のフィールド・ローカル変数">
<code><reserved></span><span class="reserved">namespace</span> Color
{
    <span class="reserved">public</span> <span class="reserved">enum</span> <span class="type">Color</span>
    {
        Green,
        Yellow,
        Red,
    }

    <span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Sample</span>
    {
        <span class="reserved">public</span> <span class="type">Color</span> Color { <span class="reserved">get</span>; <span class="reserved">set</span>; }

        <span class="reserved">public</span> <span class="reserved">void</span> M()
        {
            <span class="type">Color</span> Color = <span class="type">Color</span>.Red;
        }
    }
}
</code></pre>
<p>この場合、どの識別子かを明確化するには、完全修飾名を使うことになります。</p>
<pre class="source" title="完全修飾名で識別子を参照">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">namespace</span> Color
{
    <span class="reserved">public</span> <span class="reserved">enum</span> <span class="type">Color</span>
    {
        Green,
        Yellow,
        Red,
    }

    <span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Sample</span>
    {
        <span class="reserved">public</span> <span class="reserved">global</span>::Color.<span class="type">Color</span> Color { <span class="reserved">get</span>; <span class="reserved">set</span>; }

        <span class="reserved">public</span> <span class="reserved">void</span> M()
        {
            <span class="reserved">global</span>::Color.<span class="type">Color</span> Color = <span class="reserved">global</span>::Color.<span class="type">Color</span>.Red;

            <span class="type">Console</span>.WriteLine(Color);
            <span class="type">Console</span>.WriteLine(<span class="reserved">this</span>.Color);
        }
    }
}
</code></pre>
<p>ちなみに、これは、あくまで型が外側のスコープで定義されている場合だけです。
以下のように、まったく同じスコープ内で定義する場合は、型名とメンバー名を同じにすることはできなくなります。</p>
<pre class="source" title="同スコープ内での同名の型とメンバー定義">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">enum</span> <span class="type">Color</span>
    {
        Green,
        Yellow,
        Red,
    }

    <span class="comment">// enum の Color と同じスコープ内でプロパティの Color を作ろうとしていて</span>
    <span class="comment">// この場合はコンパイル エラーになる</span>
    <span class="reserved">public</span> <span class="type">Color</span> Color { <span class="reserved">get</span>; <span class="reserved">set</span>; }
}
</code></pre>
<h3><a id="parameter">引数</h3>
<p>メソッドの引数のスコープは、そのメソッド本体内全域です。ほぼ、ローカル変数と扱いは一緒です。
メソッド内で、引数と同名のローカル変数は作れません。</p>
<pre class="source" title="引数の扱いはローカル変数と同じ">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">int</span> x)
{
    <span class="reserved">int</span> x = 10; <span class="comment">// コンパイル エラー</span>
    <span class="type">Console</span>.WriteLine(x);
}
</code></pre>
<p>ローカル変数と同じくスコープの例外として、メンバーと同じ名前を付けることができます。
極端な話、以下のように、メソッドと同名の引数を使うこともできます。</p>
<pre class="source" title="メソッド名と同名の引数が利用可能">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> X(<span class="reserved">int</span> X)
    {
        <span class="reserved">if</span> (X &lt;= 1) <span class="reserved">return</span> 1;
        <span class="reserved">else</span> <span class="reserved">return</span> <span class="type">Sample</span>.X(X - 1);
    }
}
</code></pre>
<h3><a id="loop">ループ変数</h3>
<p><code>for</code>ステートメントや、<code>foreach</code>ステートメントの場合、ループ変数があります。ループ変数のスコープはステートメントの内側になります。</p>
<pre class="source" title="ループ変数のスコープ">
<code><reserved></span><span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 5; i++)
{
    <span class="comment">// for の i のスコープはこのブロック内</span>
    <span class="type">Console</span>.WriteLine(i);
}

<span class="reserved">foreach</span> (<span class="reserved">var</span> i <span class="reserved">in</span> <span class="type">Enumerable</span>.Range(0, 5))
{
    <span class="comment">// foreach の i のスコープはこのブロック内</span>
    <span class="comment">// for の方の i とは別物</span>
    <span class="type">Console</span>.WriteLine(i);
}
</code></pre>
<h2>変数を使える範囲</h2>
<p>変数を使える範囲は、スコープよりもやや厳しくなります。
前節の通り、スコープは、その識別子を囲うブロック全体になりますが、
変数の場合はそのブロック全体でから使えるわけではありません。</p>
<p>まず、変数は、変数宣言よりも前では使えません。</p>
<pre class="source" title="変数は、宣言より前では使えない">
<code><span class="comment">// 宣言より後なのでコンパイル エラー</span>
x = 10;

<span class="reserved">int</span> x; <span class="comment">// 変数宣言</span>

<span class="comment">// 宣言より後なので OK</span>
x = 20;
</code></pre>
<p>また、変数に格納された値を読み出すためには、それよりも前に確実に初期化を行っている必要があります。</p>
<pre class="source" title="読み出す前に初期化が必要">
<code>{
    <span class="reserved">int</span> x; <span class="comment">// 未初期化変数</span>

    <span class="comment">// 初期化前には読めない。コンパイル エラー</span>
    <span class="type">Console</span>.WriteLine(x);
}

{
    <span class="reserved">int</span> y; <span class="comment">// 未初期化変数</span>

    y = 10; <span class="comment">// ここで初期化</span>

    <span class="comment">// これならOK</span>
    <span class="type">Console</span>.WriteLine(y);
}
</code></pre>
<p>C#では、変数が確実に初期化されているかどうかを結構真面目に判定しています。
例えば、以下のように、if ステートメントでは真偽両方で初期化されているかまで見ています。
(これを、「確実な代入ルール」(definite assignment rule)と呼んで、結構事細かにルールが決まっています。)</p>
<pre class="source" title="if ステートメントの中まで追って、変数の初期化を確認">
<code>{
    <span class="reserved">int</span> x; <span class="comment">// 未初期化変数</span>

    <span class="reserved">if</span> (<span class="type">Console</span>.ReadKey().Key == <span class="type">ConsoleKey</span>.A)
    {
        x = 10;
    }

    <span class="comment">// 条件を満たさない時に x が初期化されない。コンパイル エラー</span>
    <span class="type">Console</span>.WriteLine(x);
}

{
    <span class="reserved">int</span> y; <span class="comment">// 未初期化変数</span>

    <span class="reserved">if</span> (<span class="type">Console</span>.ReadKey().Key == <span class="type">ConsoleKey</span>.A)
    {
        y = 10;
    }
    <span class="reserved">else</span>
    {
        y = 20;
    }

    <span class="comment">// これならOK</span>
    <span class="type">Console</span>.WriteLine(y);
}
</code></pre>
<!-- pageBreak -->
<h2><a id="lifetime">オブジェクトの寿命</h2>
<p>オブジェクトは、誰からも参照されなくなったら<a href="http://ufcpp.net/study/csharp/rm_gc.html#garbage-collection">ガベージ コレクション</a>の対象になります。この時点をもって、オブジェクトの寿命は尽きていると考えます。</p>
<p>この「誰かが参照している」というのは、以下のように判定します。</p>
<ol>
<li>何もしなければ識別子のスコープを抜けた時点で参照が外れたことになる</li>
<li>明示的に別の値やnullを代入すれば、その時点で参照が外れたことになる</li>
</ol>
<p>1つ目の制限 があるので、基本的に、識別子のスコープが、オブジェクトの寿命の最大範囲です。
例えば以下のようなコードから、変数のスコープ = オブジェクトの寿命になっていることが分かります。</p>
<pre class="source" title="変数のスコープとオブジェクトの寿命">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> Sample()
    {
        <span class="type">Console</span>.WriteLine(<span class="string">"Sampleが作られました"</span>);
    }
    ~Sample()
    {
        <span class="type">Console</span>.WriteLine(<span class="string">"SampleがGCされました"</span>);
    }
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M()
    {
        {
            <span class="type">Console</span>.WriteLine(<span class="string">"Scope開始"</span>);
            <span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>();

            <span class="comment">// この時点ではまだ生きているので、GC しても無駄</span>
            <span class="type">GC</span>.Collect();

            <span class="type">Console</span>.WriteLine(<span class="string">"Scope終了"</span>);
        }

        <span class="comment">// この時点で s に入っていた Sample インスタンスは寿命迎えてる</span>
        <span class="comment">// GC を強制起動すると回収されるはず</span>
        <span class="type">GC</span>.Collect();
    }
}
</code></pre>
<pre class="console" title="実行結果">
<code>Scope開始
Sampleが作られました
Scope終了
SampleがGCされました
</code></pre>
<h3><a id="closure">ラムダ式と変数の昇格</h3>
<p>通常、ローカル変数に格納したオブジェクトの寿命は非常に短いです。戻り値で返したりしない限り、ブロック内だけで寿命を終えます。
ただ、C#にはいくつか、ただのローカル変数を、もう少し寿命の長いものに「昇格」(elevation)させてしまう構文があります。</p>
<p>その1つが<a href="http://ufcpp.net/study/csharp/sp_delegate.html#anonymous">匿名関数</a>です。匿名関数は、外側のローカル変数を取り込んでしまえる(補足(capture)できる)機能を持っています。この場合、取り込んだローカル変数に入っているインスタンスの寿命が延びます。</p>
<pre class="source" title="ローカル変数の補足とオブジェクトの寿命">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">int</span> Value { <span class="reserved">get</span>; }

    <span class="reserved">public</span> Sample(<span class="reserved">int</span> value)
    {
        Value = value;
    }
    ~Sample()
    {
        <span class="type">Console</span>.WriteLine(<span class="string">"SampleがGCされました"</span>);
    }
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="type">Func</span>&lt;<span class="reserved">int</span>&gt; M()
    {
        <span class="type">Func</span>&lt;<span class="reserved">int</span>&gt; f;
        {
            <span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>(1);
            f = () =&gt; s.Value;
            <span class="comment">// 変数 s のスコープはここまで</span>
        }

        <span class="comment">// でも、f が内部で s を参照しているので、インスタンスの寿命が延びる</span>
        <span class="comment">// 変数 s のスコープを超えて、f のスコープ内でずっと生き残る</span>
        <span class="comment">// GC 起動しても回収されず</span>
        <span class="type">GC</span>.Collect();

        <span class="reserved">return</span> f;
    }
}
</code></pre>
<p>詳細は「<a href="http://ufcpp.net/study/csharp/sp2_anonymousmethod.html">匿名デリゲートのコンパイル結果</a>」で説明していますが、匿名関数から外部のローカル変数を参照すると、実際にはクラスが自動生成されて、フィールドが作られます。すなわち、ローカル変数だったものがフィールドに昇格します。この昇格により、格納されているインスタンスの寿命が延びます。</p>
<h3><a id="for-loop-variable">forステートメントのループ変数</h3>
<p>ラムダ式の外部変数補足と合わせると、ループ変数のスコープに関して注意が必要になります。</p>
<p>まず、<code>for</code>ステートメントですが、これのループ変数は、全ループで1つ、同じ変数扱いになります。
例えば、以下の2つのループ(<code>for</code>ステートメントと、その下の<code>while</code>ステートメントを使ったもの)は同じ意味になります。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">public static</span> <span class="reserved">void</span> M(<span class="reserved">int</span> n)
{
    <span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; n; i++)
    {
        <span class="type">Console</span>.WriteLine(i);
    }

    {
        <span class="reserved">int</span> i = 0;
        <span class="reserved">while</span>(i &lt; n)
        {
            <span class="type">Console</span>.WriteLine(i);
            i++;
        }
    }
}
</code></pre>
<p><code>while</code>に書き換えたものを見てのとおり、ループの外側に1つの変数があり、それがずっと使いまわされます。</p>
<pre class="source" title="forのループ変数はループ全体で共有">
<code><type></span><span class="type">Action</span> a = <span class="reserved">null</span>;

<span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 10; i++)
{
    a += () =&gt; <span class="type">Console</span>.WriteLine(i); <span class="comment">// この i はずっと共有</span>
}
<span class="comment">// ループを抜けたときには、i の値は 10 に置き換わってる</span>

<span class="comment">// 結果、10が10回表示される</span>
a();
</code></pre>
<p>この結果(10が10回表示される)は意図通りでしょうか。0～9までの数字が1回ずつ表示される方を期待したいところですが、残念ながらそうはなりません。「0～9まで1回ずつ」という挙動を得るためには以下のように書く必要があります。</p>
<pre class="source" title="ループ1回1回で分けたい場合は別の変数が必要">
<code><type></span><span class="type">Action</span> a = <span class="reserved">null</span>;

<span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 10; i++)
{
    <span class="reserved">var</span> j = i;
    a += () =&gt; <span class="type">Console</span>.WriteLine(j); <span class="comment">// この j は1回1回別</span>
}

<span class="comment">// 結果、0～9が1回ずつ表示される</span>
a();
</code></pre>
<h3><a id="foreach-loop-variable">foreachステートメントのループ変数</h3>
<h5 class="version version5">Ver. 5.0</h5>
<p>同様の件について、<code>foreach</code>ステートメントでは、C# 5.0を境に仕様変更がありました。</p>
<p>C# 4.0以前では、<code>for</code>ステートメントと同じで、ループ変数がループ全体で共有されていました。
一方、C# 5.0以降では、ループ1回1回別扱いされるように変更されています。
すなわち、<code>while</code>を使って書き直すなら以下のようになります。</p>
<pre class="source" title="foreachのループ変数は4.0以前と5.0以降で挙動が異なる">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; list)
{
    <span class="reserved">foreach</span> (<span class="reserved">var</span> i <span class="reserved">in</span> list)
    {
        <span class="type">Console</span>.WriteLine(i);
    }

    {
        <span class="comment">// C# 4.0 以前</span>
        <span class="reserved">var</span> e = list.GetEnumerator();
        <span class="reserved">using</span> (e <span class="reserved">as</span> <span class="type">IDisposable</span>)
        {
            <span class="reserved">int</span> i; <span class="comment">// ループの外</span>
            <span class="reserved">while</span> (e.MoveNext())
            {
                i = e.Current;
                <span class="type">Console</span>.WriteLine(i);
            }
        }
    }

    {
        <span class="comment">// C# 5.0 以降</span>
        <span class="reserved">var</span> e = list.GetEnumerator();
        <span class="reserved">using</span> (e <span class="reserved">as</span> <span class="type">IDisposable</span>)
        {
            <span class="reserved">while</span> (e.MoveNext())
            {
                <span class="reserved">var</span> i = e.Current; <span class="comment">// ループの中</span>
                <span class="type">Console</span>.WriteLine(i);
            }
        }
    }
}
</code></pre>
<p>当然、以下のように、匿名関数で変数を取り込んだ際の挙動が変わります。</p>
<pre class="source" title="ラムダ式で変数補足した場合の挙動">
<code><type></span><span class="type">Action</span> a = <span class="reserved">null</span>;

<span class="reserved">foreach</span> (<span class="reserved">var</span> i <span class="reserved">in</span> <span class="type">Enumerable</span>.Range(0, 10))
{
    <span class="comment">// C# 4.0 以前: この i はずっと共有</span>
    <span class="comment">// C# 5.0 以降: この i は1回1回別</span>
    a += () =&gt; <span class="type">Console</span>.WriteLine(i);
}

<span class="comment">// C# 4.0 以前: 9が10回表示される</span>
<span class="comment">// C# 5.0 以降: 0～9が1回ずつ表示される</span>
a();
</code></pre>
<p>便利になる方向への変更なので概ね問題は起こしませんが、もしも、C# 4.0以前を使う必要がある場合には注意が必要です。
最新のコンパイラーと同じ感覚で上記のようなコードを書くと、C# 4.0以前のコンパイラーではバグになったりします。</p>
<h3><a id="iterator">イテレーターと非同期メソッド</h3>
<p>ローカル変数がフィールドに昇格してしまうものがあと2つあります。<a href="http://ufcpp.net/study/csharp/sp2_iterator.html#complied">イテレーター</a>と<a href="http://ufcpp.net/study/csharp/sp5_awaitable.html">非同期メソッド</a>です。</p>
<p>これらは、結構大々的なクラスの自動生成を行っていて、ローカル変数がフィールドに格上げされます。
例えば、以下のようなコードを実行すると、<code>Sample</code>のインスタンスはプログラム終了直前まで回収されません。</p>
<pre class="source" title="イテレーターと非同期メソッドでのローカル変数の昇格">
<code><reserved></span><span class="reserved">using</span> System;
<span class="reserved">using</span> System.Collections.Generic;
<span class="reserved">using</span> System.Threading.Tasks;

<span class="reserved">class</span> <span class="type">Sample</span>
{
    ~Sample()
    {
        <span class="type">Console</span>.WriteLine(<span class="string">"SampleがGCされました"</span>);
    }
}

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M()
    {
        <span class="reserved">foreach</span> (<span class="reserved">var</span> i <span class="reserved">in</span> Iterator()) ;
        AsyncMethod().Wait();
    }

    <span class="reserved">static</span> <span class="type">IEnumerable</span>&lt;<span class="reserved">int</span>&gt; Iterator()
    {
        <span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>();
        <span class="reserved">yield</span> <span class="reserved">return</span> 1;
        <span class="type">Console</span>.WriteLine(<span class="string">"1"</span>);

        <span class="comment">// s はずっと生き残ってる。回収されない</span>
        <span class="type">GC</span>.Collect();

        <span class="reserved">yield</span> <span class="reserved">return</span> 2;
        <span class="type">Console</span>.WriteLine(<span class="string">"2"</span>);

        <span class="comment">// 同上。回収されない</span>
        <span class="type">GC</span>.Collect();

        <span class="reserved">yield</span> <span class="reserved">return</span> 3;
        <span class="type">Console</span>.WriteLine(<span class="string">"3"</span>);
    }

    <span class="reserved">static</span> <span class="reserved">async</span> <span class="type">Task</span> AsyncMethod()
    {
        <span class="reserved">var</span> s = <span class="reserved">new</span> <span class="type">Sample</span>();
        <span class="reserved">await</span> <span class="type">Task</span>.Delay(1);
        <span class="type">Console</span>.WriteLine(<span class="string">"1"</span>);

        <span class="comment">// s はずっと生き残ってる。回収されない</span>
        <span class="type">GC</span>.Collect();

        <span class="reserved">await</span> <span class="type">Task</span>.Delay(1);
        <span class="type">Console</span>.WriteLine(<span class="string">"2"</span>);

        <span class="comment">// 同上。回収されない</span>
        <span class="type">GC</span>.Collect();

        <span class="reserved">await</span> <span class="type">Task</span>.Delay(1);
        <span class="type">Console</span>.WriteLine(<span class="string">"3"</span>);
    }
}
</code></pre>
<pre class="console" title="実行結果">
<code>1
2
3
1
2
3
SampleがGCされました
SampleがGCされました
</code></pre>
<h5 class="version version6">Ver. 6</h5>
<p>C# 5.0以前の場合、すべてのローカル変数が問答無用で軒並みフィールドに昇格していました。
元々、昇格が必要な理由は<code>yield return</code>や<code>await</code>をまたいで使うためです。
にもかかわらず、たとえ<code>yield return</code>や<code>await</code>をまたいでなくてもすべて昇格します。
これは、デバッグ実行時に変数の中身を覗けるようにするためです。</p>
<p>しかし、デバッグ実行のためというなら、デバッグ ビルドの際だけでいいはずです。
そこで、C# 6ではそう変更しました。リリース ビルドすると、<code>yield return</code>や<code>await</code>をまたがないものは通常のローカル変数にとどまります。
昇格が起きない分、オブジェクトの寿命が短くなります。
例えば、先ほどのコードですが、まったく同じものを、C# 6以降のコンパイラーを使って、リリース設定でコンパイルすると、結果は以下のように変わります。</p>
<pre class="console" title="実行結果(C# 6以降、リリース設定)">
<code>1
2
SampleがGCされました
3
1
SampleがGCされました
2
3
</code></pre>
<!-- pageBreak -->
<h2><a id="csharp7"> C# 7での新しいスコープ ルール</h2>
<h5 class="version version7">Ver. 7</h5>
<p><a href="http://ufcpp.net/study/csharp/cheatsheet/ap_ver7/">C# 7</a>では、新機能の導入に伴って、それ以前にはなかったスコープ関連のルールが発生しています。</p>
<ul>
<li><a href="http://ufcpp.net/study/csharp/datatype/typeswitch/#is">is 演算子の拡張</a>と<a href="http://ufcpp.net/study/csharp/sp_ref.html#out-var">出力変数宣言</a>が入ったので、式の途中で変数宣言できるようになりました</li>
<li><a href="http://ufcpp.net/study/csharp/st_function.html#sec-local">ローカル関数</a>が入りましたが、ローカル変数とはちょっと違うルールになっています</li>
</ul>
<h5 class="version version7">Ver. 7.3</h5>
<p>ちなみに、C# 7.0の時点では、「式中での変数宣言」が使えるのは、関数本体(メソッドなどの<code>{}</code>の中や<code>=&gt;</code>の後ろの部分)の中の式だけでした。
また、<a href="/study/csharp/sp3_linq.html#query">クエリ式</a>内では変数宣言できませんでした。</p>
<p>これに対して、C# 7.3からはこの制限がなくなり、
クエリ式や<a href="/study/csharp/oo_construct.html#initializer">コンストラクター初期化子</a>などの中でも変数宣言できるようになりました。</p>
<h3><a id="declaration-expressions">式中での変数宣言</h3>
<p>C# 6以前であれば、変数の宣言は宣言ステートメントでしかできませんでした。
そして、その宣言ステートメントを囲うブロックが、変数のスコープになります。</p>
<p>ちなみに、ブロックを持たない宣言ステートメントは書けません。
「ブロックを持たない」というのは、例えば、if ステートメントや foreach ステートメント直下です。
以下のようなコードはコンパイル エラーになります。</p>
<pre class="source" title="ifやforeach直下には変数宣言を書けない">
<code><span class="reserved">if</span> (<span class="reserved">true</span>)
    <span class="reserved">int</span> x = 10; <span class="comment">// コンパイル エラー</span>

<span class="reserved">if</span> (<span class="reserved">true</span>)
{
    <span class="reserved">int</span> x = 10; <span class="comment">// これなら OK</span>
}

<span class="reserved">foreach</span> (<span class="reserved">var</span> n <span class="reserved">in</span> <span class="reserved">new</span>[] { 1 })
    <span class="reserved">int</span> x = 10; <span class="comment">// コンパイル エラー</span>

<span class="reserved">foreach</span> (<span class="reserved">var</span> n <span class="reserved">in</span> <span class="reserved">new</span>[] { 1 })
{
    <span class="reserved">int</span> x = 10; <span class="comment">// これなら OK</span>
}
</code></pre>
<p>このifやforeach直下の部分を、構文上は埋め込みステートメント(embedded statement)と呼びます。
つまり、変数宣言ステートメントは、埋め込みステートメントに含まれていません。</p>
<p>ということで、C# 6までは「変数のスコープと言えばそれを囲うブロック内」というシンプルなルールで説明が付きました。</p>
<p>ところが、C# 7で導入された<a href="http://ufcpp.net/study/csharp/datatype/typeswitch/#is">is 演算子の拡張</a>と[出力変数宣言]では、式の中で変数宣言ができます。
式は割かしどこにでも書けるものなので、実質的に、ほぼどこででも変数宣言できるようになりました。</p>
<pre class="source" title="宣言をどこにでも書けるようになった例">
<code><span class="reserved">static</span> <span class="reserved">void</span> M(<span class="reserved">object</span> obj)
{
    <span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">int</span> x1) <span class="comment">// 条件式内</span>
        ;

    <span class="reserved">foreach</span> (<span class="reserved">var</span> n <span class="reserved">in</span> obj <span class="reserved">is</span> <span class="reserved">int</span> x2 ? <span class="string">"a"</span> : <span class="string">"b"</span>) <span class="comment">// foreach の () 内</span>
        ;

    <span class="reserved">for</span> (<span class="reserved">var</span> n = 0; obj <span class="reserved">is</span> <span class="reserved">int</span> x3 ? n &lt; x3 : <span class="reserved">false</span>; n++) <span class="comment">// for の () 内</span>
        ;

    <span class="reserved">if</span> (<span class="reserved">true</span>)
        <span class="type">Console</span>.WriteLine(obj <span class="reserved">is</span> <span class="reserved">int</span> x4 ? 1 : 2); <span class="comment">// 埋め込みステートメント内</span>

    <span class="reserved">foreach</span> (<span class="reserved">var</span> n <span class="reserved">in</span> <span class="string">"a"</span>)
        <span class="type">Console</span>.WriteLine(obj <span class="reserved">is</span> <span class="reserved">int</span> x5 ? 1 : 2); <span class="comment">// 埋め込みステートメント内</span>
}
</code></pre>
<p>そうなると問題は、式中で宣言した変数のスコープがどうなるかです。
これには、仕様を決める段階で紆余曲折あったんですが、「式を囲うブロック、埋め込みステートメント、while、for、foreach、using、 case内」ということになりました。</p>
<pre class="source" title="">
<code><span class="reserved">if</span> (<span class="reserved">true</span>)
{
    <span class="type">Console</span>.WriteLine(obj <span class="reserved">is</span> <span class="reserved">int</span> x ? 1 : 2); <span class="comment">// もちろん、ブロック内がスコープ</span>
    x = 1; <span class="comment">// これは OK</span>
}

<span class="reserved">if</span> (<span class="reserved">true</span>)
    <span class="type">Console</span>.WriteLine(obj <span class="reserved">is</span> <span class="reserved">int</span> x ? 1 : 2); <span class="comment">// 埋め込みステートメント内がスコープ</span>

<span class="reserved">foreach</span> (<span class="reserved">var</span> n <span class="reserved">in</span> obj <span class="reserved">is</span> <span class="reserved">int</span> x ? <span class="string">"a"</span> : <span class="string">"b"</span>) <span class="comment">// foreach 内がスコープ</span>
    ;

<span class="reserved">for</span> (<span class="reserved">var</span> n = 0; obj <span class="reserved">is</span> <span class="reserved">int</span> x ? n &lt; x : <span class="reserved">false</span>; n++) <span class="comment">// for 内がスコープ</span>
    ;

<span class="reserved">while</span> (obj <span class="reserved">is</span> <span class="reserved">int</span> x) <span class="comment">// while 内がスコープ</span>
{
    obj = <span class="string">""</span>;
}

<span class="reserved">using</span> (obj <span class="reserved">is</span> <span class="type">IDisposable</span> x ? x : <span class="reserved">null</span>) <span class="comment">// using 内がスコープ</span>
    ;

<span class="comment">// どの x ももうスコープ外。コンパイル エラー</span>
<span class="error">x</span> = 10;
</code></pre>
<p>特に、forステートメントの更新式の部分で宣言された変数のスコープは、更新式内だけになります。
(ループ本体の中からすら参照できない。)</p>
<pre class="source" title="for ステートメントの更新式のスコープ">
<code><span class="reserved">for</span> (<span class="reserved">int</span> i = 0; i &lt; 100; i += obj <span class="reserved">is</span> <span class="reserved">int</span> x ? x : 1) <span class="comment">// この x はこの式内でだけ使える</span>
{
    <span class="reserved">var</span> x = <span class="string">"別の値"</span>; <span class="comment">// OK。更新式内の x とは別物</span>
}
</code></pre>
<p>また、switch-case では以下のような書き方もできます。</p>
<pre class="source" title="caseごとにスコープが分かれる">
<code><span class="reserved">switch</span> (obj)
{
    <span class="reserved">case</span> <span class="reserved">int</span> x: <span class="reserved">return</span> x;
    <span class="reserved">case</span> <span class="reserved">string</span> x: <span class="reserved">return</span> x.Length; <span class="comment">// int x の方とは別になる</span>
    <span class="reserved">default</span>: <span class="reserved">throw</span> <span class="reserved">new</span> <span class="type">IndexOutOfRangeException</span>();
}
</code></pre>
<p>一方で、if ステートメントの条件式ではスコープが区切られません。そのifを囲うブロックがスコープになります。</p>
<pre class="source" title="if, while はスコープを区切らない">
<code><span class="reserved">if</span> (obj <span class="reserved">is</span> <span class="reserved">int</span> x1) <span class="comment">// 条件式内</span>
{
}
<span class="reserved">else</span>
{
    x1 = 10; <span class="comment">// ここも x1 のスコープ</span>
}

<span class="type">Console</span>.WriteLine(x1); <span class="comment">// ここも x1 のスコープ</span>
</code></pre>
<p>これは、いわゆる「early return」(<code>if (条件) { 長い処理 }</code> の代わりに、<code>if (!条件) return;</code> で処理を打ち切ってしまうパターン)で変数宣言をしたいという要件が多いからだそうです。</p>
<pre class="source" title="early return と if の条件式中での変数宣言">
<code><span class="reserved">void</span> M(<span class="reserved">string</span> s)
{
    <span class="reserved">if</span> (!<span class="reserved">int</span>.TryParse(s, <span class="reserved">out</span> var x)) <span class="reserved">return</span>;

    <span class="comment">// x を使った長い処理</span>
}
</code></pre>
<h3><a id="lambda">ラムダ式</h3>
<p><a href="/study/csharp/sp3_lambda.html">ラムダ式</a>では、ブロックを使った <code>() =&gt; { }</code> というようなものと、
<code>=&gt;</code> に続けて式を直接書く <code>() =&gt; x</code> というようなものの2パターンの記法が使えます。
後者であっても、この中で宣言した変数のスコープはラムダ式内に限られます。
(要するに、<code>() =&gt; x</code> みたいなのの<code>x</code>の部分は、前述の「埋め込みステートメント」と同じ扱いになっています。)</p>
<pre class="source" title="ラムダ式中の変数宣言">
<code><span class="type">Func</span>&lt;<span class="reserved">string</span>, <span class="reserved">int</span>&gt; f = s =&gt; <span class="reserved">int</span>.TryParse(s, <span class="reserved">out</span> var x) ? x : -1;
f(<span class="string">"123"</span>);
<span class="type">Console</span>.WriteLine(<span class="error">x</span>); <span class="comment">// ここで x は使えない</span>
</code></pre>
<h3><a id="is-operator">余談: is 演算子で新しい変数を導入</h3>
<p>Swift など、他のプログラミング言語の一部では、(C#風に書くと)以下のような構文を持っているものがあります。</p>
<pre class="source" title="is 演算子">
<code><reserved></span><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Base</span> { }
<span class="reserved">class</span> <span class="type">Derived1</span> : <span class="type">Base</span> { <span class="reserved">public</span> <span class="reserved">int</span> Id =&gt; 1; }
<span class="reserved">class</span> <span class="type">Derived2</span> : <span class="type">Base</span> { <span class="reserved">public</span> <span class="reserved">string</span> Name =&gt; <span class="string">"2"</span>; }

<span class="reserved">class</span> <span class="type">Sample</span>
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Base</span> x)
    {
        <span class="reserved">if</span> (x <span class="reserved">is</span> <span class="type">Derived1</span>)
        {
            <span class="comment">// この中では、x を Derived1 として扱える</span>
            <span class="type">Console</span>.WriteLine(x.Id);
        }
        <span class="reserved">else</span> <span class="reserved">if</span> (x <span class="reserved">is</span> <span class="type">Derived2</span>)
        {
            <span class="comment">// この中では、x を Derived2 として扱える</span>
            <span class="type">Console</span>.WriteLine(x.Name);
        }
    }
}
</code></pre>
<p>is演算子の拡張は、C# 7でもこういう「型による分岐」機能がほしいということで入った機能です。
しかし、Swiftのような構文だと、「スコープ内で識別子の意味を変えない・上書かない」という原則に反します。
<code>x</code>は最初に<code>Base</code>型として定義した以上、ずっと<code>Base</code>型のままにしたいということです。</p>
<p>結局、is演算子の拡張は以下のように、式の中で新しい変数を導入する構文になっています。</p>
<pre class="source" title="C# 7のis演算子">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">void</span> M(<span class="type">Base</span> x)
{
    <span class="reserved">if</span> (x <span class="reserved">is</span> <span class="type">Derived1</span> d1)
    {
        <span class="comment">// x の型が Derived1 だった場合だけ、キャスト結果が d1 に入る</span>
        <span class="type">Console</span>.WriteLine(d1.Id);
    }
    <span class="reserved">else</span> <span class="reserved">if</span> (x <span class="reserved">is</span> <span class="type">Derived2</span> d2)
    {
        <span class="comment">// x の型が Derived2 だった場合だけ、キャスト結果が d2 に入る</span>
        <span class="type">Console</span>.WriteLine(d2.Name);
    }
}
</code></pre>
<h3><a id="local-functions">ローカル関数を使える範囲</h3>
<p><a href="http://ufcpp.net/study/csharp/st_function.html#sec-local">ローカル関数</a>はどう扱うべきでしょうか。
ローカル変数のようなものだと考えると、宣言より前では使えないはずです。
一方で、メソッドのようなものだと考えると、通常、メソッドは宣言よりも前で使えます。</p>
<pre class="source" title="ローカル関数はローカル変数的であるべきか、メソッド的であるべきか">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Program</span>
{
    <span class="reserved">static</span> <span class="reserved">void</span> Main()
    {
        <span class="comment">// ローカル関数は、こういうローカル変数的な扱いすべき？</span>
        <span class="type">Func</span>&lt;<span class="reserved">int</span>, <span class="reserved">int</span>&gt; f = x =&gt; x * x;

        <span class="comment">// もしローカル変数的に扱うなら、f はこの後ろでしか使えない</span>
        <span class="reserved">var</span> y = f(2);

        <span class="comment">// それとも、メソッドと同じような扱いにすべき？</span>
        <span class="comment">// メソッドなら、宣言よりも前でも使える</span>
        <span class="reserved">var</span> z = M(2);
    }

    <span class="comment">// メソッドであれば、宣言が後ろにあってもいい</span>
    <span class="reserved">static</span> <span class="reserved">int</span> M(<span class="reserved">int</span> x) =&gt; x * x;
}
</code></pre>
<p>これは結局、後者が選ばれました。すなわち、メソッド的に、宣言よりも前で使えます。</p>
<pre class="source" title="ローカル関数は宣言より前で使える">
<code><span class="reserved">static</span> <span class="reserved">void</span> Main()
{
    <span class="comment">// ローカル関数は宣言より前で使える</span>
    <span class="reserved">var</span> y = f(2);

    <span class="reserved">int</span> f(<span class="reserved">int</span> x) =&gt; x * x;
}
</code></pre>
<p>もう1つ、ローカル関数が絡むと、「確実な代入ルール」も少々複雑です。
ローカル関数が周りのローカル変数をキャプチャする際、
その変数は、初めてローカル関数を呼び出すまでに初期化すればよいということになっています。</p>
<pre class="source" title="ローカル関数を呼ぶまでに初期化すればOK">
<code><span class="reserved">static</span> <span class="reserved">void</span> SuccessfulSample()
{
    <span class="reserved">int</span> a; <span class="comment">// 未初期化</span>
    <span class="reserved">int</span> f(<span class="reserved">int</span> x) =&gt; a * x; <span class="comment">// (この時点で)未初期化変数 a 参照</span>
    a = 10; <span class="comment">// ここで初期化</span>
    <span class="reserved">var</span> y = f(2); <span class="comment">// OK</span>
}

<span class="reserved">static</span> <span class="reserved">void</span> ErroneousSample()
{
    <span class="reserved">int</span> a; <span class="comment">// 未初期化</span>
    <span class="reserved">int</span> f(<span class="reserved">int</span> x) =&gt; a * x; <span class="comment">// 未初期化変数 a 参照</span>
    <span class="comment">// a を初期化しない！</span>
    <span class="reserved">var</span> y = f(2); <span class="comment">// コンパイル エラー</span>
}
</code></pre>
<h3><a id="query-expression">クエリ式</h3>
<h5 class="version version7">Ver. 7.3</h5>
<p>C# 7.3までは、クエリ式中では式中での変数宣言ができませんでした。
(変数のスコープをどうするかがちょっと悩ましく、7.0時点では「先送り」していました。)
C# 7.3で、これが許されるようになりました。</p>
<pre class="source" title="クエリ式中での変数宣言">
<code><span class="reserved">var</span> q =
    <span class="reserved">from</span> s <span class="reserved">in</span> <span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"abc"</span>, <span class="string">"112"</span>, <span class="string">"132"</span>, <span class="string">"451"</span>, <span class="reserved">null</span> }
    <span class="reserved">where</span> s <span class="reserved">is</span> <span class="reserved">string</span> <em>x</em> &amp;&amp; x.Length &gt; 1
    <span class="reserved">where</span> <span class="reserved">int</span>.TryParse(s, <span class="reserved">out var</span> <em>x</em>) &amp;&amp; (x % 3) == 0
    <span class="reserved">select</span> s;
</code></pre>
<p>ちなみに、この場合、変数のスコープは「句の中のみ」に限られます
(<code>where</code>とか<code>select</code>とかによってスコープが区切られます)。
上記の例の場合、1つ目の<code>where</code>中の<code>x</code>と、2つ目の<code>where</code>中の<code>x</code>はそれぞれ別変数になります。</p>
<p>これは、クエリ式が実際には以下のようなメソッド チェーンに展開されるためです。</p>
<pre class="source" title="クエリ式のメソッド チェーンへの展開">
<code><span class="reserved">var</span> q =
    <span class="reserved">new</span>[] { <span class="string">"a"</span>, <span class="string">"abc"</span>, <span class="string">"112"</span>, <span class="string">"132"</span>, <span class="string">"451"</span>, <span class="reserved">null</span> }
    .Where(s =&gt; s <span class="reserved">is</span> <span class="reserved">string</span> <em>x</em> &amp;&amp; x.Length &gt; 1)
    .Where(s =&gt; <span class="reserved">int</span>.TryParse(s, <span class="reserved">out var</span> <em>x</em>) &amp;&amp; (x % 3) == 0);
</code></pre>
<p>前述の通り、ラムダ式内で変数宣言した場合、その変数のスコープはラムダ式内に限られます。
クエリ式は句ごとに1つのラムダ式が作られるので、それとの整合性を取った結果が「句ごとに別スコープ」です。
句をまたいだ変数を宣言したい場合は<a href="/study/csharp/sp3_stdquery.html#let"><code>let</code>句</a>を使ってください。</p>
<h3><a id="initializer">コンストラクター初期子、フィールド初期化子、プロパティ初期化子</h3>
<h5 class="version version7">Ver. 7.3</h5>
<p>ラムダ式同様、スコープをどうするか悩ましくて保留になっていたものに初期化子があります。
C# 7.3で、以下のように、初期化子内でも変数宣言できるようになりました。</p>
<pre class="source" title="初期化子内での変数宣言">
<code><span class="reserved">using</span> System;

<span class="reserved">class</span> <span class="type">Derived</span> : <span class="type">Base</span>
{
    <span class="reserved">public</span> Derived(<span class="reserved">string</span> s) : <span class="reserved">this</span>(<span class="reserved">int</span>.TryParse(s, <span class="reserved">out var</span> <em>x</em>) ? x : -1)
    {
        <span class="comment">// コンストラクター初期化子中で宣言した x は、コンストラクター本体内で利用可能。</span>
        <span class="type">Console</span>.WriteLine(x);
    }

    <span class="reserved">public</span> Derived(<span class="reserved">int</span> a) : <span class="reserved">base</span>(<span class="reserved">out var</span> <em>x</em>)
    {
        <span class="comment">// base の場合でも同様。</span>
        <span class="type">Console</span>.WriteLine(x);
    }

    <span class="comment">// フィールド初期化子、プロパティ初期化子中で宣言した x は、その初期化子内でのみ有効。</span>
    <span class="reserved">public</span> <span class="reserved">int</span> Field = <span class="reserved">int</span>.TryParse(<span class="string">"123"</span>, <span class="reserved">out var</span> <em>x</em>) ? x : -1;
    <span class="reserved">public</span> <span class="reserved">int</span> Property{ <span class="reserved">get</span>; <span class="reserved">set</span>; } = <span class="reserved">int</span>.TryParse(<span class="string">"123"</span>, <span class="reserved">out var</span> <em>x</em>) ? x : -1;
}
</code></pre>
<p>ちなみに、コンストラクター初期化子内で宣言した変数のスコープはそのコンストラクター全体、
フィールド初期化子・プロパティ初期化子中のものはその初期化子の中限定です。</p>
 ]]></description>
				<pubDate>Thu, 14 Jan 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>[雑記] 多重継承できない理由</title>
				<link>http://www.ufcpp.net/study/csharp/oop/oo_multipleinheritance/</link>
				<description><![CDATA[ <p>「継承」で説明した通り、C#ではクラスの多重継承を認めていません。すなわち、どんな型も基底クラスは1つだけです。制限なしの多重継承は実装のコストが結構高く、メリットに対してコストが見合わないというのが一般的な見方です。ここでは、その多重継承にかかるコストについて説明していきます。</p>
<h2><a id="layout">オブジェクトのメモリ レイアウト</h2>
<p>多重継承を認めた場合に問題となるのは、オブジェクトのメモリ レイアウトです。そこでまず、このメモリ レイアウトについて軽く説明しておきます。</p>
<p><a href="http://ufcpp.net/study/csharp/sp_reflection.html">実行時型情報</a>で少し触れていますが、クラスや構造体などの複合型は、実行時にはメモリ上でどうレイアウトされるかが決まっています。</p>
<p>例えば、以下のようなクラスがあったとします。</p>
<pre class="source" title="レイアウトの例">
<code><reserved></span><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">int</span> x;
    <span class="reserved">int</span> y;
    <span class="reserved">int</span> z;
}
</code></pre>
<p>こういうフィールドの持ち方をすると、たいてい<sup>※</sup>の場合、以下のようなレイアウトになります。</p>
<p><img src="/media/1050/layout1.png" alt="メモリ レイアウトの例" /></p>
<p><code>int</code>(32ビット整数)なので4バイトごとに、宣言した <code>x</code>, <code>y</code>, <code>z</code> の順に前から詰まります。</p>
<p><sup>※</sup> 仕様上はコンパイラーの裁量によってフィールド間に隙間を開けることも許されているので、必ずしもこうなる保証はありません。</p>
<h2><a id="single-inheritance">単一継承時のメモリ レイアウト</h2>
<p>続いて、クラスを継承した時のレイアウトがどうなるかについてですが、例として以下のようなクラス階層を考えます。</p>
<pre class="source" title="単一継承のレイアウトの例">
<code><reserved></span><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">int</span> x;
}

<span class="reserved">class</span> <span class="type">B</span> : <span class="type">A</span>
{
    <span class="reserved">int</span> y;
}

<span class="reserved">class</span> <span class="type">C</span> : <span class="type">B</span>
{
    <span class="reserved">int</span> z;
}
</code></pre>
<p>このときのレイアウトは「基底クラス側から順にフィールドを並べたものになります。この例の場合、下図のようになります。</p>
<p><img src="/media/1051/layout2.png" alt="単一継承時のレイアウトの例" /></p>
<p>継承の性質(is-aの関係)から、<code>B</code>のインスタンスは<code>A</code>としても使え、<code>C</code>のインスタンスは<code>B</code>としても<code>A</code>としても使えます。
単一継承の場合、実装上も難しい話は何もなく、単にレイアウトの<em>前半だけを使う</em>ことで基底クラスとして振る舞うことができます。</p>
<p><img src="/media/1052/layout3.png" alt="派生クラス is-a 基底クラス" /></p>
<h2><a id="multiple-inheritance">多重継承を認めた場合のメモリ レイアウト</h2>
<p>面倒が出てくるのはここからです。先ほどと同じことを多重継承で考えてみましょう。
C#では認められていませんが、仮に、以下のように書けたとしましょう。</p>
<pre class="source" title="多重継承のレイアウトの例(C#では認められていない)">
<code><reserved></span><span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">int</span> x;
}

<span class="reserved">class</span> <span class="type">B</span>
{
    <span class="reserved">int</span> y;
}

<span class="reserved">class</span> <span class="type">C</span> : <span class="type">A</span>, <span class="type">B</span>
{
    <span class="reserved">int</span> z;
}
</code></pre>
<p>レイアウトは以下のようにするのがシンプルでよいでしょう。</p>
<p><img src="/media/1053/layout4.png" alt="多重継承のレイアウトの例" /></p>
<p><code>C</code>では、<code>x</code>(<code>A</code>のメンバー)と<code>y</code>(<code>B</code>のメンバー)のどちらを前にするかという問題はあるものの、まあ、宣言の順(<code>C : A, B</code>という順で書いたんだから<code>A</code>が先)にすればいいでしょう。</p>
<p>ここで、<code>C</code>は<code>A</code>でも<code>B</code>でもあります。<code>C</code>のインスタンスを<code>A</code>として使うのは「前半を使う」で問題ないんですが、<code>B</code>として使いたければ「4バイト後ろを使う」という特殊ルールが必要になります(先頭からずれている分のオフセット管理が必要)。</p>
<p><img src="/media/1054/layout5.png" alt="多重継承時のis-aの取り扱い例" /></p>
<p>「4バイト後ろを使う」というのは単純そうにも思えますが、実装上は結構面倒になります。
<code>B</code>のインスタンスと<code>C</code>のインスタンスを混在させて、どちらも<code>B</code>として使うことを考えると、<code>B</code>のインスタンスなら普通に先頭を、<code>C</code>のインスタンスなら4バイト後ろを使うというような分岐処理が必要になります。</p>
<h2><a id="diamond-inheritance">ダイヤモンド問題</h2>
<p>オフセット管理が必要な時点ですでに多重継承は面倒なんですが、より深い問題として、ダイヤモンド問題(diamond problem)というものがあります。ここで出てくるダイヤモンドという言葉は、野球用語の「ダイヤモンド」と同じく、ひし形形状のことを指します。すなわち、以下のように「ひし形な」多重継承をした場合にどうなるかという問題です。</p>
<pre class="source" title="ダイヤモンド継承の例">
<code>
<span class="reserved">class</span> <span class="type">A</span>
{
    <span class="reserved">int</span> w;
}

<span class="reserved">class</span> <span class="type">B</span> : <span class="type">A</span>
{
    <span class="reserved">int</span> x;
}

<span class="reserved">class</span> <span class="type">C</span> : <span class="type">A</span>
{
    <span class="reserved">int</span> y;
}

<span class="reserved">class</span> <span class="type">D</span> : <span class="type">B</span>, <span class="type">C</span>
{
    <span class="reserved">int</span> z;
}
</code></pre>
<p>クラス図を描くと下図のようにひし形になるので「ダイヤモンド継承」と呼ばれます。</p>
<p><img src="/media/1055/diamond.png" alt="ダイヤモンド継承" /></p>
<p>では、これらのクラスのレイアウトを考えてみましょう。<code>A</code>, <code>B</code>, <code>C</code>については単一継承しかしていないので問題はありません。</p>
<p><img src="/media/1056/layout6.png" alt="A, B, Cのレイアウト" /></p>
<p>一方で、<code>D</code>クラスのレイアウトをどうすべきはなかなか悩ましくなります。
<code>B</code>にも<code>C</code>にも、<code>A</code>のメンバー<code>w</code>が含まれていることが問題になります。
Dからすると、二重管理です。</p>
<p>よくある実装としては2パターンあります。
1つ目は本当に二重管理してしまう方法で、<code>w</code>を2か所に持ってしまいます。</p>
<p><img src="/media/1057/layout7.png" alt="2重管理でレイアウト" /></p>
<p>このやり方だと、<code>D</code>のインスタンスを<code>C</code>として使うのに、
前節と同様「8バイト後ろを使う」(オフセット管理)という方法でできるという利点はあります。
一方で、やはり二重管理は大変です。
<code>w</code>を書き換えるたびに、2か所のメモリ上を書き換える必要があります。</p>
<p>もう1つは、二重管理をなくすために、以下のようなレイアウトを考えます。</p>
<p><img src="/media/1058/layout8.png" alt="重複するフィールドを除外したレイアウト" /></p>
<p>これで二重管理は解消するものの、今度は<code>C</code>のフィールドがとびとびになるという問題が出ます。
このせいで、フィールドの読み書きがかなり面倒になります。
フィールド<code>w</code>, <code>y</code>の読み書きの際、先頭から何バイト目を見ればよいかが、<code>C</code>のインスタンスか<code>D</code>のインスタンスかで、
以下の表のように変わります。</p>
<table>
<thead>
<tr>
	<th></th>
	<th>w の読み書き</th>
	<th>y の読み書き</th>
</tr>
</thead>
<tbody>
<tr>
	<td><code>C</code>のインスタンス</td>
	<td>0</td>
	<td>4</td>
</tr>
<tr>
	<td><code>D</code>のインスタンス</td>
	<td>0</td>
	<td>8</td>
</tr>
</tbody>
</table>
<p>こういう不規則なオフセット管理はコストに直結します。
フィールドの読み書きがだいぶ遅くなるわけです。
そのコストを掛けてまで、本当に多重継承を使いたかったのかということを考えないといけません。</p>
<h2><a id="interface">実際にほしかったものはインターフェイス</h2>
<p>ちなみに、実際、C++の場合はここで説明したようなメモリ レイアウトで多重継承を実装しています。
しかし、コストが高すぎるので避けられる傾向があります。</p>
<p>ただし、多重継承のコストが問題にならない場合が1つあります。
それは、何もフィールドを持っていない場合です。
フィールドのメモリ レイアウトが問題の原因なんだから、フィールドがなければ問題ありません。
フィールドがなくても、メソッドがあればクラスの振る舞いは定義できます。
フィールドなしだとメソッドの実装が書けないにしても、抽象メソッドであればそもそも実装は必要ありません。</p>
<p>つまり、抽象メソッドだけを持つクラス(C++的に言うと純粋仮想関数だけを持つクラス)なら多重継承しても無害です。
C++でもそういうクラスを作ることが推奨されていますし、それを言語構文として取り入れたのがJavaやC#のインターフェイスです。
なので、JavaやC#では、クラスは単一継承関係しか認めず、代わりに、インターフェイスの実装が無制限です。</p>
<p>もちろん、フィールドを持てない分の不便はありますが、抽象メソッドだけでも十分な利用価値があります。
コストとメリットのバランスを考えると、これが良い妥協点だったということです。</p>
 ]]></description>
				<pubDate>Wed, 13 Jan 2016 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>JITコンパイル</title>
				<link>http://www.ufcpp.net/study/csharp/framework/fwjitcompilation/</link>
				<description><![CDATA[ <h2><a id="abstract"> 概要</h2>
<p>C# の実行方法の1つに、<strong id="jit" class="keyword">JIT</strong> (Just-In-Time: ちょうど必要になったときに)コンパイルという方式があります。</p>
<p>C# が登場して以来長らくの間、主流の実行方式はJITコンパイルでした。現在でも、デスクトップPCなどではこの実行方式をとります。C#<sup>※1</sup>の他では、Java<sup>※2</sup>もJIT方式です<sup>※3</sup>。JITコンパイルとまではいわないものの、スクリプト言語と呼ばれるようなプログラミング言語も、内部実装的にJITコンパイルに似たような仕組みを使っていたりもします。</p>
<ul>
<li><sup>※1</sup> 正確にはC#に加え、Visual BasicやF#など、.NETランタイム上で動かすプログラミング言語も</li>
<li><sup>※2</sup> こちらも正確にはJava仮想マシン上で動かすScalaなどの言語も</li>
<li><sup>※3</sup> Javaは、登場初期にはインタープリター方式という別の方式も使っていましたが、現在ではあまり使われません。</li>
</ul>
<p>ここでは、JITコンパイルという方式がどのようなものかを説明していきます。</p>
<h2><a id="run-on-framework">.NET上で実行</h2>
<p>「C#は.NET Framework上で動かす」などと言われます。つまり、C#で書いたプログラムを動かすためには、下図のように、作ったアプリとは別にフレームワークが必要になります。</p>
<p><img src="/media/1038/framework1.png" alt="C#アプリの実行に必要なもの" /></p>
<p>ここでいうフレームワークは、.NETの事なんですが、互換環境や新実装がいくつかあり、例えば以下のようなものがあります。</p>
<ul>
<li>.NET Framework: C#登場時点(2000年頃)からある、マイクロソフト実装のWindowsデスクトップ上で動くフレームワーク</li>
<li>Mono: .NET Framework登場からほどなくして作られた、オープンソースで開発されている.NET Framework互換環境</li>
<li>.NET Core: 2015年に登場した、マイクロソフト主導のオープンソースで開発されている新しいフレームワーク</li>
</ul>
<p>フレームワークの用意の仕方は、.NET Frameworkと.NET Coreで少し異なります。</p>
<p><img src="/media/1039/frameworkandcore.png" alt=".NET Frameworkと.NET Coreの準備" /></p>
<p>基本的には何らかのインストールが必要になります。.NET Frameworkは、アプリを動かす環境に、必要なものをすべて事前にインストールする必要があります。</p>
<p>一方で、.NET Coreの場合、インストールが必要なものはパッケージ マネージャーという部分だけです。パッケージ マネージャーは非常に小さいプログラムなので、仰々しいインストールをしなくても、アプリと一緒に配ったり、必要になったときにネットからダウンロードしてくればいいでしょう。残りの部分は、そのパッケージ マネージャーがパッケージ管理サーバーから探して自動的にダウンロードします。</p>
<p>(この辺りの詳細は別ページで書くかも)</p>
<p>いずれにせよ、フレームワークは以下のようなものを含みます。</p>
<ul>
<li>メモリ管理: <a href="http://ufcpp.net/study/computer/MemoryManagement.html#heap">ヒープ</a>領域の確保・解放を管理します。</li>
<li>型ローダー: アプリ内にどういうクラスやどういうメソッドがあるかという情報を読みだします。</li>
<li>ネイティブ コード生成: <a href="http://ufcpp.net/study/il/">IL</a>からネイティブ コードを生成します。</li>
<li>標準ライブラリ: 「このバージョンのフレームワークをインストールすれば必ず使える」という保証のあるライブラリです。ネイティブ コードで実装されいている部分も、ILで実装されている部分もあります。</li>
</ul>
<h2><a id="jit-compilation">JITコンパイル</h2>
<p>JITコンパイル方式では、Just-In-Timeという名前通り、必要になるまでアプリのコードは読み込まれません。アプリを起動した直後には、下図のように、メモリの実行領域には、フレームワーク側のコードだけが読み込まれていて、アプリのコードはありません。</p>
<p><img src="/media/1040/jit1.png" alt="アプリ実行直後の状況" /></p>
<p>アプリのコードは必要になったときに初めて読み込まれます。例えば、<code>A</code>というクラスの<code>M</code>というメソッドが呼ばれたとします。ここでは、<code>A</code>というクラスも初めて出てきたので、まず、<code>A</code>の型情報が読み込まれます。このとき、メモリ上には関数テーブル<sup>※</sup>と呼ばれるものが作られます。</p>
<p><img src="/media/1041/jit2.png" alt="クラスAの型情報の読み込み" /></p>
<ul>
<li><sup>※</sup> 関数テーブル(function table)の他、仮想関数テーブル(virtual function table)、仮想メソッド テーブル(virtual method table)などと呼ばれます。あるいはvirtual function/method tableをVTなどと略す書き方もよくします。</li>
</ul>
<p>関数テーブルには、「このメソッドを呼ばれた時には、実行領域のこの部分を呼び出せ」というような、ジャンプ先の情報(メモリ アドレス)が入ります。初期状態では、ジャンプ先として、「ネイティブ コード生成」のコードを指しています。これによって、「メソッド<code>M</code>の初回呼び出し時に、<code>M</code>をネイティブ コード化するコードが実行される」というような状態になっています。</p>
<p>続いて、実際にメソッド<code>M</code>の呼び出しが行われます。前述のとおり、関数テーブルの初期状態を参照した結果、メソッド<code>M</code>のネイティブ コード生成が行われます。結果として、下図のような状態になります。</p>
<p><img src="/media/1042/jit3.png" alt="メソッドMのネイティブ コード生成" /></p>
<p>そして、ネイティブ コード化されたMのコードが実際に呼び出されます。2回目の呼び出し以降は、直接このネイティブ コードが呼ばれます。</p>
<p>ここまで来れば、「Just-In-Time(必要になったちょうどその時に)コンパイルされている」という感覚がわかるでしょうか。クラスやメソッドなどを初めて使う瞬間にコンパイルが走ります。2回目以降の利用はかなり高速に動作できます。</p>
<h2><a id="aot-compilation">AOTコンパイル</h2>
<p>JITコンパイル方式にはそれなりにメリットがあるからこそこの方式を使うわけですが、万能でもなく、事前に全部ネイティブ コード化してしまいたい場面もあります。通常はJITコンパイル実行するものを、普通に全部事前コンパイルすることを、JITとの対比で、<strong id="aot" class="keyword">AOT</strong>(Ahead-Of-Time: その時が来る前に)コンパイルと言ったりします。</p>
<p>JIT コンパイル方式のフレームワークでも、結局最後にはネイティブ コード化して実行することになるわけで、ネイティブ コード生成のタイミングを変えるだけでAOTコンパイルを実現できたりはします。要するに、下図のような状態です。</p>
<p><img src="/media/1043/aot.png" alt="AOTコンパイル" /></p>
<p>JITコンパイル方式の利点を以下の表にまとめます。</p>
<table>
<tr>
<th>JITの利点</th><th>その利点が働きにくくなる場面</th>
</tr>
<tr>
<td>セキュリティが担保しやすい</td>
<td>他の仕組み(ストアでの審査など)でセキュリティが担保できる。あるいは、開発者自身が使う場合など、そもそもセキュリティ担保が不要な場面もある</td>
</tr>
<tr>
<td>C#→ILのコンパイルはかなり早い</td>
<td>デバッグ時はJIT方式で実行して動作確認し、最終製品にはAOT方式を使うというような対処が可能</td>
</tr>
<tr>
<td>依存するライブラリを更新しやすい</td>
<td>ライブラリの更新頻度はアプリよりもだいぶ低く、通常はアプリ更新のタイミングで一緒に更新すればいい。
ライブラリだけを更新する必要があるのはセキュリティ ホールがあった場合など、緊急の場面のみ。
この場合も、その時に1回コンパイルすればよく、JITが必須というわけではない</td>
</tr>
<tr>
<td>
 <a href="http://ufcpp.net/study/csharp/sp_reflection.html#reflection">リフレクション</a> など、動的な処理がしやすい
</td>
<td>動的な処理は元々実行速度が遅くなりがちなので避けることが多い。少し手間は増えるものの、AOTでも動的な処理が全くできないわけではない</td>
</tr>
</table>
<p>こういう性質から、セキュリティ担保や動的処理の問題が避けれる状況ではAOT方式が好まれます。例えば、</p>
<ul>
<li>出所が分からないアプリを実行する可能性のあるデスクトップ アプリでは、JIT方式がそれなりに有利</li>
<li>ストア審査があるスマホ アプリでは、JIT方式が有利にならない。一方で、スマホは可能な限りスマホ上での処理を減らしたいので、動的な処理も元々避けがちで、AOT方式が有利</li>
</ul>
<p>というような使い分けができます。</p>
 ]]></description>
				<pubDate>Thu, 19 Nov 2015 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>トップ レベルのアクセシビリティ</title>
				<link>http://www.ufcpp.net/study/csharp/package/toplevelaccessibility/</link>
				<description><![CDATA[ <p><a href="http://ufcpp.net/study/csharp/oo_conceal.html">実装の隠蔽</a>で、5種類のアクセシビリティ(4つのキーワードとその組み合わせ)を紹介しました。</p>
<p>クラスや構造体のメンバーについてはこの5種類全てを選べる一方で、トップ レベルの型には public, internal の2つのうちのどちらかだけが選べます。</p>
<p>トップ レベルのアクセシビリティは、アセンブリを超えてその型を使えるかどうか(public なら使える、internal なら使えない)を表します。</p>
<h2><a id="abstract">概要</h2>
<p>クラスなどの型定義は、名前空間直下やファイル直下に書けます。この場合に指定できるアクセシビリティは public と internal の2種類になります。</p>
<ul>
<li>public: 他のアセンブリから参照できる</li>
<li>internal: 他のアセンブリからは参照できない</li>
</ul>
<p>省略すると internal 扱いになります。</p>
<h5>サンプル</h5>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Oop/TopLevelAccessibility">https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Oop/TopLevelAccessibility</a></li>
</ul>
<h2><a id="background">前提知識</h2>
<p>本題に入る前に少し用語の説明。</p>
<h3><a id="assembly">アセンブリ</h3>
<p>まずは<a href="http://ufcpp.net/study/csharp/package/project/">前項</a>のおさらいから。</p>
<p>通常、プログラムは複数のアセンブリ(assembly: 組み立て部品)を組み合わせて作り上げます。</p>
<ul>
<li>アセンブリ = 実行可能ファイル(exe)、もしくは、ライブラリ(dll)</li>
<li>C# の場合、1つのプロジェクトで1つのアセンブリを作る</li>
<li>複数のプロジェクト(アセンブリ)で、1つの課題を解決(ソリューション)する</li>
</ul>
<h3><a id="top-level">トップ レベル要素</h3>
<p>フィールドやプロパティなどのメンバーは、常にクラスもしくは構造体の内部にあります。
一方で、型(クラス、構造体、インターフェイス、デリゲート、列挙型など)の定義は名前空間の直下や、ファイル直下(コンパイル単位(compilation unit)とか呼ばれたりします)に書けます。</p>
<p>この、名前空間直下やファイル直下の位置を、トップ レベル(top level)と呼びます。
逆に、他の型の内部を<strong id="key-nested" class="keyword">入れ子</strong>(nested)と呼びます。</p>
<p><img src="/media/1028/toplevel.png" alt="トップ レベル" /></p>
<h3><a id="top-level-accessibility">トップ レベル要素に対するアクセシビリティ</h3>
<p><a href="http://ufcpp.net/study/csharp/oo_conceal.html">実装の隠蔽</a>で、5種類のアクセシビリティ(4つのキーワードとその組み合わせ)を紹介しました。</p>
<p>トップ レベルの型に対するアクセシビリティは、アセンブリをまたいでアクセスできるかどうかを表します。
アクセスできるかどうかの2種類しか必要ないので、
トップ レベルの型には public, internal の2つのうちのどちらかだけが選べます。</p>
<table summary="">
	<tr>
		<th>アクセシビリティ</th>
		<th>説明</th>
	</tr>
	<tr>
		<td>
public
</td>
		<td>
アセンブリの外からアクセス可能
</td>
	</tr>
	<tr>
		<td>
internal
</td>
		<td>
同一アセンブリ内からのみアクセス可能
</td>
	</tr>
</table>
<p>例えば、
以下の型(クラス、構造体、インターフェイス、デリゲート)はいずれも、アセンブリの外からアクセスできません。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">internal</span> <span class="reserved">interface</span> <span class="type">InternalInterface</span>
{
    <span class="type">InternalDelegate</span> X { <span class="reserved">get</span>; }
}

<span class="reserved">internal</span> <span class="reserved">delegate</span> <span class="reserved">void</span> <span class="type">InternalDelegate</span>();

<span class="reserved">namespace</span> A
{
    <span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">InternalClass</span> : <span class="type">InternalInterface</span>
    {
        <span class="reserved">private</span> <span class="type">InternalStruct</span> _value;

        <span class="reserved">public</span> <span class="type">InternalDelegate</span> X =&gt; _value.X;
    }

    <span class="reserved">internal</span> <span class="reserved">struct</span> <span class="type">InternalStruct</span>
    {
        <span class="reserved">public</span> <span class="type">InternalDelegate</span> X { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    }
}
</code></pre>
<p>一方、以下の型はいずれも、アセンブリの外からアクセスできます。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">interface</span> <span class="type">PublicInterface</span>
{
    <span class="type">PublicDelegate</span> X { <span class="reserved">get</span>; }
}

<span class="reserved">public</span> <span class="reserved">delegate</span> <span class="reserved">void</span> <span class="type">PublicDelegate</span>();

<span class="reserved">namespace</span> A
{
    <span class="reserved">public</span> <span class="reserved">class</span> <span class="type">PublicClass</span> : <span class="type">PublicInterface</span>
    {
        <span class="reserved">private</span> <span class="type">PublicStruct</span> _value;

        <span class="reserved">public</span> <span class="type">PublicDelegate</span> X =&gt; _value.X;
    }

    <span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">PublicStruct</span>
    {
        <span class="reserved">public</span> <span class="type">PublicDelegate</span> X { <span class="reserved">get</span>; <span class="reserved">set</span>; }
    }
}
</code></pre>
<p>これらの型を定義しているのとは別のプロジェクトから参照する場合、
以下のように、internal なものへのアクセスはコンパイル エラーになります。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">namespace</span> ConsoleApplication
{
    <span class="reserved">class</span> <span class="type">Program</span>
    {
        <span class="reserved">static</span> <span class="reserved">void</span> Main(<span class="reserved">string</span>[] args)
        {
            <span class="reserved">var</span> c1 = <span class="reserved">new</span> A.<span class="type">PublicClass</span>();
            <span class="reserved">var</span> s1 = <span class="reserved">new</span> A.<span class="type">PublicStruct</span>();

            <span class="reserved">var</span> c2 = <span class="reserved">new</span> A.InternalClass();  <span class="comment">// コンパイル エラー</span>
            <span class="reserved">var</span> s2 = <span class="reserved">new</span> A.InternalStruct(); <span class="comment">// コンパイル エラー</span>
        }
    }
}
</code></pre>
<h3><a id="details">いくつか細かいルール</h3>
<p>ちなみに、入れ子であれば、型に対しても5種類全部のアクセシビリティを指定できます。
それぞれの意味は、<a href="http://ufcpp.net/study/csharp/oo_conceal.html">実装の隠蔽</a>で紹介したメンバーに対するものと同じです。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">TopLevelClass</span>
{
    <span class="reserved">public</span> <span class="reserved">class</span> <span class="type">PublicClass</span> { }
    <span class="reserved">protected</span> <span class="reserved">class</span> <span class="type">ProtectedClass</span> { }
    <span class="reserved">protected</span> <span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">ProtectedInternalClass</span> { }
    <span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">InternalClass</span> { }
    <span class="reserved">private</span> <span class="reserved">class</span> <span class="type">PrivateClass</span> { }
}
</code></pre>
<p>インターフェイスの実装であれば、
public なクラスで internal なインターフェイスを実装することも可能です。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">struct</span> <span class="type">PublicStruct</span> { }
<span class="reserved">public</span> <span class="reserved">interface</span> <span class="type">PublicInterface</span> { <span class="type">PublicStruct</span> X { <span class="reserved">get</span>; } }

<span class="reserved">internal</span> <span class="reserved">struct</span> <span class="type">InternalStruct</span> { }
<span class="reserved">internal</span> <span class="reserved">interface</span> <span class="type">InternalInterface</span> { <span class="type">InternalStruct</span> X { <span class="reserved">get</span>; } }

<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">PublicClass</span> : <span class="type">PublicInterface</span>, <span class="type">InternalInterface</span>
{
    <span class="reserved">public</span> <span class="type">PublicStruct</span> X =&gt; <span class="reserved">default</span>(<span class="type">PublicStruct</span>);
    <span class="type">InternalStruct</span> <span class="type">InternalInterface</span>.X =&gt; <span class="reserved">default</span>(<span class="type">InternalStruct</span>);
}
</code></pre>
<p>一方、internal なクラスを public なクラスで継承することはできません。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">internal</span> <span class="reserved">class</span> <span class="type">InternalClass</span> { }

<span class="comment">// コンパイル エラー</span>
<span class="reserved">public</span> <span class="reserved">class</span> <span class="type">PublicClass</span> : <span class="type">InternalClass</span>
{
}
</code></pre> ]]></description>
				<pubDate>Tue, 14 Jul 2015 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>型フォワーディング</title>
				<link>http://www.ufcpp.net/study/csharp/package/typeforwarding/</link>
				<description><![CDATA[ <p>.NETでは、「アセンブリ＋名前」の組み合わせで型を厳密に判定します。
その結果、異なるアセンブリでまったく同じ名前の型を定義しても、それぞれ別の型として扱われます。
これは、人的ミスの削減や、悪意あるコードへの耐性につながる一方で、
型の定義場所を移動させたいときに困ります。</p>
<p>そこで.NETは、型の検索の際に、別のアセンブリに転送する仕組みを提供しています。
これを型フォワーディング(Type Forwarding)と呼びます。</p>
<h2><a id="abstract">概要</h2>
<p>.NETでは、「アセンブリ＋名前」の組み合わせで型の所在を検索します。
その結果、異なるアセンブリでまったく同じ名前の型を定義しても、それぞれ別の型として扱われます。
これは、人的ミスの削減や、悪意あるコードへの耐性につながる一方で、
型の定義場所を移動させたいときに困ります。</p>
<p>そこで.NETは、型の検索の際に、別のアセンブリに転送する仕組みを提供しています。
これを型フォワーディング(type forwarding: 型の転送)と呼びます。</p>
<h5>サンプル</h5>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Package/TypeForwarding">https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Package/TypeForwarding</a></li>
</ul>
<h2><a id="TypeForwardedTo">TypeForwardedTo属性</h2>
<p>型フォワーディングには、<code>TypeForwardedTo</code>属性(<code>System.Runtime.CompilerServices</code>)というものを使います。</p>
<p>例えば、ActualLibraryという名前のライブラリがあって、この中に以下のようなクラスが定義されているとします。</p>
<pre class="source" title="ActualLibrary中">
<code><reserved></span><span class="reserved">public</span> <span class="reserved">class</span> <span class="type">Class1</span>
{
    <span class="reserved">public</span> <span class="reserved">string</span> Name =&gt; GetType().Assembly.GetName().Name + <span class="string">" / "</span> + <span class="reserved">nameof</span>(<span class="type">Class1</span>);
}
</code></pre>
<p>このActualLibraryを参照して、以下のような.csファイルを含む、TypeForwardingLibraryという名前のライブラリを作ります。</p>
<pre class="source" title="">
<code><reserved></span><span class="reserved">using</span> System.Runtime.CompilerServices;

[<span class="reserved">assembly</span>: <span class="type">TypeForwardedTo</span>(<span class="reserved">typeof</span>(<span class="type">Class1</span>))]
</code></pre>
<p>これで、アプリが「TypeForwardingLibraryにあるはずのClass1」を使おうとすると、
実際には「ActualLibraryで定義されたClass1」が返ってきます。</p>
<p><img src="/media/1022/typeforwarding.png" alt="型フォワーディング" /></p>
<p>これで、例えば、「元々ライブラリAにあった型を、ライブラリBに移した」という場合でも、
Aに<code>TypeForwardedTo</code>属性を書いておけば、互換性を崩さずに型を移動できます。</p>
<p>で、型の転送ができて何が嬉しいかというと、主に2通りの用途が考えられます。</p>
<ul>
<li>モジュール分割</li>
<li>バックポーティング</li>
</ul>
<!-- pageBreak -->
<h2><a id="modular">モジュール分割</h2>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Package/TypeForwarding/VersioningSamples">サンプル</a></li>
</ul>
<p>ありがちな技術的負債の1つに、単一のライブラリに債務を詰め込み過ぎるというのがあります。</p>
<p>取り急ぎ開発を進めていると、クラスの置き場に困ってついつい1つのライブラリになんでもかんでも置いてしまうということがあります。
そして、後から振り返ると、別々のライブラリに分けたくなったりします。</p>
<p>例えば、以下の様な状態です。</p>
<p><img src="/media/1023/monolithic.png" alt="詰め込み過ぎたライブラリ" /></p>
<p>「よく使う処理を拡張メソッドにして、ライブラリ化しよう」と試みて、気がつけば、文字列関連、ネットワーク関連、数値処理関連など、全然違う債務を1箇所に詰め込み過ぎてしまっています。
こういう状態を「一枚岩」(monolithic)であると言います。</p>
<p>そして、このライブラリの利用者が増えてきた頃に、「文字列関連だけが使いたい」「ネットワーク関連だけが使いたい」など、個別の要求が出てきます。</p>
<p>反省して複数のライブラリに分割することになったとして、問題は既存のユーザーです。
「アセンブリ＋名前」で型を探すわけで、別ライブラリに移動してしまうと互換性を崩します。</p>
<p>そこで、型フォワーディングの出番です。
詰め込み過ぎたライブラリを別のライブラリに分割した上で、元のライブラリには<code>TypeForwardedTo</code>属性だけを書きます。</p>
<p><img src="/media/1024/modular.png" alt="詰め込み過ぎたライブラリをモジュール分割" /></p>
<p>これで、互換性は崩さずに型を移動できます。</p>
<p>修正後のように、債務ごとに綺麗に分かれた状態を「モジュール型」(modular)と言います。
一枚岩な状態は、依存関係が大きくなりすぎたり、部分的な更新ができなかったりといった問題を抱えることになるので、
モジュール型な状態を保つよう心がけるべきです。</p>
<h3><a id="transpose">余談: 逆のやり方</h3>
<p>ちなみに、<code>TypeForwardedTo</code>属性を付けるのを逆にすることもできます。</p>
<p>上記の例で言うと、</p>
<ul>
<li>将来的にライブラリを StringClassLibrary, HttpClassLibrary, NumericClassLibrary の3つに分けることに決まった</li>
<li>が、今は分けてる余裕ない。MonolithicClassLibraryは今のままで維持したい</li>
<li>なので、新しく作ったStringClassLibrary, HttpClassLibrary, NumericClassLibrary の側に<code>TypeForwardedTo</code>属性をつけて、MonolithicClassLibraryに型を転送する</li>
</ul>
<p>というやり方もできます。</p>
<p>内部的には一枚岩のままなので、根本的には問題解決しません(依存関係は大きいままだし、部分更新できない)が、
「将来こう分割するよ」という予告にはなります。</p>
<h3><a id="modular-dotnet">余談: .NET 標準ライブラリのモジュール化</h3>
<p>「初期段階で一枚岩に作ってしまって、後からモジュール分割」という流れ、
.NET Frameworkの標準ライブラリが典型例だったりします。</p>
<p>.NET Framework 4までは、標準ライブラリ中のクラスの大半がmscorlib.dllというアセンブリに詰め込まれていました。
それが、.NET Framework 4.5で、System.Net.dll, System.Threading.dll, System.Linq.dll… など、債務ごとに分割されました。</p>
<p>ちなみに、方法としては前節の「<a href="#transpose">逆のやり方</a>」でやっています。
mscorlib.dll自体は元のままで、モジュール分割した側のアセンブリに<code>TypeForwardedTo</code>属性が入っています。</p>
<p>一方で、2015年に、Windowsデスクトップ向けの.NET Frameworkとは別に、
クロスプラットフォーム向けの「.NET Core」というバージョンの別実装が出てきました。</p>
<ul>
<li><a href="https://github.com/dotnet/coreclr">.NET Core Runtime (CoreCLR)</a></li>
<li><a href="https://github.com/dotnet/corefx">.NET Core Libraries (CoreFX)</a></li>
</ul>
<p>こっちのバージョンでは、最初からモジュール分割済みの実装が行われています。</p>
<!-- pageBreak -->
<h2><a id="backporting">バックポーティング</h2>
<ul>
<li><a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Package/TypeForwarding/FormattableString">サンプル</a></li>
</ul>
<p><a href="http://ufcpp.net/study/csharp/cheatsheet/listfxlangversion/">C#の言語バージョンと.NET Frameworkバージョン</a>で書いていますが、
C#の新しめの機能を、古いバージョンの.NET上で動かすためには、
いくつかライブラリのバックポーティング(新しいバージョンで追加された機能を、古いバージョンに向けて移植する作業)が必要なものがあります。</p>
<p>ここで問題になるのが、バージョンの混在です。</p>
<p>C# 5.0の<a href="http://ufcpp.net/study/csharp/sp5_async.html">async/await</a>を例にとって話しましょう。
まず、以下のように、.NET 4.5で完結している場合にはそもそもバックポーティングが必要なく、何の問題もありません。</p>
<p><img src="/media/1025/async45.png" alt=".NET 4.5 での async/await" /></p>
<p>一方で、例えばAsyncBridgeという名前でバックポーティング用のライブラリを用意したとします。
これを使う場合でも.NET 3.5で完結するなら、以下のように特に問題は置きません。</p>
<p><img src="/media/1026/async35.png" alt=".NET 3.5 での async/await バックポーティング" /></p>
<p>問題は、.NET 4.5向けライブラリと.NET 3.5向けライブラリの混在です。
.NET 4.5向けのものは標準ライブラリ(System.Threading.Tasks.dll)の<code>Task</code>クラスを参照し、
.NET 3.5向けのものはバックポーティング(AsyncBridge.dll)の<code>Task</code>クラスを参照している状態になります。
同名の別実装があると、どちらを参照すればいいのかわからなくなって色々と問題を起こします
(回避方法もなくはないものの、基本的にはコンパイルできなくなります)。</p>
<p>この問題の解決にも型フォワーディングが使えます。
以下のように、標準ライブラリへの型フォワーディングを書いたAsyncBridge.dllを用意します。</p>
<p><img src="/media/1027/asyncmixed.png" alt="標準ライブラリとバックポーティングの混在" /></p>
<p>つまり、以下のような実装が必要になります。</p>
<ul>
<li>
.NET 3.5向けに、標準ライブラリをバックポーティング実装を書いた AsyncBridge.dll を作る
<ul>
<li>.NET 3.5アプリからはこれを参照する</li>
</ul>
</li>
<li>
.NET 4.5向けに、標準ライブラリへの型フォワーディングを書いた AsyncBridge.dll を作る
<ul>
<li>.NET 4.5アプリからはこれを参照する</li>
</ul>
</li>
</ul>
<p>ちなみに、<a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/Package/TypeForwarding/FormattableString">サンプル</a>では、async/awaitではなく、もっと実装が簡単な<a href="http://ufcpp.net/study/csharp/st_string.html#FormatableString">FormatableString</a>の実装例を書いています。</p>
 ]]></description>
				<pubDate>Tue, 07 Jul 2015 15:57:24 +0900</pubDate>
			</item>
			<item>
				<title>プロジェクトの分割</title>
				<link>http://www.ufcpp.net/study/csharp/package/project/</link>
				<description><![CDATA[ <p>プログラムや、プログラムを作るための部品は「プロジェクト」という単位で管理します。</p>
<p>ここでは、プロジェクトという単位に分ける動機などについて説明していきます。</p>
<h2><a id="abst">概要</h2>
<p><a href="/study/csharp/devenv/vs_project/">プロジェクト管理</a>で触れたように、プログラムや、プログラムを作るための部品は「プロジェクト」という単位で管理します。</p>
<ul>
<li>依存関係を考える最小単位がプロジェクト</li>
<li>.NETの場合、プロジェクトの成果物は「アセンブリ」(dllもしくはexe)</li>
<li>いろんなプログラム、いろんな環境で使える部分を別プロジェクトに切り出して使う</li>
</ul>
<h2><a id="dependency">依存関係</h2>
<p>プログラムをちゃんと部品として分けて作って、その部品をいろんなプログラムから再利用するためには、依存関係の整理が必要です。</p>
<p>依存関係(dependecy)について説明するために、まずはクラスの依存について考えてみます。例えば、以下の図のようなコードを見てください。</p>
<p><img src="/media/1011/dependency1.png" alt="クラスの依存関係" /></p>
<p>図中の矢印が「依存」です。あるクラスが別のクラスから使われているという状態。</p>
<p>この例は、ゲームでよくありそうなデータ構造です。</p>
<ul>
<li>各ユーザー(<code>User</code>)が、ユニット(<code>Unit</code>)を複数持っていて、1つの同盟(<code>Alliance</code>)に入っている。</li>
<li>各同盟には複数のユーザー(<code>User</code>)がメンバーとして含まれている。</li>
<li>各ユニットは装備品(<code>Equipment</code>)を複数装備している。</li>
</ul>
<p>今回の場合、1クラス1ファイルで分けているので、ソースコード ファイル的にも以下のような依存関係があります。</p>
<p><img src="/media/1012/dependency2.png" alt="ソースコード ファイルの依存関係" /></p>
<p>この関係からは、以下のようなことが言えます。</p>
<ul>
<li><code>Equipment.cs</code> は単体で切り出せる。</li>
<li><code>Unit.cs</code>を使うには<code>Equipment.cs</code>もセットで必要。</li>
<li><code>User.cs</code>を使おうとすると、芋づる式に<code>Alliance.cs</code>、<code>Unit.cs</code>、<code>Equipment.cs</code>すべてが必要。</li>
<li><code>User.cs</code>と<code>Alliance.cs</code>は相互依存していて、絶対に切り離せない。</li>
</ul>
<p>このように、依存関係を整理することによって、「何かを抜き出して使うには別の何かが必要になる」というような状況が見えてきます。</p>
<h3><a id="physical-path">補足: .NETのソースコード ファイル配置</h3>
<p>(C#を含め).NETでは、<code>.cs</code>ファイルなどのソースコードと、クラス、メソッドなどのC#文法構成要素との間に何の制約もありません。<code>A.cs</code>というファイルに<code>B</code>というクラスがあっても構いません。「<a href="http://ufcpp.net/study/csharp/oo_class.html#partial">クラスの分割定義</a>」ができるので、複数のファイルにわたって1つのクラスを書くこともできます。</p>
<p>(他の言語だと、ファイル名を使って参照解決したり、ファイル名とクラス名が同じでないといけないという制約があったりするものもあります。)</p>
<p>ただ、一般的に推奨される方針としては、<a href="http://ufcpp.net/study/csharp/sp_namespace.html">名前空間</a>と同じフォルダー階層の下に、クラス名と同じ名前の<code>.cs</code>ファイルを作る方がよいとされています。</p>
<!-- pageBreak -->
<h2><a id="project">プロジェクト</h2>
<p>これまでファイル単位で説明してきましたが、クラスやファイルという単位は細かすぎて、依存管理には不向きです(管理しきれない)。もう少し大きな単位で区切る必要があって、これが「プロジェクト」を作る動機です。</p>
<p><img src="/media/1013/projectdependency1.png" alt="enter image description here" /></p>
<p>プロジェクト内のファイルやクラスに関しては、依存関係をあまり気にする必要はありません。仕組み上は、どれだけ複雑な依存関係を持っていても構いません。</p>
<p>(ただし、もちろん、「最初は1つのプロジェクトとして作ってしまったけども、この部分は汎用的に使えそうだから抜き出して別プロジェクトにしよう」というようなこともよくあるので、プロジェクト内であっても依存関係には気をつけておいた方が後々よい結果になることはあります。)</p>
<p>一方で、プロジェクト間の依存関係はきちんと考えないと行けません。ここをサボると、何かを抜き出して使いたい時に、芋づる式にいろいろなものが必要になって困ることがあります。必要な物が増える事による問題の例をいくつか挙げると、以下のようなものがあります。</p>
<ul>
<li>必要なコードが増えて、最終的なプログラムのサイズが肥大化する</li>
<li>依存先がアップデートされたときの追従が大変になる</li>
<li>動かせないリスク、例えば、「Windowsプログラムで今まで動いていたコードをiOSアプリで使いたい」とか言う時に動かせない可能性が高まる(依存先すべてがiOS実行に対応していないといけない)</li>
</ul>
<h2><a id="project-artifact">プロジェクトの成果物</h2>
<p>プロジェクト内のファイルは個別に切り出して使うことをあまり想定しません。プロジェクトというものが、プログラム、あるいは、プログラムを作るための部品の最小単位です。そのため、プロジェクトによって得られる成果物は、1つのファイルにまとめたりします。</p>
<p>C#など、.NET言語の場合は、複数のソースコードのコンパイル結果を最初から1つのファイルにまとめて出力します。(他のプログラミング言語では、バラバラに出力されたコンパイル結果を ZIP 形式ファイルなどにまとめたりするものもあります。) 出力されるファイルは以下のいずれかです。</p>
<ul>
<li>ライブラリ … 単体で実行できない。他のプログラムから参照して使う部品。拡張子dll(dymamic link library。dymamicとかlinkとかの言葉の意味はまた別の機会に)。</li>
<li>実行可能ファイル … 単体で実行できるプ プログラム。拡張子exe。</li>
</ul>
<p>.NET の場合、dllでもexeでも中身はほとんど同じ(exeの方にはプログラムの開始地点の情報が多い程度)です。これらは合わせて、<strong id="assembly" class="keyword">アセンブリ</strong>(assembly: (組み立て)部品)といいます。</p>
<h2><a id="separation">プロジェクトの分け方</h2>
<p>プロジェクトを分ける(プログラムを部品化する)1番の動機は、いろんなプログラム、いろんな環境から使いたいというものです。</p>
<h2><a id="multi-purpose">いろんなプログラムから1つの部品を使う</h2>
<p>最初にゲームっぽい例を出したついでですし、ここでもゲームを作ることを考えましょう。</p>
<p>今どきはどんなゲームもオンラインでつながっています。ゲーム本体と同じコードをサーバー側で共有したいことも多いでしょう。また、ゲーム自体のプログラムの他にも、テスト用や、企画者向けのプログラムが必要になったりします。</p>
<ul>
<li>ゲーム本体 … ゲーム専用ハードウェア上で動かしたりします。今どきだとiPhoneやAndroid向けも多いです。</li>
<li>ゲーム サーバー … 複数のプレイヤー間でゲーム本体からのデータを中継するだけの簡単なものから、ゲームの核となる処理がすべてサーバー上で動いている場合まであります。</li>
<li>テスト用プログラム … ゲーム中の特定の部位だけを抜き出して、そこを重点的にデバッグしたりすることがあります。</li>
<li>企画者向けツール … ゲーム中のデータを作ったりバランス調整したりするため、開発者以外の人でも動作を確認しつつデータを編集できるツールが必要になります。</li>
</ul>
<p>こういう場合、このいずれからも使う部分を別プロジェクトに切り出して、全部から参照して使います。</p>
<p><img src="/media/1014/projectarchitecture1.png" alt="enter image description here" /></p>
<h2><a id="multi-platform">いろんな環境から1つの部品を使う</h2>
<p>Windowsに限って言っても、組み込み製品、デスクトップ、サーバー、ゲーム機など、要件の異なるいろいろな機器の上で動きます。スマホやタブレットでいうと、iOSやAndroidとシェアが分かれていて、そのどちらにも対応したプログラムを書く必要がある場面は多いです。そして、こういう環境が変わると、使える機能(参照できるアセンブリ)が違ってきます。</p>
<p>こういう場合、環境によらず共通して使える部分と、それぞれの環境に応じた(それぞれの専用のフレームワークに依存した)部分に分かれます。</p>
<p><img src="/media/1015/projectarchitecture2.png" alt="enter image description here" /></p>
 ]]></description>
				<pubDate>Sat, 16 May 2015 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>Code-Awareなライブラリ</title>
				<link>http://www.ufcpp.net/study/csharp/package/pkgcodeawarelibrary/</link>
				<description><![CDATA[ <p>.NET Compiler Platformによって、Code-Awareなライブラリを作れるようになりました。
Code-Aware、直訳すると「コードを理解している」「コードを意識している」という感じになります。ライブラリだけでなく、ライブラリ利用側のコードを理解して、問題点の指摘やその修正方法まで提供することを言います。</p>
<h2><a id="abst"> 概要</h2>
<h5 class="version version6">Ver. 6</h5>
<p>(C# 6の言語的な機能ではありませんが、C# 6と同世代(Visual Studio 2015世代)の技術なので、利用できるのはC# 6以降になります。)</p>
<p><a href="/study/csharp/misc/misc_roslyn?key=compiler-platform">.NET Compiler Platform</a>を使うことで、
コードを解析してその問題点の指摘やその修正方法を提供できる、コード アナライザーというものを作れます。</p>
<p>ライブラリを作る際、そのライブラリに特化したコード アナライザーを作って同梱して配ることで、
「ライブラリ自身が、ライブラリ利用側のコードを理解して、問題点の指摘やその修正方法まで提供」ということが実現できます。</p>
<p>こういう、「利用側のコードを理解するライブラリ」を、Code-Aware なライブラリと呼びます。</p>
<h5>サンプル</h5>
<p><a href="https://github.com/ufcpp/UfcppSample/tree/master/Chapters/DevEnv/CodeAwareLibrarySample">https://github.com/ufcpp/UfcppSample/tree/master/Chapters/DevEnv/CodeAwareLibrarySample</a></p>
<h2>コード アナライザー</h2>
<p>(アナライザー自体の説明はたぶんそのうち別ページに分ける。分けたあかつきには: 
1. C#はリアルタイムに、書いてるそばからエラー・警告出してもらえる言語。
2. Visual Studio以外もRoslyn対応そのうちするはず。Xamarinは近々？VSチームがOmniSharpにも協力してたはず。)</p>
<p><a href="/study/csharp/cheatsheet/ap_ver6">C# 6 の新機能</a>の冒頭で触れていますが、しばらくの間、C#コンパイラーの再実装に工数を割いていて、C# 6は言語機能としては大きなものがあまりありません。言語的に大きな機能追加がなかった代わりと言ってはなんですが、新しくなったコンパイラーには別の「売り」があります。それが、コード アナライザーの作成です。</p>
<p>コード アナライザーは、「コードを解析するもの」という名前通り、C#ソースコードを解析して、問題点を指摘したり、その修正機能を提供するものです。こういう解析機能を、誰でも自由に作れるようになりました。</p>
<p>その結果、C#コンパイラー自身では提供しにくいような、以下の様なコード解析が実現できます。</p>
<ol>
<li>
経験則的な警告・エラーの提示
<ul>
<li>機械的な判断だと間違う可能性のあるものは、コンパイラー機能としては実装しにくい</li>
</ul>
</li>
<li>
チーム内でのローカル ルールの解析
<ul>
<li>ルールはチームごとに違ったりするので、コンパイラーにはわからない</li>
</ul>
</li>
<li>
ライブラリ固有の事情
<ul>
<li>特定のライブラリのためだけのコード解析は、標準では提供すべきではない</li>
</ul>
</li>
</ol>
<p>本稿の主題は3つ目の「ライブラリ固有の事情」になります。</p>
<h2><a id="libary-specific"> ライブラリ固有の事情の例</h2>
<p>簡単な例を上げてみましょう。以下のようなコードをライブラリ化することを考えます。</p>
<pre class="source" title="fluent interface な算術演算ライブラリ">
<code><reserved></span><span class="reserved">namespace</span> FluentArithmetic
{
    <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">class</span> <span class="type">FluentExtensions</span>
    {
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> Add(<span class="reserved">this</span> <span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; x + y;
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> Sub(<span class="reserved">this</span> <span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; x - y;
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> Mul(<span class="reserved">this</span> <span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; x * y;
        <span class="reserved">public</span> <span class="reserved">static</span> <span class="reserved">int</span> Div(<span class="reserved">this</span> <span class="reserved">int</span> x, <span class="reserved">int</span> y) =&gt; x / y;
    }
}
</code></pre>
<p><code>a + b - c</code> などと書く代わりに、<code>a.Add(b).Sub(c)</code> と書けるようにするコードです。特に使い道はないんですが、「ライブラリ固有の事情」の説明にはなかなか手頃だと思います。</p>
<p>単純な四則演算なわけですから、いくつかの経験則が働くでしょう。ここでは2つほど挙げると、以下のようなものがあります。</p>
<ul>
<li><code>1.Div(0)</code> というような、「0割り」は実行してみるまでもなくエラーになることがわかっている</li>
<li><code>1.Add(2)</code> というような、<a href="/study/csharp/st_variable.html#literal">リテラル</a>同士の演算は、<code>3</code> などに置き換えて最適化できる</li>
</ul>
<p>「<code>Div(0)</code> と書いたら常にエラーを起こす」というのは完全にこのライブラリ固有の事情になります。このライブラリのこの<code>Div</code>メソッドに限り、常に実行時エラーを起こすんだからもうコンパイル時にエラーにしたい。しかし、コンパイラーは、そんな特定のライブラリだけの特殊対応なんてできません。こんな時こそコード アナライザーの出番です。</p>
<h2><a id="libary-specific-analyzer"> ライブラリ固有のコード アナライザーの例</h2>
<p>ということで、以下のような機能を提供するコード アナライザーを考えます。</p>
<ul>
<li><code>Div(0)</code> を見たら問答無用でコンパイル エラーにする</li>
<li>
<code>1.Add(2)</code> とかのリテラル同士の演算は最適化できる旨、情報を出す
<ul>
<li>この最適化を自動的に行う「クイック アクション」を提供する</li>
</ul>
</li>
</ul>
<p>実際に実装してみた感じが以下の通り。</p>
<p>まず、<code>Div(0)</code>エラー。ちゃんとコンパイル エラーです。直さないとコンパイルできません。</p>
<p><img src="/media/1007/codeawarelibrary1.png" alt="Div(0) エラー" /></p>
<p>次が、<code>1.Add(2)</code> は最適化できるという情報。この場合、別にエラーにもならないし、警告も出ません。</p>
<p><img src="/media/1008/codeawarelibrary2.png" alt="リテラル同士の演算" /></p>
<p>エラーにも警告にもなりませんが、該当箇所には電球(lightbulb)マークがついています。この電球をクリックする(もしくは、<code>Ctrl+.</code> ショートカットキーを押す)と、コードの自動修正(code fix)が働きます。</p>
<p><img src="/media/1009/codeawarelibrary3.png" alt="電球マークをクリック" /></p>
<p>実行すると以下のようになるはずです。</p>
<p><img src="/media/1010/codeawarelibrary4.png" alt="自動修正の結果" /></p>
<p>ちなみに、Visual Studio的には、この「電球マークを起点として何か処理を掛ける」操作を「クイック アクション」といいます。</p>
<h2><a id="code-aware"> Code-Aware ライブラリ</h2>
<p><a href="https://github.com/ufcpp/UfcppSample/tree/master/DevEnv/CodeAwareLibrarySample">サンプル</a>は実際にこの例のライブラリとそれ用コード アナライザーを実装したものです。</p>
<ul>
<li>FluentArithmetic.dll: ライブラリ本体。<code>a.Add(b).Sub(c)</code> という類の書き方で整数の四則演算をするためのライブラリ。</li>
<li>FluentArithmeticAnalyzer.dll: FluentArithmetic 専用のコード アナライザー。</li>
</ul>
<p>ライブラリ専用なわけですから、コード アナライザーはライブラリ本体とセットで配布すべきでしょう。
そうすることで、ライブラリ自身がライブラリ利用側のコードを見て、問題点の指摘やその修正方法まで提供できる状態になります。こういう状態のライブラリを、「利用側のコードまで理解する」、「利用側のコードを意識している」という意味で「Code-Aware」と言います。</p>
<p>要するに、以下の様なパッケージを作って配布します。</p>
<ul>
<li>ライブラリと、それ用コード アナライザーを同梱する</li>
<li>パッケージ インストール時に走るスクリプトで、コード アナライザーへの参照を足す</li>
</ul>
<p>（書きかけ）以下、作成手順の説明</p>
<ul>
<li>
テンプレート通りに「Analyzer with Code Fix (NuGet + VSIX)」を作れば大体それっぽいものできてる
<ul>
<li>nuspec とか、install.ps1 最初からある</li>
</ul>
</li>
<li>これに、ライブラリ本体の参照を足す</li>
<li>今回の場合、nuspec とか install.ps1 とか、「ビルド後に実行するコマンドライン」でNuGetコマンドを呼ぶ処理は別プロジェクトに分離・移動</li>
<li>
コード アナライザーの動作確認は Test プロジェクトの実行で
<ul>
<li>Vsix プロジェクトを実行すると別 Visual Studio が立ち上がってデバッグ実行できるんだけど、重いし、エラーが出た時悲惨だし</li>
</ul>
</li>
<li>一応 NuGet Gallary においてある: https://www.nuget.org/packages/FluentArithmetic/</li>
</ul>
<p>（書きかけ）どういう場合に有効かの例をもう何例か列挙</p>
<ul>
<li>JSONパーサー ライブラリ同梱で、文字列リテラル中のJSONを解析</li>
<li>正規表現ライブラリ同梱で、<code>Regex(&quot;ここの解析&quot;)</code></li>
</ul>
 ]]></description>
				<pubDate>Wed, 13 May 2015 00:00:00 +0900</pubDate>
			</item>
			<item>
				<title>プロジェクト管理</title>
				<link>http://www.ufcpp.net/study/csharp/devenv/vs_project/</link>
				<description><![CDATA[ <p>Visual Studio で C# を使ったプログラム開発を行う場合、まず、「プロジェクト」というものを作ります。
また、この際、「ソリューション」というものが一緒に作られます。</p>
<p>ここでは、そのプロジェクトの作り方の簡単な紹介と、プロジェクトやソリューションが何なのか、どうして必要なのかを説明します。</p>
<h2><a id="abstract"> 概要</h2>
<p>Visual Studio で C# を使ったプログラム開発を行う場合、まず、「プロジェクト」というものを作ります。
また、この際、「ソリューション」というものが一緒に作られます。</p>
<p>ここでは、そのプロジェクトの作り方の簡単な紹介と、プロジェクトやソリューションが何なのか、どうして必要なのかを説明します。</p>
<h5>ポイント</h5>
<ul>
<li>プロジェクト: 1つのプログラムを作るのに必要な各種ファイルを管理するもの</li>
<li>ソリューション: 1つの課題を解決するのに必要な一連のプロジェクト(≒ プログラム)を管理するもの</li>
</ul>
<p>ちなみに、プログラムを作るのにどうして「プロジェクト」という単位が必要になるのかや、
どういう単位で「プロジェクト」を区切るのかなどは
「<a href="http://ufcpp.net/study/csharp/package/project/">プロジェクトの分割</a>」で説明します。</p>
<h2><a id="new-project"> プロジェクトの作成</h2>
<p>プロジェクトやソリューションの説明は次節以降でしますが、まずは、そのプロジェクトの作り方を簡単に紹介します。
(※ここでは、Visual Studio 2015を使ってスクリーンショットを撮っています。他のバージョンでもそれほど大きな違いはありません。)
Visual Studio を起動すると以下のような画面になっていると思います。</p>
<p><img src="/media/1002/newproject1.png" alt="Visual Studio 起動直後" /></p>
<p>ここで、「スタート」→「新しいプロジェクト」を選ぶと、以下のようなダイアログが表示されます。</p>
<p><img src="/media/1003/newproject2.png" alt="「新しいプロジェクト」で「プロジェクト テンプレート」を選択" /></p>
<p>この中から、作りたいプログラムの種類に応じた「プロジェクト テンプレート」(後述)を選びます。</p>
<p>この「C# によるプログラミング入門」での説明の多くは「コンソール アプリケーション」で動きます。ここでも「コンソール アプリケーション」を選びます。通常は、「名前」のところには作りたいプログラムの名前に応じた適切な名前を入力します。今回はとりあえず、最初から入っている「ConsoleApplication1」という名前のままでプロジェクトを作ってみましょう。これで、以下のような画面になるはずです。</p>
<p><img src="/media/1005/newproject3.png" alt="プロジェクト作成直後" /></p>
<p>これで、プログラム作成に必要な最低ラインの準備が整いました。ちなみに、この時点で(プロジェクトの新規作成をしただけで)、ソリューションというものも一緒に作られています。
 以降では、ここで出てきた「プロジェクト」「ソリューション」「プロジェクト テンプレート」などの言葉について説明していきます。</p>
<h2><a id="project"> プロジェクトとは</h2>
<p>プログラムの作成・実行 で説明するように、ソースコードをコンパイルすることでプログラムを作ります。
通常、ソースコードは切りのいい単位ごとに別ファイルに分けて作るので、プログラムの作成には複数のソースコード ファイルが必要になります。
また、プログラムの種類によっては、ソースコード以外にも画像や音声など、様々な素材（アセット(asset)と呼んだりします）が必要です。</p>
<p>これら、プログラムを作るのに必要なファイルを管理するのがプロジェクトです。
例えば、下図の場合、ConsoleApplication1 という名前のプロジェクトに、App.config、Logic.cs、Program.cs という3つのファイルが管理されています。</p>
<p><img src="/media/1001/project1.png" alt="enter image description here" /></p>
<p>その他、C#のプロジェクトでは以下のようなものを管理します。</p>
<ul>
<li>ライブラリ の参照</li>
<li>コンパイル オプション(プログラム名、C# のバージョンや、コンパイル時の警告の厳しさなど)の設定</li>
<li>プログラムの種類によっては、インストーラー作成や、サーバーやストアへのアップロード方法などの設定</li>
</ul>
<h2><a id="solution"> ソリューションとは</h2>
<p>何かやりたいこと(課題)があるからプログラムを作るはずです。
そしてそのやりたいことの実現(解決)には、1つのプログラムではなく、複数のプログラムを作る場合があります。
あるいは、それらのプログラムから共通利用する「部品」も必要になったりします。</p>
<p>このような、やりたいことを実現(課題を解決)するために必要な複数のプログラムや部品(その1つ1つがプロジェクトとして管理される)を束ねるのがソリューション(solution: 解決策)です。</p>
<p>以下の図は、例として、「アプリ1」「社内ツール1」「社内ツール2」という3つのプログラムと、この3つから使う「共通部品」という、合わせて4つのプロジェクトを作った例です。
この3つのプロジェクトを管理するのが「アプリ1」ソリューションです。</p>
<p><img src="/media/1139/solution1.png" alt="4つのプロジェクトを含むソリューションの例" /></p>
<p>ソリューション内には、プロジェクト間の依存関係などが記録されています。</p>
<h2><a id="project-template"> プロジェクト テンプレート</h2>
<p>プログラムに必要なソースコードなどのファイルは、どんなプログラムでも同じなような必要最低限のものであっても、結構な分量があります。
どんなプログラムでもだいたい同じになるなら、最初からひな形を用意しようというのが、プロジェクト テンプレート(project template: プロジェクトのひな形)です。</p>
<p>いくつか紹介しましょう。</p>
<table>
<tr>
<th>テンプレートの種類</th><th>説明</th>
</tr>
<tr>
<td>コンソール アプリケーション</td>
<td>“古き良き”文字だけのプログラムのことをコンソール アプリケーション(console application: console は操作卓という意味。昔はコンピューターをキーボードからの文字入力だけで操作していたのの名残)といいます。</td>
</tr>
<tr>
<td>ASP.NET Web アプリケーション</td>
<td>Web アプリを作ります。ASP.NET は、C#でWebアプリを作るためのフレームワークの名前です。</td>
</tr>
<tr>
<td>Blank App (Windows Universal)</td>
<td>(Windows 10以降用の)Windows GUIアプリを作ります。C#でGUIアプリを作るためのフレームワークは、詳細は省きますが、歴史的経緯で、他にも WPF、Windows Formsなどたくさんあります。</td>
</tr>
</table>
<p>とにかく習うより慣れろで見た目に面白いものや、実用的なものを作りたいという方は、Web アプリや GUI アプリから始めるのもいいでしょう。</p>
<p>作るのが簡単なのはコンソール アプリです。
このサイトでは、C# というプログラミング言語や、プログラミングに関する概念的な説明が主題なので、ほとんどのサンプルがコンソール アプリになっています。</p>
<p>その他にもいろんな種類のテンプレートが用意されています。例えば、Visual Studio 2015では、iOSやAndroidなど、マイクロソフト以外の製品向けのアプリ開発ができるテンプレートも用意されています。選べるプログラミング言語も、C#の他、C++、Visual Basic、JavaScript、TypeScriptなどたくさんあります。Visual Studioが標準で用意しているものの他にも、拡張機能(いろんな会社から、商用・非商用問わずたくさん出ています)を入れることでより多くのテンプレートを利用できます。</p>
 ]]></description>
				<pubDate>Tue, 12 May 2015 00:00:00 +0900</pubDate>
			</item>
</channel>
</rss>