Frage

string [] files = new string[2];
files[0] = "ThinkFarAhead.Example.Settings.Configuration_Local.xml";
files[1] = "ThinkFarAhead.Example.Settings.Configuration_Global.xml";

//Resharper complains this is an "access to modified closure"
for (int i = 0; i < files.Length; i++ )
{
    // Resharper disable AccessToModifiedClosure
    if(Array.Exists(Assembly.GetExecutingAssembly().GetManifestResourceNames(),
    delegate(string name) { return name.Equals(files[i]); }))
         return Assembly.GetExecutingAssembly().GetManifestResourceStream(files[i]);
    // ReSharper restore AccessToModifiedClosure
}

Das scheint oben gut zu funktionieren, obwohl ReSharper beschwert sich, dass diese „den Zugang zu modifizierten Schließung“ ist. Kann man Licht in diese?

(dieses Thema fortgesetzt hier )

War es hilfreich?

Lösung

In diesem Fall ist es in Ordnung, da Sie tatsächlich die Ausführung der Delegierten in die Schleife.

Wenn Sie die Delegierten sparen und deren Verwendung später jedoch, würden Sie feststellen, dass alle Delegierten Ausnahmen werfen würde, wenn sie versuchen auf Dateien zuzugreifen [i] - sie erfassen die Variable i statt dessen Wert zum Zeitpunkt der Delegierten Schöpfung.

Kurz gesagt, es ist etwas bewusst zu sein, wie ein Potential trap, aber in diesem Fall ist es nicht dich verletzen.

Sehen Sie die unten auf dieser Seite für ein komplexeres Beispiel, in dem die Ergebnisse sind nicht eingängig.

Andere Tipps

Ich weiß, dass dies eine alte Frage, aber ich habe vor kurzen Schließungen studiert und dachte, ein Codebeispiel nützlich sein könnte. Hinter den Kulissen, erzeugen die Compiler eine Klasse, die eine lexikalische Verschluss für Ihren Funktionsaufruf darstellt. Es sieht wohl so etwas wie:

private sealed class Closure
{
    public string[] files;
    public int i;

    public bool YourAnonymousMethod(string name)
    {
        return name.Equals(this.files[this.i]);
    }
}

Wie bereits erwähnt, Ihre Funktion funktioniert, weil die Prädikate unmittelbar nach der Erstellung aufgerufen werden. Der Compiler wird so etwas wie erzeugen:

private string Works()
{
    var closure = new Closure();

    closure.files = new string[3];
    closure.files[0] = "notfoo";
    closure.files[1] = "bar";
    closure.files[2] = "notbaz";

    var arrayToSearch = new string[] { "foo", "bar", "baz" };

    //this works, because the predicates are being executed during the loop
    for (closure.i = 0; closure.i < closure.files.Length; closure.i++)
    {
        if (Array.Exists(arrayToSearch, closure.YourAnonymousMethod))
            return closure.files[closure.i];
    }

    return null;
}

Auf der anderen Seite, wenn Sie speichern waren und dann rufen Sie später die Prädikate, würden Sie sehen, dass jeder einzelne Anruf zu den Prädikaten wirklich die gleiche Methode auf der gleichen Instanz der Schließung Klasse würde anrufen und damit das würde verwenden derselbe Wert für i.

„Dateien“ ist ein erfasst äußere Variable , da sie von der anonymen Delegatfunktion erfasst wurde. Seine Lebensdauer wird durch die anonyme Delegatfunktion erweitert.

  

Captured äußere Variablen   Wenn eine äußere Variable durch eine anonyme Funktion Bezug genommen wird, wird die äußere Variable gesagt, durch die anonyme Funktion aufgenommen wurden. Normalerweise wird die Lebensdauer einer lokalen Variablen auf die Ausführung des Blocks oder Aussage beschränkt, mit denen sie verbunden ist (lokale Variablen). Jedoch ist die Lebensdauer eines erfassten äußeren variable mindestens verlängert, bis die Delegierten oder Ausdrucksbaums aus der anonymen Funktion erstellt für Speicherbereinigungsvorgang ausgewählt wird.

https: / /docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#outer-variables

  

Wenn eine lokale Variable oder ein Wertparameter von einer anonymen Funktion, die lokale Variable oder einem Parameter erfaßt wird, nicht mehr als eine feste Größe (feste und bewegliche Variablen) sein, sondern wird stattdessen eine bewegliche Variable angesehen werden. Somit kann jede unsicheren Code, der die Adresse eines erfassten äußeren Variable nimmt müssen zuerst die feste Anweisung verwenden, um die Variable zu fixieren.   Man beachte, dass im Gegensatz zu einer nicht erfaßten Variable, ein aufgenommenes lokale Variable kann gleichzeitig auf mehrere Ausführungs-Threads ausgesetzt werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top