これが実装の詳細であることを理解しています。私は実際、その実装の詳細がMicrosoftのCLRにどのように含まれているかに興味があります。
さて、私は大学でCSを勉強していなかったので、私は我慢してください。それで、私はいくつかの基本的な原則を逃したかもしれません。
しかし、現在のCLRに実装されている「スタック」と「ヒープ」についての私の理解は確かだと思います。たとえば、「値型はスタックに格納されます」などの不正確な包括的ステートメントを作成するつもりはありません。ただし、最も一般的なシナリオ(パラメーターとして渡されるか、メソッド内で宣言され、クロージャー内に含まれない値型のプレーンなバニラローカル変数)では、値型変数はスタックに格納されます(ここでもMicrosoftのCLRに格納されます)。
私が確信していないのは、ref
値型パラメーターがどこから来るのかということだと思います。
もともと私が考えていたのは、コールスタックが次のようになっている場合(左=下):
A() -> B() -> C()
...その後、 Aのスコープ内で宣言され、ref
パラメーターとしてBに渡されたローカル変数は、引き続きスタックに格納できますか?Bは、そのローカル変数がAのフレーム内に格納されたメモリ位置を必要とするだけです(それが正しい用語でない場合はご容赦ください。とにかく、私が何を意味するかは明らかだと思います)。
しかし、私がこれを行うことができると思ったとき、これは厳密には真実ではないことに気づきました。
delegate void RefAction<T>(ref T arg);
void A()
{
int x = 100;
RefAction<int> b = B;
// This is a non-blocking call; A will return immediately
// after this.
b.BeginInvoke(ref x, C, null);
}
void B(ref int arg)
{
// Putting a sleep here to ensure that A has exited by the time
// the next line gets executed.
Thread.Sleep(1000);
// Where is arg stored right now? The "x" variable
// from the "A" method should be out of scope... but its value
// must somehow be known here for this code to make any sense.
arg += 1;
}
void C(IAsyncResult result)
{
var asyncResult = (AsyncResult)result;
var action = (RefAction<int>)asyncResult.AsyncDelegate;
int output = 0;
// This variable originally came from A... but then
// A returned, it got updated by B, and now it's still here.
action.EndInvoke(ref output, result);
// ...and this prints "101" as expected (?).
Console.WriteLine(output);
}
したがって、上記の例では、x
(Aのスコープ内で)どこに保存されていますか?そして、これはどのように機能しますか?箱入りですか?そうでない場合、値型であるにもかかわらず、ガベージコレクションの対象になりますか?または、メモリをすぐに回収できますか?
長い質問をお詫び申し上げます。しかし、答えが非常に単純であっても、これは、将来同じことを考えている他の人にとって有益なものになるかもしれません。