2010-09-03 5 views
5

Ho difficoltà a comprendere il seguente codice C#. Questo codice è stato preso da Pro ASP.NET MVC 2 Framework di Steven Sanderson. Il codice crea in modo essenziale URL in base a un elenco di categorie.Perché hanno usato questa sintassi C# per creare un elenco di collegamenti in ASP.NET MVC 2?

Ecco il codice:

 Func<string, NavLink> makeLink = categoryName => new NavLink { 
      Text = categoryName ?? "Home", 
      RouteValues = new RouteValueDictionary(new { 
       controller = "Products", 
       action = "List", 
       category = categoryName, 
       page = 1 
      }), 
      IsSelected = (categoryName == currentCategory) 

Un sacco di roba sta succedendo qui. Sto indovinando che sta definendo una funzione che si aspetta due parametri di tipo stringa e NavLink. Poi vedo la Lambda categoryName => new NavLink etc.... Penso che tutto ciò che sta facendo sia creare un'istanza di NavLink.

La funzione viene quindi chiamato nella stessa azione Controller:

 // Place home link on top 
     List<NavLink> navLinks = new List<NavLink>(); 
     navLinks.Add(makeLink(null)); 

     // Add link for each distinct category 
     var categories = productsRepository.Products.Select(x => x.Category.Name); 
     foreach (string categoryName in categories.Distinct().OrderBy(x => x)) 
      navLinks.Add(makeLink(categoryName)); 

posso dire che si tratta di fare un elenco di NavLink. Non capisco perché Steven Sanderson abbia scritto così in questo modo. Non avrebbe potuto scrivere qualcosa del tipo:

var categories = productsRepository.Products.Select(x => x.Category.Name); 
foreach (string categoryName in categories.Distinct().OrderBy(x => x)) 
{ 
    var newlink = new Navlink{ 
     text = categoryName, 
     RouteValues = new RouteValueDictionary(new { 
      controller = "Products", 
      action = "List", 
      category = categoryName, 
      page = 1 
     }), 
     IsSelected = (categoryName == currentCategory) 
    } 
    navLinks.Add(newlink); 
} 

Esiste un vantaggio nel fare la strada di Steven contro la mia strada?

risposta

5

Sembra che abbia voluto utilizzare una funzione locale che può essere utilizzata sia per aggiungere il collegamento home che come parte del ciclo delle categorie. Se lo avesse fatto in linea come hai fatto, avrebbe dovuto quasi ripetere lo stesso codice solo per il singolo collegamento a casa.

+0

Non ho pensato di dover ripetere il codice per il collegamento home. – quakkels

1

Sto indovinando che è la definizione di una funzione che prevede due parametri di tipo string, e NavLink.

Ci vuole un parametro di stringa e restituisce un NavLink.

L'unico vantaggio che vedo creando in questo modo è se si creano NavLink in più posizioni. Quindi in questo modo hai i mezzi per creare uno tutto in un posto --- la tipica giustificazione per una subroutine, che è praticamente tutto ciò che è.

+0

non poteva essere scritto come 'NavLink makeLink (stringa categoryName) {etc ..}' ??? – quakkels

+0

@quakkels: Sì, potrebbe. L'unica differenza è che nella sua versione, 'makeLink' è localmente portata al metodo di inclusione. – Timwi

+0

@quakkels: sì. Non vedo una buona ragione per essere un delegato o un lambda, a meno che non lo usi in un altro modo nel codice. –

1

Sembra essere più sullo stile del codice. Ho anche iniziato a utilizzare lo stile di programmazione più funzionale quando sono diventato più a mio agio con i delegati.

Alcuni vantaggi sono (1) riutilizzo della funzione per usi futuri e (2) cicli possono essere abbreviati - diventa piuttosto difficile trovare parentesi graffe corrispondenti quando sono lunghi e nidificati diversi livelli.

1

(questo è solo parere, non è destinato a offendere o provocare)

Personalmente, mi piace il tuo modo migliore. (o un modello in cui si scrive semplicemente una semplice vecchia funzione privata chiamata all'interno del foreach).

È alla moda fare le cose con lambda, ma in questo caso non si guadagna nulla per questo (non è in corso alcuna esecuzione differita). In questo caso, penso che il lambda renda il codice molto meno chiaro.

+0

Penso che sia perfettamente valido se hai bisogno del codice solo all'interno di un metodo. Un metodo privato "vecchio e semplice" sarebbe accessibile al resto della classe, ma la variabile contenente il lambda è accessibile solo a questo metodo. Migliore incapsulamento. Puoi ancora renderlo un metodo privato se ne hai bisogno da qualche altra parte in seguito. – Timwi

+0

@Timwi: Capisco il tuo punto, e ho anche usato un "metodo privato" un paio di volte - Pascal ha permesso metodi privati ​​per un lungo periodo. Detto questo, è stato solo un paio di volte in circa 18 anni. L'importanza dell'incapsulamento non dovrebbe essere sottovalutata, sono d'accordo, ma ma quando si parla di un metodo privato in 1 classe, si è incapsulati piuttosto bene - né gli eredi né le forze esterne possono chiamare quel metodo, e il metodo viene prima -strumento di supporto degli strumenti da browser degli oggetti, guida in linea xml, ecc. – JMarsch

+0

@ JMarsch: ① Come ho detto, se hai bisogno di supporto per gli strumenti, l'aiuto XML, qualunque sia, puoi comunque renderlo un metodo privato "normale". - ② Ho usato solo WPF un paio di volte nella sua esistenza, vuol dire che nessun altro dovrebbe usarlo? – Timwi

2

L'uso eccessivo di qualsiasi struttura avanzata e interessante solo perché è avanzato e freddo di solito non si traduce in nulla se non in una scarsa leggibilità. A meno che il lambda non venga usato in qualche modo sofisticato e sofisticato, altrimenti userei un semplice metodo privato vecchio ...

Modifica: Vale la pena di aggiungere che “speciali sofisticati modi difficili” sono almeno commentate in modo appropriato ...

Problemi correlati