2009-04-17 15 views
12

Sono stato reading this article about closures in cui si dice:Cosa c'è di così speciale nelle chiusure?

  • "tutto l'impianto idraulico è automatico"
  • il compilatore "crea una classe wrapper" e "aumenta la durata delle variabili"
  • "si è possibile utilizzare variabili locali senza preoccupazione"
  • il compilatore .NET si prende cura del l'impianto idraulico per voi, ecc

Così ho fatto un esempio in base al loro codice e per me, sembra che sebbene le chiusure agiscano in modo simile ai metodi con denominazione regolare che "si prendono cura delle variabili locali senza preoccupazione" e in cui "tutto l'impianto idraulico è automatico".

Oppure quale problema ha risolto questo "involucro di variabili locali" che rende le chiusure così speciali/interessanti/utili?

using System; 
namespace TestingLambda2872 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Func<int, int> AddToIt = AddToItClosure(); 

      Console.WriteLine("the result is {0}", AddToIt(3)); //returns 30 
      Console.ReadLine(); 
     } 

     public static Func<int, int> AddToItClosure() 
     { 
      int a = 27; 
      Func<int, int> func = s => s + a; 
      return func; 
     } 
    } 
} 

risposta

Quindi la risposta a questo è quello di leggere Jon Skeet's article on closures che Marc ha sottolineato. Questo articolo non mostra solo l'evoluzione che porta alle espressioni lambda in C# ma mostra anche come le chiusure siano trattate in Java, un'ottima lettura per questo argomento.

+0

Altre lingue (ad esempio Javascript) supportano le chiusure. Stai chiedendo il concetto o l'implementazione specifica di C#? – strager

+1

Penso che l'esempio sia troppo semplice per comprendere il potere delle chiusure. –

+0

@strager: intendo il concetto in generale, sto cercando di capire come delegare, chiusure, mappe, lambda, "espressioni lambda", "lambda trees", funzioni anonime, curry, ecc. E in generale il nuovo paradigmi di programmazione funzionale che sembrano estendersi oltre qualsiasi lingua, hanno le loro radici in matematica, ecc. (avevo messo C# nel titolo perché Stackoverflow ora ti dice che il tuo titolo non è abbastanza buono, aggiungi parole univoche ...) –

risposta

20

Il tuo esempio non è chiaro, e non (IMO) mostra l'uso tipico di acquisizione (l'unica cosa catturata è a, che è sempre 3, quindi non molto interessante).

Considerate questo esempio da manuale (un predicato):

List<Person> people = ... 
string nameToFind = ... 
Person found = people.Find(person => person.Name == nameToFind); 

Ora provare senza una chiusura; è necessario fare molto di più di lavoro, anche se siamo pigri:

PersonFinder finder = new PersonFinder(); 
finder.nameToFind = ... 
Person found = people.Find(finder.IsMatch); 
... 
class PersonFinder { 
    public string nameToFind; // a public field to mirror the C# capture 
    public bool IsMatch(Person person) { 
     return person.Name == nameToFind; 
    } 
} 

approccio La cattura si estende inoltre a un sacco di variabili in ambiti diversi - un sacco di complessità che è nascosto.

Oltre ai nomi, quanto sopra è un'approssimazione di ciò che il compilatore C# esegue dietro le quinte. Si noti che quando sono coinvolti ulteriori ambiti iniziamo a concatenare le diverse classi di cattura (ad esempio gli ambiti interni hanno un riferimento alla classe di acquisizione degli ambiti esterni). Abbastanza complesso.

Jon Skeet ha un buon article on this here e altro in his book.

+0

(alla domanda cancellata su come renderlo 'static'): No - perché thread diversi potrebbero voler cercare nomi diversi nello stesso momento, o rinviare l'esecuzione del delegato. –

+1

+1 per la parte C# in profondità sulle chiusure –

+2

+1 per questa frase nell'articolo C# nelle chiusure di profondità: "le chiusure consentono di incapsulare un comportamento, passarlo intorno come qualsiasi altro oggetto e avere ancora accesso al contesto in che sono stati dichiarati per la prima volta " –

0

La chiusura è una funzionalità del compilatore. Non lo vedi, rende solo il codice che scrivi.

In caso contrario, la chiamata a AddToIt (3) avrà esito negativo, poiché la lamda sottostante utilizza la variabile locale a = 27 nell'ambito di AddToItClusure(). Questa variabile non esiste quando si chiama AddToIt.

Ma a causa della chiusura, un meccanismo utilizzato dal compilatore, il codice funziona e non devi preoccupartene.

Problemi correlati