2014-05-06 2 views
5

Sto usando un'estensione IEnumerable per scorrere una collezione e anche ottenere il suo indice:Usa PerOgni estensione Razor

@Model.ForEach((card, i) => { 
    @<li class="[email protected](i)">@card.Text</li>; 
}) 

L'estensione ForEach è la seguente:

public static void ForEach<T>(this IEnumerable<T> source, Action<T, Int32> action) { 

    Int32 i = 0; 
    foreach (T item in source) { 
    action(item, i); 
    i++; 
    } 

} // ForEach 

Ma quando provo compilarlo ricevo il seguente messaggio di errore:

Argomento 1: non può convertire da 'vuoto' di 'System.Web. WebPages.HelperResult '

Come posso risolvere questo? Ho bisogno di una nuova estensione?

+2

problema Interessante - facilmente risolto semplicemente usando '@for (...)' nella vista invece del metodo di estensione, naturalmente. – James

+0

Un altro problema è che il corpo della clausola foreach non viene convertito in un delegato di azione. Stai cercando di implicare una transizione del rasoio dal codice all'html che non capisce. –

risposta

5

Il tuo problema è che Razor si aspetta che il tuo metodo ForEach restituisca un valore, come MvcHtmlString.

Inoltre, non puoi semplicemente aspettarti che Razor traduca il corpo della tua clausola foreach per lavorare con il tuo delegato di Azione. C'è un modo per farlo funzionare, ma non è così bello. Suggerirei di utilizzare la clausola @for(...) come suggerito da James se si desidera utilizzare la sintassi del rasoio standard.

Tuttavia, ecco un'implementazione che funziona:

public static MvcHtmlString ForEach<T>(this IEnumerable<T> source, Func<T, Int32, string> selector) 
{ 
    return new MvcHtmlString(String.Join("\n", source.Select(selector))); 
} 

Usage:

@Model.ForEach((card, i) => 
{ 
    return "<li class=c" + i + ">" + card.Text + "</li>"; 
}) 
+0

Concettualmente questo rappresenta "Aggregate', non" ForEach', poiché stai trasformando ogni elemento della sequenza in qualcos'altro, e poi combinando tutte queste cose in un risultato. Potresti effettivamente implementarlo con operazioni che lo rendano più chiaro, non che il tuo sia sbagliato, facendo qualcosa di più simile a 'return new MvcHtmlString (string.Join (" \ n ", source.Select (action)));'. Inoltre, 'action' non è più un'azione, poiché genera un valore. È un 'selettore' ora; Suggerirei di rinominarlo. – Servy

+0

@Servy Ya, che lo condensa un po '. Lo aggiorno. Lascerò il nome del metodo fino all'opzione e lascerò così com'è. –

2

Questo funziona, ma ci si sente hacker:

public static HelperResult ForEach<T>(this IEnumerable<T> source, Func<T, int, Func<TextWriter, HelperResult>> action) { 
    return new HelperResult((writer) => { 
    int i = 0; 
    foreach (T item in source) { 
     action(item, i)(writer).WriteTo(writer); 
     i++; 
    } 
    }); 
} 

@Model.ForEach((card, i) => 
    @<li class="[email protected](i)">@card.Text</li> 
)