2009-02-24 3 views
11

Also, jedes Mal, wenn ich einen Lambda-Ausdruck oder eine anonyme Methode innerhalb einer Methode geschrieben habe, die ich nicht richtig richtig habe, bin ich gezwungen, die gesamte Anwendung oder Unit-Test-Framework neu zu kompilieren und neu zu starten, um es zu beheben. Das ist sehr ärgerlich, und am Ende verschwende ich mehr Zeit, als ich mit diesen Konstrukten gespart habe. Es ist so schlimm, dass ich versuche, von ihnen wegzubleiben, wenn ich kann, obwohl Linq und Lambdas zu meinen Lieblings-C# -Features gehören.Warum kann ich eine Methode, die eine anonyme Methode im Debugger enthält, nicht bearbeiten?

Ich denke, es gibt einen guten technischen Grund dafür, warum es so ist, und vielleicht weiß jemand? Weiß jemand außerdem, ob es in VS2010 behoben wird?

Danke.

Antwort

14

Ja, es gibt einen sehr guten Grund, warum Sie das nicht tun können. Der einfache Grund ist Kosten. Die Kosten für die Aktivierung dieser Funktion in C# (oder VB) sind extrem hoch.

Das Bearbeiten einer Lambda-Funktion ist ein spezieller Fall einer Klasse von ENC-Problemen, die mit der aktuellen ENC (Edit'n'Continue) -Architektur sehr schwer zu lösen sind. Das heißt, es ist sehr schwierig, jede Methode zu ENC, die, wo die ENC hat eine der folgenden Möglichkeiten: -

  1. generiert Metadaten in Form einer Klasse
  2. Edits oder erzeugt eine generische Methode

Die Das erste Problem ist mehr eine logische Einschränkung, aber es stößt auch in ein paar Einschränkungen in der ENC-Architektur. Das Problem ist nämlich, die erste Klasse zu generieren ist nicht besonders schwierig. Was störend ist, erzeugt die Klasse nach der zweiten Bearbeitung. Die ENC-Engine muss beginnen, die Symboltabelle nicht nur für den Live-Code, sondern auch für die generierten Klassen zu verfolgen. Normalerweise ist das nicht so schlimm, aber dies wird zunehmend schwierig, wenn die Form einer generierten Klasse auf dem Kontext basiert, in dem sie verwendet wird (wie es bei Lambda aufgrund von Schließungen der Fall ist). Noch wichtiger: Wie lösen Sie die Unterschiede zu Instanzen der Klassen, die bereits in diesem Prozess existieren?

Das zweite Problem ist eine strenge Begrenzung in der CLR ENC-Architektur. Es gibt nichts, was C# (oder VB) tun könnte, um dies zu umgehen.

Lambdas schlug leider beide dieser Probleme tot auf. Die kurze Version ist, dass ENC'ing ein Lambda viele Mutationen auf bestehenden Klassen beinhaltet (die möglicherweise von anderen ENCs erzeugt wurden oder nicht). Das große Problem besteht darin, die Unterschiede zwischen dem neuen Code und den vorhandenen Closure-Instanzen, die im aktuellen Prozessbereich vorhanden sind, zu lösen. Außerdem tendieren Lambdas dazu, Generika viel mehr als andere Codes zu verwenden und treffen auf Nummer 2.

Die Details sind ziemlich haarig und ein bisschen zu kompliziert für eine normale SO-Antwort. Ich habe überlegt, einen längeren Blogeintrag zu diesem Thema zu schreiben. Wenn ich dazu komme, werde ich es in diese spezielle Antwort zurückverwandeln.

+1

Direkt aus dem Maul des Pferdes. +1 –

+0

@Jon Wir hatten viele interne Treffen zu diesem Thema und ich musste diese Präsentation viele Male geben. Ich muss wirklich einen vollständigen doc zu diesem Thema schreiben. Bloggen scheint ein guter Ort dafür zu sein. Es gibt Hoffnung, dass dies in einer zukünftigen Version von VS gelöst wird. – JaredPar

+1

Bitte schreibe einen Blog darüber. – Eyvind

0

Das Neustarten eines Komponententests sollte einige Sekunden dauern. Ich habe das "Edit and Continue" -Modell nie gemocht, um ehrlich zu sein - Sie sollten IMO immer von Grund auf neu starten, nur für den Fall, dass die Änderung in der Mitte der Ausführung den Code beeinflusst hätte, der früher ausgeführt wurde. In Anbetracht dessen ist es besser, Komponententests zu verwenden, die mit einer sehr kurzen Bearbeitungszeit ausgeführt werden können. Wenn Ihre individuellen Unit-Tests eine unerträgliche Zeit brauchen, um damit zu beginnen, sollten Sie sich die Adressierung ansehen.

EDIT: Warum es nicht funktioniert - Sie können feststellen, dass es für einige Lambdas funktioniert, aber nicht für andere. Lambda-Ausdrücke, die keine Variablen (einschließlich this) erfassen, werden in einer privaten statischen Variablen zwischengespeichert, so dass immer nur eine Instanz des Delegaten erstellt wird. Das Ändern des Codes bedeutet, dass diese Variable reinitialisiert wird, was interessante Nebenwirkungen haben könnte, die ich vermute.

+0

Ich stimme zu ...., aber es ist keine Antwort auf die Frage. –

+0

Ich wusste, dass du die Antwort kennst ;-) –

+0

IMO die Antwort auf viele Fragen ist es, zu vermeiden, in die schmerzhafte Situation zu kommen. –

1

Gemäß einer Liste von Supported Code Changes können Sie keine Felder zu vorhandenen Typen hinzufügen. Anonyme Methoden werden in merkwürdig benannte Klassen (Art <>_c__DisplayClass1) kompiliert, die genau das sind: Typen. Obwohl Ihre Änderungen an der anonymen Methode möglicherweise nicht die Menge der eingeschlossenen Variablen ändern (das Hinzufügen würde die Felder einer vorhandenen Klasse ändern), ist das der Grund, warum es unmöglich ist, anonyme Methoden zu ändern.

+1

Sie müssen die anonyme Methode selbst nicht ändern, damit sich dieses Problem manifestiert. Es reicht aus, eine Methode _contains_ einer anonymen Methode zu ändern, und es scheint, dass sogar ein einzelner Speicherplatz ausreicht, um sie zu deaktivieren ... – Eyvind

1

Es ist ein bisschen schadet, dass diese Funktion teilweise in VB unterstützt wird, aber nicht in C#: http://msdn.microsoft.com/en-us/library/bb385795.aspx

das gleiche Verhalten in C# Die Umsetzung würde das Schmerzniveau um 80% für Funktionen reduzieren, die Lambda-Ausdrücke enthalten, wo wir weder die Lambda-Ausdrücke noch irgendeinen Ausdruck ändern müssen, der von ihnen abhängt, und wahrscheinlich nicht für einen "Monster-Preis".

Verwandte Themen