"パターン ベースの using" と "using 宣言"
メモ
この記事は機能仕様についてです。 仕様は、機能の設計ドキュメントとして使用できます。 これには、提案された仕様の変更および機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が決定され、現在の ECMA 仕様に組み込まれるまで公開されます。
機能の仕様と行われた実装では、いくつかの違いがあることがあります。 これらの違いは、関連する言語設計ミーティング (LDM) メモに取り上げられています。
機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。
チャンピオンの課題: https://github.com/dotnet/csharplang/issues/114
まとめ
この言語では、リソース管理を簡単にするために、using
ステートメントの周囲に 2 つの新機能が追加されます。using
は、IDisposable
に加えて破棄可能なパターンを認識し、using
宣言を言語に追加します。
目的
using
ステートメントは、今日のリソース管理に効果的なツールですが、かなりの形式的な処理が必要です。 管理するリソースが多数あるメソッドでは、一連の using
ステートメントでは構文的に行き詰まる可能性があります。 このような構文上の負担が大きいため、ほとんどのコーディング スタイル ガイドラインでは、このシナリオに対して中括弧に関する例外を明示的に規定しています。
using
宣言はここでの形式的な処理の多くを削除し、リソース管理ブロックを含む他の言語と同等の C# を取得します。 さらに、パターンベースの using
を使用すると、開発者はここで参加できる型のセットを拡張できます。 多くの場合、using
ステートメントで値を使用できるようにするためにのみ存在するラッパー型を作成する必要がなくなります。
これらの機能を組み合わせることで、開発者は using
を適用できるシナリオを簡素化および拡張できます。
詳細な設計
using 宣言
この言語を使用すると、ローカル変数宣言に using
を追加できます。 このような宣言は、同じ場所にある using
ステートメントで変数を宣言する場合と同じ効果を持ちます。
if (...)
{
using FileStream f = new FileStream(@"C:\source\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\source\using.md"))
{
// statements
}
}
using
ローカルの有効期間は、それが宣言されているスコープの最後まで延長されます。 その後、using
ローカルは宣言されている順序の逆に破棄されます。
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("...");
using var f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
using
宣言に直面しても、goto
やその他の制御フロー コンストラクトに関する制限はありません。 代わりに、コードは同等の using
ステートメントの場合と同じように機能します。
{
using var f1 = new FileStream("...");
target:
using var f2 = new FileStream("...");
if (someCondition)
{
// Causes f2 to be disposed but has no effect on f1
goto target;
}
}
using
ローカル宣言で宣言されたローカルは、暗黙的に読み取り専用になります。 これは、using
ステートメントで宣言されたローカルの動作と一致します。
using
宣言の言語文法は次のようになります。
local-using-declaration:
'using' type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
using
宣言に関する制限事項:
case
ラベル内に直接表示されるのではなく、case
ラベル内のブロック内に配置する必要があります。out
変数宣言の一部として表示されない場合があります。- 各宣言子の初期化子が必要です。
- ローカル型は、暗黙的に
IDisposable
に変換可能であるか、using
パターンを満たす必要があります。
パターンベースの using
言語は、ref struct
型の破棄可能なパターンの概念を追加します。これは、アクセス可能な Dispose
インスタンス メソッドを持つ ref struct
です。 破棄可能なパターンに適合する型は、IDisposable
の実装を必要とせずに、using
ステートメントまたは宣言に参加できます。
ref struct Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
これにより、開発者はusing
をref struct
型に活用できます。 これらの型は C# 8 でインターフェイスを実装できないため、using
ステートメントに参加できません。
ここでは、従来の using
ステートメントと同じ制限が適用されます。using
で宣言されたローカル変数は読み取り専用で、null
値では例外がスローされません。コード生成は、Dispose を呼び出す前に IDisposable
にキャストされないという点でのみ異なります。
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
破棄可能なパターンに合わせるには、Dispose
メソッドはアクセス可能なインスタンス メンバーであり、パラメーターなしであり、void
戻り値の型がある必要があります。 拡張メソッドにすることはできません。
考慮事項
これらの考慮事項はどちらも C# 8 では実装されませんでした
ブロックなしのケースラベル
using declaration
は、その実際の寿命に関する問題のため、case
ラベル内で直接使用することはできません。 考えられる解決策の 1 つは、単に同じ場所の out var
と同じ有効期間を設定することです。 機能実装の複雑さが増し、回避策の容易さ (case
ラベルにブロックを追加するだけ) は、このルートを取ることを正当化しなかったと見なされました。
今後の拡張
fixed ローカル
fixed
ステートメントには、using
ローカルを持つ機能の根拠となった using
ステートメントのすべての特性があります。 この機能をローカル fixed
に拡張することにも考慮する必要があります。 有効期間と順序付け規則は、ここで using
と fixed
に同じように適用されます。
C# feature specifications