web-dev-qa-db-fra.com

Fermetures implicitement capturées, avertissement ReSharper

Je sais normalement ce que «fermeture implicite» signifie, cependant, aujourd’hui, j’ai rencontré la situation suivante:

public static void Foo (Bar bar, Action<int> a, Action<int> b, int c)
{
    bar.RegisterHandler(x => a(c)); // Implicitly captured closure: b
    bar.RegisterHandler(x => b(c)); // Implicitly captured closure: a
}

Pourquoi est-ce que je capture implicitement l'autre action? Si je commente l'une ou l'autre des lignes, l'autre ne me donne pas l'avertissement. Quelqu'un sait quel danger ReSharper m'avertit?

Edit: ReSharper 8.0.1

32
D.R.

Le problème ici est que lorsque vous fermez une variable, ce qui se passe en coulisse est que le compilateur crée un nouveau type non nommé, attribue à ce type un champ d'instance pour chaque variable fermée dans ce bloc , lui donne une méthode pour chaque méthode anonyme dans ce bloc de code, puis passe une instance unique de cet objet autour.

Cela signifie que la durée de vie du premier délégué conserve cet objet de fermeture en vie et qu'il contient une référence à l'objet b, en plus de a, en interne et inversement.

Maintenant, dans votre cas, ce n’est pas un problème, étant donné que Action n’est pas particulièrement gourmand en mémoire, vous pouvez donc le garder en vie un peu plus longtemps.

L’équipe C # aurait pu, en théorie, s’assurer que dans ce cas particulier, un nouveau type non nommé pourrait être créé pour chaque fermeture du même bloc, mais elle a choisi de ne pas le faire car cela aggraverait le cas commun.

35
Servy

Et un avertissement, je devenais folle de ça:

List<List<string>> allowed = AllowedSCACSwaps;
foreach (List<string> c in allowed.Where(c => c.Contains(scac)))
{
    csc = openCycles.FirstOrDefault(icsc => (icsc.CustomerCode == customerCode) && c.Contains(icsc.SCAC));
    if (null != csc)
    {
        return csc;
    }
}

en disant "fermeture implicite pour customerCode"

string cc = customerCode.ToUpperInvariant();
string sc = scac.ToUpperInvariant();    List<List<string>> allowed = AllowedSCACSwaps;
    foreach (List<string> c in allowed.Where(c => c.Contains(sc)))
    {
        csc = openCycles.FirstOrDefault(icsc => (icsc.CustomerCode == cc) && c.Contains(icsc.SCAC));
        if (null != csc)
        {
            return csc;
        }
    }

C'est bien.

Raison je devenais fou?

scac et customerCode sont les deux chaînes passées dans la méthode . Mais même lorsque j'ai remplacé customerCode par cc, je continuais à recevoir le même avertissement.

La fermeture était en fait terminée, mais Resharper l’a mal déclarée.

0
Roger Willcocks

J'ai déjà vu ça cela a à voir avec les variables conservées pendant la durée de vie du lambda, donc si elles sont grandes, cela peut créer une pression sur la mémoire.

0
Allan Elder