Question

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
}

Ce qui précède semble bien fonctionner, bien que ReSharper se plaint du fait qu’il s’agit d’un "accès à une fermeture modifiée". Quelqu'un peut-il nous éclairer?

(suite de ici )

Était-ce utile?

La solution

Dans ce cas, ça va, puisque vous exécutez le délégué dans la boucle.

Si vous enregistrez et utilisez le délégué plus tard, vous constaterez que tous les délégués lèveront des exceptions lors de la tentative d'accès aux fichiers [i] - ils capturent la variable . i plutôt que sa valeur lors de la création des délégués.

En bref, il faut en prendre conscience comme un piège potentiel , mais dans ce cas, cela ne vous fait pas de mal.

Voir le bas de cette page pour un exemple plus complexe où les résultats sont contre-intuitifs.

Autres conseils

Je sais que c’est une vieille question, mais j’ai récemment étudié les fermetures d’opérations et j’ai pensé qu’un échantillon de code pourrait être utile. En coulisse, le compilateur génère une classe qui représente une clôture lexicale pour votre appel de fonction. Cela ressemble probablement à quelque chose comme:

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

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

Comme mentionné ci-dessus, votre fonction fonctionne car les prédicats sont invoqués immédiatement après la création. Le compilateur générera quelque chose comme:

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;
}

D’autre part, si vous deviez stocker puis invoquer plus tard les prédicats, vous verriez que chaque appel aux prédicats appellerait réellement la même méthode sur la même instance de la classe de fermeture et utiliserait donc le même valeur pour i.

" fichiers " est une variable externe capturée , car elle a été capturée par la fonction de délégation anonyme. Sa durée de vie est prolongée par la fonction de délégué anonyme.

  

Variables externes capturées   Lorsqu'une variable externe est référencée par une fonction anonyme, on dit que la variable externe a été capturée par la fonction anonyme. En règle générale, la durée de vie d'une variable locale est limitée à l'exécution du bloc ou de l'instruction auquel elle est associée (variables locales). Cependant, la durée de vie d’une variable externe capturée est prolongée au moins jusqu’à ce que le délégué ou l’arbre d’expression créé à partir de la fonction anonyme soit éligible pour le garbage collection.

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

  

Lorsqu'une variable locale ou un paramètre de valeur est capturé par une fonction anonyme, la variable ou le paramètre local n'est plus considéré comme une variable fixe (variables fixes et mobiles), mais plutôt comme une variable mobile. Ainsi, tout code non sécurisé prenant l'adresse d'une variable externe capturée doit d'abord utiliser l'instruction fixed pour corriger la variable.   Notez que contrairement à une variable non capturée, une variable locale capturée peut être simultanément exposée à plusieurs threads d'exécution.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top