2009-10-23 10 views
13

Je ne comprends toujours pas ce que fermeture est donc j'ai posté ces deux exemples et je veux savoir si ces exemples sont à la fois des fermetures ou non?Ces exemples sont-ils des fermetures C#?

Exemple A:

List<DirectoryInfo> subFolders = new List<DirectoryInfo>(); 

Action<string> FilterSubFoldersStartA = 
    s => subFolders. 
     AddRange((new DirectoryInfo(s)).GetDirectories(). 
     Where(d => d.Name.StartsWith("A"))); 

FilterSubFoldersStartA(@"c:\tempa"); 
FilterSubFoldersStartA(@"c:\tempb"); 

Exemple B:

List<DirectoryInfo> subFolders = new List<DirectoryInfo>(); 

string filter = "A"; 

Action<string> FilterSubFoldersStartGen = 
    s => subFolders. 
     AddRange((new DirectoryInfo(s)).GetDirectories(). 
     Where(d => d.Name.StartsWith(filter))); 

FilterSubFoldersStartGen(@"c:\tempa"); 

filter = "B"; 

FilterSubFoldersStartGen(@"c:\tempb"); 

Répondre

6

Oui, une fermeture est rien de plus qu'une fonction "sauvegarde" certaines variables de l'environnement dans lequel il est défini. Ainsi, dans vos deux exemples, l'action définie enregistre la liste nommée subFolders, qui peut être référencée par les fonctions même après que la variable locale est hors de portée. La variable filter dans le deuxième exemple est également enregistrée par la fonction définie.

Une définition plus précise here

9

Votre deuxième exemple utilise des fermetures (vous pouvez techniquement dire que le compilateur calcule une fermeture dans les deux cas, mais vous ne faites pas usage dans le premier cas).

Une fermeture est simplement "toutes les variables visibles pour cette fonction". Ni plus ni moins. Et évidemment, dans les deux cas, ces variables existent et sont déterminées par le compilateur. Mais ce que nous entendons habituellement par "utiliser des fermetures", c'est que les expressions lambda peuvent utiliser toutes les variables locales visibles à l'endroit où elles sont déclarées. Ils font tous partie de sa fermeture.

Dans votre cas, d est simplement le paramètre de la fonction lambda, et puisque c'est tout ce que vous utilisez dans le premier cas, vous ne profitez pas vraiment des fermetures.

Dans le second cas, filter n'est pas défini dans l'expression lambda, ce n'est pas un paramètre ou quoi que ce soit. C'est une variable locale qui est juste visible à l'endroit où le lambda est déclaré. Il fait donc partie de la fermeture du lambda, ce qui permet de le référencer dans le corps du lambda.

Modifier
Comme indiqué dans les commentaires, je ne l'ai pas lu votre code de trop près. J'ai seulement remarqué la deuxième expression lambda dans chaque exemple. Le premier lambda utilise des fermetures (il se ferme sur subFolders dans les deux cas.)

+2

Le premier exemple se ferme sur 'subFolders', donc c'est aussi une fermeture. –

+0

Ah oui, je n'ai même pas remarqué le premier lambda. Je viens de voir le 'd => ...' un. Tu as raison. Le premier se referme sur 'subFolders', et dans le second cas, le second lambda se referme sur' filter'. – jalf

0

Les deux exemples ont des fermetures. Dans "A" la méthode anonyme capture les sous-dossiers variables locaux. Dans "B" méthode anonyme capture les variables locales sous-dossiers et filtre. Jetez aussi un coup d'oeil here.

P.S. Notez également que vous utilisez réellement la fermeture dans "A" parce que vous utilisez la variable subFolders.

0

Voici un exemple de http://www.agileatwork.com/a-proper-closure-in-csharp/ de quelque chose qui pourrait vous sembler un peu plus familier si vous êtes à l'aise avec JavaScript. Une fermeture est créée autour de la variable tax afin que le calcul ne soit effectué qu'une seule fois. Ce n'est pas vraiment facile pour les yeux, mais c'est cool que vous puissiez faire ce genre de chose en C#.

public class Order 
{ 
    public Order(ITaxCalculator taxCalculator) 
    { 
     CalculateTax = new Func<Func<decimal>>(() => 
     { 
      decimal? tax = null; 
      return() => 
      { 
       if (!tax.HasValue) 
       { 
        tax = taxCalculator.Calculate(this); 
       } 
       return tax.Value; 
      }; 
     })(); 
    } 

    public Func<decimal> CalculateTax { get; set; } 

    ... 
}