ホームページ  >  記事  >  バックエンド開発  >  C# 2.0仕様書(匿名方式) (2)

C# 2.0仕様書(匿名方式) (2)

黄舟
黄舟オリジナル
2017-01-03 11:58:171304ブラウズ

21.7 デリゲート インスタンスの等価性

以下のルールは、等価演算子 (§7.9.8) および匿名メソッド デリゲート インスタンスの object.Equals メソッドによって生成される結果に適用されます。
l デリゲート インスタンスが、キャプチャされた外部変数の同じセットを使用して、意味的に同一の匿名メソッド式を評価した結果として得られる場合、それらは等しい (ただし、等しい必要はない) と言われます。
l デリゲート インスタンスが、異なるセマンティクスを持つ匿名メソッド式、またはキャプチャされた外部変数の異なるセットで表される場合、それらは決して等しくありません。

21.8 明示的な割り当て

匿名メソッドのパラメータの明示的な割り当てステータスは、名前付きメソッドの明示的な割り当てステータスと同じです。つまり、参照パラメータと値パラメータには明示的に初期値が割り当てられますが、出力パラメータには初期値を割り当てる必要はありません。また、匿名メソッドが正常に戻る前に、出力パラメータを明示的に割り当てる必要があります (§5.1.6)。
匿名メソッド式のプログラムブロックに制御が移った場合、外部変数vの明示的な代入状態は、無名メソッド式前のvの明示的な代入状態と同じになります。つまり、外部変数への明示的な代入は、匿名メソッド式コンテキストから継承されます。匿名メソッド ブロック内では、明示的な代入は通常のブロック内と同様に推定されます (§5.3.3)。
匿名メソッド式の後の変数 v の明示的な代入状態は、匿名メソッド式の前の明示的な代入状態と同じです。

たとえば、

delegate bool Filter(int i);
void F() {
int max;
// 错误,max没有明确赋值
Filter f = delegate(int n) { return n < max; }
max = 5;
DoWork(f);
}

は、匿名メソッドが宣言されている場所にmaxが明示的に割り当てられていないため、コンパイル時エラーを生成します。例

delegate void D();
void F() {
int n;
D d = delegate { n = 1; };
d();
//错误,n没有明确赋值
Console.WriteLine(n);
}

もコンパイル時エラーを生成します。これは、匿名メソッド内の n の代入は、匿名メソッド外の n の明示的な代入状態に影響を与えないためです。

21.9 メソッド グループの変換

§21.3 で説明した暗黙的な匿名メソッド変換と同様に、メソッド グループ (§7.1) から互換性のあるデリゲート型への暗黙的な変換もあります。
特定のメソッド グループ E とデリゲート型 D について、new D(E) 形式のデリゲート作成式が許可されている場合 (§7.5.10.3 および §20.9.6)、E から D への暗黙的な変換が行われます。変換の結果は、新しい D(E) とまったく同じになります。
次の例

using System;
using System.Windows.Forms;
class AlertDialog
{
Label message = new Label();
Button okButton = new Button();
Button cancelButton = new Button();`
public AlertDialog() {
okButton.Click += new EventHandler(OkClick);
cancelButton.Click += new EventHandler(CancelClick);
...
}
void OkClick(object sender, EventArgs e) {
...
}
void CancelClick(object sender, EventArgs e) {
...
}
}

では、コンストラクターは new を使用して 2 つのデリゲート インスタンスを作成します。暗黙的なメソッド グループ変換を使用すると、これを

public AlertDialog() {
okButton.Click += OkClick;
cancelButton.Click += CancelClick;
...
}

に簡素化できます。他のすべての暗黙的変換および明示的変換と同様に、変換演算子を使用して特定の変換を明示的に実行できます。これを行うには、代わりに例

object obj = new EventHandler(myDialog.OkClick);

を次のように記述できます。

object obj = (EventHandler)myDialog.OkClick;

メソッド合成の匿名メソッド式はオーバーロードの解決に影響を与える可能性がありますが、型推論には関与しません。詳細については、§20.6.4 を参照してください。

21.10 実装例

このセクションでは、標準 C# コンポーネントの形式での匿名メソッドの可能な実装について説明します。ここで説明する実装は、Microsoft C# コンパイラで採用されているのと同じ原則に基づいていますが、これは決して必須ではなく、また唯一可能な実装でもありません。
このセクションの後半でいくつかのサンプル コードを示します。これらには、異なる特性を持つ匿名メソッドが含まれています。各例では、独自の標準 C# 構造を使用したコードの対応する変換を提供します。これらの例では、識別子 D は次のデリゲート型を表すと想定されています。

public delegate void D();

匿名メソッドの最も単純な形式は、外部変数をキャプチャしないものです。

class Test
{
static void F() {
D d = delegate { Console.WriteLine("test"); };
}
}

このコードは、コンパイラによって生成された静的メソッドを参照するデリゲート インスタンスに変換でき、匿名メソッドのコードは静的メソッドに配置されます。 ,

class Test
{
static void F() {
D d = new D(__Method1);
}
static void __Method1() {
Console.WriteLine("test");
}
}

以下の例では、匿名メソッドは this のインスタンス メンバーを参照しています。

class Test
{
int x;
void F() {
D d = delegate { Console.WriteLine(x); };
}
}

これは、匿名メソッド コードを含むコンパイラによって生成されたインスタンス メソッドに変換できます。

class Test
{
int x;
void F() {
D d = new D(__Method1);
}
void __Method1() {
Console.WriteLine(x);
}
}

この例では、匿名メソッドがローカル変数をキャプチャします。


class Test
{
void F() {
int y = 123;
D d = delegate { Console.WriteLine(y); };
}
}

该局部变量的生存期现在至少必须延长到匿名方法委托的生存期为止。这可以通过将局部变量“提升(lifting)”为编译器生成的(compiler-generated)类的字段来完成。局部变量的实例化对应于创建一个编译器生成的类的实例,而访问局部变量将对应于访问编译器生成的类实例的一个字段。并且,匿名方法将成为编译器生成类的实例方法。

class Test
{
void F() {
__locals1 = new __Locals1();
__locals1.y = 123;
D d = new D(__locals1.__Method1);
}
class __Locals1
{
public int y;
public void __Method1() {
Console.WriteLine(y);
}
}
}

最后,如下匿名方法将捕获this,以及具有不同生存期的两个局部变量。

class Test
{
int x;
void F() {
int y = 123;
for (int i = 0; i < 10; i++) {
int z = i * 2;
D d = delegate { Console.WriteLine(x + y + z); };
}
}
}

在这里,编译器将为每个语句块生成类,在这些语句块中局部变量将被捕获,而在不同块中的局部变量将会有独立的生存期。

__Locals2的实例,编译器为内部语句块生成的类,包含局部变量z和引用__Locals1实例的字段。__Locals1的实例,编译器为外部语句块生成的类,包含局部变量y和引用封闭函数成员的this的字段。通过这些数据结构,你可以通过__Locals2的一个实例到达所有被捕获的局部变量,并且匿名方法的代码可以作为那个类的实例方法而实现。

class Test
{
void F() {
__locals1 = new __Locals1();
__locals1.__this = this;
__locals1.y = 123;
for (int i = 0; i < 10; i++) {
__locals2 = new __Locals2();
__locals2.__locals1 = __locals1;
__locals2.z = i * 2;
D d = new D(__locals2.__Method1);
}
}
class __Locals1
{
public Test __this;
public int y;
}
class __Locals2
{
public __Locals1 __locals1;
public int z;
public void __Method1() {
Console.WriteLine(__locals1.__this.x + __locals1.y + z);
}
}
}

(匿名方法完)


以上就是C# 2.0 Specification(匿名方法)(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。