7

バックグラウンド

実行時に C# コードをコンパイルすることはできますが、生成されたコードを現在のスコープに含めて実行することはできません。代わりに、すべての変数を明示的なパラメーターとして渡す必要があります。

Python のような動的プログラミング言語と比較すると、eval(この例のように) の完全な動作を真に再現することはできません。

x = 42
print(eval("x + 1")) # Prints 43

質問

したがって、私の質問は (実際に役立つかどうかに関係なく ;)) 、リフレクションを使用して .NET で動的スコープを模倣できるかどうかです。

.NET はDiagnostics.StackTrace呼び出しメソッドを検査できるクラスを提供するので、この質問は次のように要約されます: (どのように) 呼び出しメソッドのローカルに確実にアクセスできますか?

スタック トレースは、メモリ オフセットを計算するのに十分な情報を提供してくれますか、それともマネージ コードではそのようなことは禁止されていますか?

そのようなコードは何とか可能ですか?

void Foo() {
   int x = 42;
   Console.WriteLine(Bar());
}

int Bar() {
   return (int)(DynamicScope.Resolve("x")); // Will access Foo's x = 42
}
4

2 に答える 2

8

したがって、私の質問は、リフレクションを使用して .NET で動的スコープを模倣できるかどうかです。

リフレクションを使用すると、アセンブリのメタデータで表現される項目を実行時に操作できます。

ローカル変数は、アセンブリのメタデータで表現される項目ではありません。

したがって、あなたの質問に対する答えは「いいえ」です。

(どのように) 呼び出しメソッドのローカルに確実にアクセスできますか?

呼び出しメソッドのローカルにアクセスするデバイスは「デバッガ」と呼ばれます。したがって、あなたの質問に対する答えは、「デバッガーを自分で作成する」です。

デバッガーは、コードが最適化されたワールド内のローカルに確実にアクセスしないことに注意してください。ローカルは最適化されず、ジッターは 2 つの異なるローカルに同じレジスタを使用するコードを生成でき、テール コール中にスタック フレームを再利用できます。そしてもちろん、各スタック フレームの場所に関連付けられている名前をデバッガーに伝える PDB ファイルが必要です。

メソッドで行う必要があるのは、カスタム デバッガーを新しいプロセスとして起動し、デバッガーがメッセージを送信するのを待つことです。デバッガーは、元のプロセスのスレッドを一時停止し、スタック フレームの問い合わせを行ってから、プロセスのスレッドを再開します。次に、発見した情報を含むメッセージをデバッグ対象に送信します。デバッグ対象はメッセージを待っている待機状態でそこに座っているため、その後、業務を再開します。

インプロセスの「評価」機能が必要な場合は、そのような目的のために設計された言語である JScript.NET を検討してください。

于 2010-02-14T17:28:20.133 に答える
5

これは不可能です。コンパイルされた.NETコード(中間言語)では、変数はスタック上のインデックスとして単純に表されます。たとえば、変数の値をロードする命令は、パラメータとして値のみを取りldlocますunsigned int16。デバッグモードでコンパイルされたアプリケーションに対してこれを行う方法はいくつかあるかもしれませんが(結局のところ、アプリケーションをデバッグするとき、Visual Studioはそれを行います)、一般的には機能しません。

Phalanger(私が部分的に関わっている.NET用のPHPコンパイラ)では、PHP言語が(動的スコープevalを提供する必要はありませんが、名前で変数にアクセスする必要があります)、これを何らかの方法で解決する必要がありました。したがって、Phalangerは、関数にの使用が含まれているかどうかを検出し、含まれている場合は、すべての変数をに格納し、それを関数に渡します(変数を名前で読み取ることができるようにするため)。私はこれがこれを行う唯一の方法だと思います...evalDictionary<string, object>eval

于 2010-02-14T16:12:44.867 に答える