Ich habe folgenden Code:
public double CalculateDailyProjectPullForceMax(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pull Force Max...");
var pullForceList = start == null
? _pullForce.Where((t, i) => _date[i] == date).ToList() // implicitly captured closure: end, start
: _pullForce.Where(
(t, i) => _date[i] == date && DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();
_pullForceDailyMax = Math.Round(pullForceList.Max(), 2, MidpointRounding.AwayFromZero);
return _pullForceDailyMax;
}
Jetzt habe ich einen Kommentar zu der Zeile hinzugefügt, in der ReSharper eine Änderung vorschlägt. Was bedeutet das oder warum muss es geändert werden?implicitly captured closure: end, start
Antworten:
Die Warnung sagt Ihnen, dass die Variablen
end
undstart
am Leben bleiben, da alle Lambdas in dieser Methode am Leben bleiben.Schauen Sie sich das kurze Beispiel an
Beim ersten Lambda wird die Warnung "Implizit erfasste Schließung: g" angezeigt. Es sagt mir, dass
g
kein Müll gesammelt werden kann, solange das erste Lambda verwendet wird.Der Compiler generiert eine Klasse für beide Lambda-Ausdrücke und fügt alle Variablen in diese Klasse ein, die in den Lambda-Ausdrücken verwendet werden.
Also in meinem Beispiel
g
undi
werden in der gleichen Klasse für die Ausführung meiner Delegierten gehalten. Wenng
es sich um ein schweres Objekt handelt, bei dem viele Ressourcen zurückbleiben, konnte der Garbage Collector es nicht zurückfordern, da die Referenz in dieser Klasse noch aktiv ist, solange einer der Lambda-Ausdrücke verwendet wird. Dies ist also ein potenzieller Speicherverlust, und das ist der Grund für die R # -Warnung.@splintor Wie in C # werden die anonymen Methoden immer in einer Klasse pro Methode gespeichert. Es gibt zwei Möglichkeiten, dies zu vermeiden:
Verwenden Sie eine Instanzmethode anstelle einer anonymen.
Teilen Sie die Erstellung der Lambda-Ausdrücke in zwei Methoden auf.
quelle
Random
Instanz zu enthalten.Einverstanden mit Peter Mortensen.
Der C # -Compiler generiert nur einen Typ, der alle Variablen für alle Lambda-Ausdrücke in einer Methode kapselt.
Zum Beispiel angesichts des Quellcodes:
Der Compiler generiert einen Typ, der wie folgt aussieht:
Und die
Capture
Methode ist kompiliert als:Obwohl das zweite Lambda nicht verwendet wird
x
, kann es nicht als Müll gesammelt werden, dax
es als Eigenschaft der generierten Klasse kompiliert wird, die im Lambda verwendet wird.quelle
Die Warnung ist gültig und wird in Methoden mit mehr als einem Lambda angezeigt. Sie erfassen unterschiedliche Werte .
Wenn eine Methode aufgerufen wird, die Lambdas enthält, wird ein vom Compiler generiertes Objekt instanziiert mit:
Als Beispiel:
Untersuchen Sie den generierten Code für diese Klasse (ein wenig aufgeräumt):
Beachten Sie die Instanz der
LambdaHelper
erstellten Speicher sowohlp1
als auchp2
.Stell dir das vor:
callable1
hält einen langlebigen Verweis auf seine Argumentation,helper.Lambda1
callable2
behält keinen Verweis auf sein Argument,helper.Lambda2
In dieser Situation verweist der Verweis auf
helper.Lambda1
auch indirekt auf die Zeichenfolge inp2
, und dies bedeutet, dass der Garbage Collector die Zuordnung nicht aufheben kann. Im schlimmsten Fall handelt es sich um ein Speicher- / Ressourcenleck. Alternativ können Objekte länger am Leben bleiben als sonst erforderlich, was sich auf die GC auswirken kann, wenn sie von gen0 zu gen1 befördert werden.quelle
p1
voncallable2
so herausnehmen würden:callable2(() => { p2.ToString(); });
- Würde dies immer noch nicht das gleiche Problem verursachen (Garbage Collector kann es nicht freigeben),LambdaHelper
das nochp1
und enthältp2
?LambdaHelper
oben) für alle Lambdas innerhalb der übergeordneten Methode. Selbst wenncallable2
es nicht verwendetp1
würde, würde es dasselbe Erfassungsobjekt wie verwendencallable1
, und dieses Erfassungsobjekt würde sowohl aufp1
als auch verweisenp2
. Beachten Sie, dass dies nur für Referenztypen wirklich wichtig ist undp1
in diesem Beispiel ein Werttyp ist.Bei Linq to Sql-Abfragen wird möglicherweise diese Warnung angezeigt. Der Gültigkeitsbereich des Lambda kann die Methode überleben, da die Abfrage häufig aktualisiert wird, nachdem die Methode außerhalb des Gültigkeitsbereichs liegt. Abhängig von Ihrer Situation möchten Sie möglicherweise die Ergebnisse (dh über .ToList ()) innerhalb der Methode aktualisieren, um eine GC für die im L2S-Lambda erfassten Instanzvariablen der Methode zu ermöglichen.
quelle
Sie können immer mit Gründen für R # -Vorschläge herausfinden, indem Sie einfach auf die unten gezeigten Hinweise klicken:
Dieser Hinweis leitet Sie hierher .
quelle