"パターンベースの使用" と "宣言の使用""pattern-based using" and "using declarations"
まとめSummary
この言語では、リソース管理を簡略化するために、ステートメントの周囲に2つの新機能が追加され using
ます。では using
、に加えて、破棄可能なパターンを認識 IDisposable
し、 using
宣言を言語に追加します。The language will add two new capabilities around the using
statement in order to make resource management simpler: using
should recognize a disposable pattern in addition to IDisposable
and add a using
declaration to the language.
目的Motivation
using
このステートメントは、今日のリソース管理のための効果的なツールですが、かなりの手続きが必要です。The using
statement is an effective tool for resource management today but it requires quite a bit of ceremony. 多数のリソースを管理するメソッドでは、一連のステートメントを使用して構文的に行き詰まるを取得でき using
ます。Methods that have a number of resources to manage can get syntactically bogged down with a series of using
statements. この構文の負担は、ほとんどのコーディングスタイルのガイドラインで、このシナリオで中かっこを囲む例外が明示的に設定されているためです。This syntax burden is enough that most coding style guidelines explicitly have an exception around braces for this scenario.
using
この宣言は、ここでは多くの手続きを削除し、リソース管理ブロックを含む他の言語と同等に C# を取得します。The using
declaration removes much of the ceremony here and gets C# on par with other languages that include resource management blocks. さらに、パターンベースのを使用すると、 using
開発者はここで参加できる型のセットを展開できます。Additionally the pattern-based using
lets developers expand the set of types that can participate here. 多くの場合、ステートメントで値を使用できるようにするためだけに存在するラッパー型を作成する必要はあり using
ません。In many cases removing the need to create wrapper types that only exist to allow for a values use in a using
statement.
これらの機能を組み合わせて使用すると、を適用できるシナリオを簡略化および拡張でき using
ます。Together these features allow developers to simplify and expand the scenarios where using
can be applied.
詳細なデザインDetailed Design
using 宣言using declaration
この言語では、を using
ローカル変数宣言に追加できます。The language will allow for using
to be added to a local variable declaration. このような宣言は、 using
同じ場所にあるステートメントで変数を宣言するのと同じ効果があります。Such a declaration will have the same effect as declaring the variable in a using
statement at the same location.
if (...)
{
using FileStream f = new FileStream(@"C:\users\jaredpar\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\users\jaredpar\using.md"))
{
// statements
}
}
ローカルの有効期間は、 using
宣言されているスコープの末尾まで拡張されます。The lifetime of a using
local will extend to the end of the scope in which it is declared. using
ローカル変数は、宣言された順序と逆の順序で破棄されます。The using
locals will then be disposed in the reverse order in which they are declared.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("..."), f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
goto
宣言の表面には、または他の制御フローコンストラクトに関する制限はありません using
。There are no restrictions around goto
, or any other control flow construct in the face of a using
declaration. 代わりに、コードは同等のステートメントと同じように動作し using
ます。Instead the code acts just as it would for the equivalent using
statement:
{
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
ます。A local declared in a using
local declaration will be implicitly read-only. これは、ステートメントで宣言されたローカルの動作と一致し using
ます。This matches the behavior of locals declared in a using
statement.
宣言の言語文法は using
次のようになります。The language grammar for using
declarations will be the following:
local-using-declaration:
using type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
宣言に関する制限事項 using
は次のとおりです。Restrictions around using
declaration:
- ラベル内に直接表示
case
することはできませんが、代わりにラベル内のブロック内に配置する必要case
があります。May not appear directly inside acase
label but instead must be within a block inside thecase
label. - 変数宣言の一部として表示
out
されない場合があります。May not appear as part of anout
variable declaration. - 宣言子ごとに初期化子が必要です。Must have an initializer for each declarator.
- ローカル型は、 に暗黙的に変換するか、パターン
IDisposable
を満たす必要using
があります。The local type must be implicitly convertible toIDisposable
or fulfill theusing
pattern.
を使用したパターンベースのpattern-based using
この言語では、使い捨て可能なパターンの "つまり、アクセス可能なインスタンス メソッドを持つ型" の呼び出しが Dispose
追加されます。The language will add the notion of a disposable pattern: that is a type which has an accessible Dispose
instance method. 使い捨てパターンに適合する型は、 を実装する必要なく、 ステートメント using
または宣言に参加できます IDisposable
。Types which fit the disposable pattern can participate in a using
statement or declaration without being required to implement IDisposable
.
class Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
これにより、開発者は次の多くの using
新しいシナリオを利用できます。This will allow developers to leverage using
in a number of new scenarios:
ref struct
: これらの型は現在インターフェイスを実装できないので、 ステートメントにusing
参加できません。ref struct
: These types can't implement interfaces today and hence can't participate inusing
statements.- 拡張メソッドを使用すると、開発者は他のアセンブリの型を拡張して ステートメントに
using
参加させることができます。Extension methods will allow developers to augment types in other assemblies to participate inusing
statements.
型を 暗黙的に に変換し、また、使い捨て可能なパターンに適合できる状況では、 IDisposable
が IDisposable
優先されます。In the situation where a type can be implicitly converted to IDisposable
and also fits the disposable pattern, then IDisposable
will be preferred. これは (インターフェイスより優先されるパターン) の反対のアプローチを採用しますが foreach
、下位互換性のためには必要です。While this takes the opposite approach of foreach
(pattern preferred over interface) it is necessary for backwards compatibility.
従来の ステートメントと同じ制限がここでも適用されます。 で宣言されたローカル変数は読み取り専用です。値を指定した場合、例外がスローされるなどはありません。 using
using
null
コード生成が異なるのは、Dispose を呼び出す前に へのキャスト IDisposable
が含されないという場合のみです。The same restrictions from a traditional using
statement apply here as well: local variables declared in the using
are read-only, a null
value will not cause an exception to be thrown, etc ... The code generation will be different only in that there will not be a cast to IDisposable
before calling Dispose:
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
使い捨て可能なパターンに適合するには、メソッドにアクセス可能で、パラメーターなしで、戻り Dispose
値の型を持 void
つ必要があります。In order to fit the disposable pattern the Dispose
method must be accessible, parameterless and have a void
return type. その他の制限はありません。There are no other restrictions. これは、拡張メソッドをここで使用できる明示的な意味です。This explicitly means that extension methods can be used here.
考慮事項Considerations
ブロックを含めずに大文字と小文字のラベルを作成するcase labels without blocks
は using declaration
、実際の有効期間に関する複雑さのために、ラベル case
内で直接は不正です。A using declaration
is illegal directly inside a case
label due to complications around its actual lifetime. 考え得る解決策の 1 つは、単に同じ場所にある と同 out var
じ有効期間を提供する方法です。One potential solution is to simply give it the same lifetime as an out var
in the same location. これは、機能の実装の複雑さが増し、回避策 (ラベルにブロックを追加するだけで済みます) がこのルートの作成には合わないと見なされました case
。It was deemed the extra complexity to the feature implementation and the ease of the work around (just add a block to the case
label) didn't justify taking this route.
将来の展開Future Expansions
固定ローカルfixed locals
fixed
ステートメントには、 using
ローカル変数を持つことができるステートメントのすべてのプロパティがあり using
ます。A fixed
statement has all of the properties of using
statements that motivated the ability to have using
locals. この機能をローカル変数に拡張することも考慮する必要があり fixed
ます。Consideration should be given to extending this feature to fixed
locals as well. 有効期間と順序の規則は、とでも同様に適用する必要があり using
fixed
ます。The lifetime and ordering rules should apply equally well for using
and fixed
here.