Wenn Sie eine Iteratorfunktion in C# schreiben, verwendet die Compiler-Syntax mithilfe der Yield-Syntax Ihre Funktion intern in eine Klasse. Also, wenn ich so etwas schreiben:Suchen des Objektfelds, das einem Referenzparameter in C# entspricht
IEnumerator<int> MyIterator() {
for (int i = 0; i < 10; i++)
yield return i;
}
Hervorrufen MyIterator() erstellt eine Klasse mit einem eigenen Bereich für i, anstatt einen Stapel Variable zu verwenden.
Jetzt für die Frage: Ich möchte einen Weg finden, das Feld zu finden, das verwendet wird, um den Wert von i zu speichern. Der Grund ist ein wenig beteiligt:
Ich verwende Iterator-Funktionen für kooperative Threading. Ich schreibe einfachen Code wie diesen in einen Iterator, um die Ausführung einer Funktion zu unterbrechen, bis ein asynchroner Vorgang abgeschlossen ist.
Future<string> f;
yield return file.readLine(out f);
string line = f.Result;
Wenn diese drei Anweisungen ausgeführt werden, wird die Readline Funktion aufgerufen und speichert eine Zukunft in die ‚f‘ Feld. Die Iterator-Funktion wird dann ausgesetzt und wacht wieder auf, wenn im 'f' Future ein Ergebnis gespeichert wurde, an dem ich das Ergebnis abrufen kann.
Was ich will, tun können, ist dies:
string line;
yield return file.readLine(out line);
Unter normalen Umständen ist dies nicht möglich sein würde, in .NET, da es keine Möglichkeit, dass ein Stapel Variable am Leben zu garantieren bleibt lang genug für mich, um daran schreiben zu können.
Allerdings, ich weiß, dass Iterator-Funktionen alle ihre Locals innerhalb von Feldern speichern, kann ich theoretisch dies tun, indem Sie einen Verweis auf den Iterator (am Leben zu halten) und auf das Feld selbst, so dass, wenn der readLine-Vorgang abgeschlossen ist kann das Ergebnis direkt in das Feld speichern.
Das Problem ist, dass die CLR scheint mir keinen Weg zu geben, dies zu tun.
Wenn ich einen Parameter 'out' oder 'ref' habe, kann ich die unsichere C# oder rohe MSIL verwenden, um diesen Parameter in einen rohen Zeiger, eine Referenz oder eine TypedReference zu konvertieren. Leider ist es nicht legal, einen dieser drei Typen in einem Feld zu speichern - selbst wenn Sie den Compiler dazu bringen, es Ihnen zu überlassen, lässt der Bytecode-Verifizierer den Code nicht ausführen. Dies liegt höchstwahrscheinlich daran, dass das Speichern eines Verweises auf eine Stapelvariable von Natur aus unsicher ist.
Also was ich suche, ist eine Funktion zu schreiben, die einen out/ref-Parameter verwendet, und die Felder des aufrufenden Iterators durchsucht, um ein entsprechendes Feld zu finden. Sobald das Feld vorhanden ist, speichert es einen Verweis auf den Iterator und das Feld in einen Wrappertyp und ordnet dem Wrapper eine asynchrone Operation zu.
Angesichts der Overhead in Laufzeit Reflektion in .NET, vermute ich, dass dies nicht möglich ist, ohne entweder meine Quellcode vorverarbeiten oder meine Assemblys nach der Kompilierung nachbearbeiten.
Allerdings würde ich gerne einige Vorschläge für alternative Lösungen hören. :) Irgendwelche Ideen?
Zukunft im Beispiel mehr oder weniger dient dem Zweck, die Sie beschreiben. Den Wert eines Containers jedes Mal aus der Box zu nehmen, ist ein Problem, also würde ich den Schritt überspringen und direkt in das Feld schreiben, wenn ich kann. Die Semantik des Änderns der Felder des Iterators scheint mir klar zu sein - wenn Sie die generierte IL für einen Iterator betrachten, ist es vollkommen sicher, die Locals zu modifizieren, solange Sie es vernünftig tun. –