2009-10-23 11 views
13

Ancora non capisco cosa sia una chiusura così ho postato questi due esempi e voglio sapere se questi esempi sono entrambi chiusi o no?Questi esempi sono le chiusure C#?

Esempio 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"); 

Esempio 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"); 

risposta

6

Sì, una chiusura non è altro che una funzione che "salva" alcune variabili dall'ambiente in cui si è definito. Quindi, in entrambi i vostri esempi, l'azione definita salva la lista denominata subFolders, che può essere referenziata dalle funzioni anche dopo che la variabile locale è fuori ambito. La variabile filter nel secondo esempio viene salvata anche dalla funzione definita.

Una definizione più precisa here

9

tuo secondo esempio fa uso di chiusure (tecnicamente si potrebbe dire che il compilatore calcola una chiusura in entrambi i casi, ma non si fanno uso di esso nel primo caso).

Una chiusura è semplicemente "tutte le variabili visibili a questa funzione". Niente di più, niente di meno. E ovviamente, in entrambi i casi, queste variabili esistono e sono determinate dal compilatore.

Ma ciò che di solito si intende quando si parla di "utilizzo di chiusure" è che le espressioni lambda possono utilizzare tutte le variabili locali visibili nel punto in cui sono state dichiarate. Fanno tutti parte della sua chiusura.

Nel tuo caso, d è semplicemente il parametro della funzione lambda, e dal momento che è tutto ciò che usi nel primo caso, non stai davvero sfruttando le chiusure.

Nel secondo caso, filter non è definito nell'espressione lambda, non è un parametro o altro. È una variabile locale che è così visibile nel punto in cui viene dichiarata la lambda. Quindi fa parte della chiusura del lambda, che ti permette di fare riferimento nel corpo del lambda.

Modifica
Come sottolineato nei commenti, non ho letto il codice di troppo da vicino. Ho notato solo la seconda espressione lambda in ogni esempio. Il primo lambda usa chiusure (si chiude su subFolders in entrambi i casi).

+2

Il primo esempio si chiude su 'sottocartelle' quindi è anche una chiusura. –

+0

Oh, giusto, non ho nemmeno notato il primo lambda. Ho appena visto 'd => ...' uno. Hai ragione. Il primo si chiude su 'subFolders', e nel secondo caso, il secondo lambda si chiude su' filter'. – jalf

0

Entrambi gli esempi hanno chiusure. Nel metodo anonimo "A" acquisisce sottocartelle variabili locali. In "B", il metodo anonimo cattura sottocartelle di variabili locali e filtra. Dai anche un'occhiata a here.

P.S. Si noti inoltre che si sta effettivamente utilizzando la chiusura in "A" perché si utilizza la variabile sottocartelle.

0

Ecco un esempio da http://www.agileatwork.com/a-proper-closure-in-csharp/ di qualcosa che potrebbe sembrare un po 'più familiare se si ha familiarità con JavaScript. Viene creata una chiusura attorno alla variabile tax in modo che il calcolo venga eseguito una sola volta. Non è esattamente facile per gli occhi, ma è bello poter fare questo tipo di cose in 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; } 

    ... 
} 
Problemi correlati