6

私は、どの中間言語コードが出力されるかを理解する目的で、 LINQPadのいくつかのC#ステートメントで遊んでいます。

私は最初に次のコードを試しました:

var Container = new {Name = "James"};
Console.WriteLine(Container.Name);

そして、次の6行のILが放出されるのを見ました。

IL_0001:  ldstr       "James"
IL_0006:  newobj      <>f__AnonymousType0<System.String>..ctor
IL_000B:  stloc.0     
IL_000C:  ldloc.0     
IL_000D:  callvirt    <>f__AnonymousType0<System.String>.get_Name
IL_0012:  call        System.Console.WriteLine

これは、私が期待していることであり、set_Nameプロパティがないため、匿名型が読み取り専用/不変である方法を示す非常に優れたデモンストレーションです。

次に、私はステートメントを試しました:

dynamic Container = new System.Dynamic.ExpandoObject();
Container.Name = "James";
Console.WriteLine(Container.Name);

これにより、大量のILが放出されます。ここには貼り付けませんが、このペーストビンにあります。

System.Console.WriteLine動的型とExpandoObjectの管理に関してかなりのオーバーヘッドがあることは理解していますが、この場合の呼び出しが内部反射によって実行されているように見える理由がわかりません。

IL_0072:  ldstr       "WriteLine"
....
IL_00BF:  ldtoken     System.Console

コードの最初のセグメントでは、プロパティが取得されて保存された後、を呼び出したのは1行のILステートメントでしたSystem.Console.WriteLine

では、なぜdynamicタイプを使用した呼び出しにこのすべての追加が必要なのですか?

4

2 に答える 2

7

変数がdynamic存在するため、コンパイル時に、どのオーバーロードをWriteLine呼び出す必要があるかを知る方法はありません。dynamicオブジェクトの実際のタイプがわかるのは、実行時までではありません。動作方法のため、コンパイル時にdynamic単に扱われるのではないことが重要です。object力の一部は、実行時に正しい過負荷を決定していることです。

オブジェクトを動的以外のものにキャストし(つまりstring、呼び出した後、ToStringまたはに戻った直後ExpandoObject)、それをに渡すとWriteLine、リフレクション呼び出しがなくなり、コンパイル時に、の適切なオーバーロードが静的に決定されることがわかりますWriteLine

于 2012-09-20T19:55:18.987 に答える
1

何が起こっているのかというと、コンパイラーは「レイトバインド」できるような方法でコードを作成しているということです。遅延バインディングとは、従来のデータ型やオブジェクトのように、コンパイル中にオブジェクトを解決するのではなく、アセンブリが実際にメモリ内にあり実行されている間に、実行時にオブジェクトが解決されることを意味します。

ReflectorまたはdotPeekでコードを見ると、動的オブジェクトが[Dynamic]属性で装飾されていることがわかります。プログラムがメモリ内で実行されている間、この属性で装飾されたオブジェクトに関しては、このオブジェクトへの呼び出しはダイナミックContainer(またはオブジェクトが呼び出されるもの)を介してパイプされます。これContainerは、実行時バインディングを担当するバインダーで初期化されます。それがすべての人がするMicrosoft.CSharp.RuntimeBinderことです。これRuntimeBinderは、後でプロパティやメソッド、または動的なものを呼び出すために使用されます。

これで少し問題が解決することを願っています。私は自分のAndroidで入力しているので、説明は理想的ではないかもしれません。後で片付けます。

于 2012-09-20T20:12:27.823 に答える