2014-05-06 7 views
5

Używam IEnumerable rozszerzenie pętli kolekcji, a także uzyskać swój indeks:Zastosowanie ForEach rozszerzenie Razor

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

Rozszerzenie ForEach jest następujący:

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 

Ale gdy próbuję aby go skompilować, pojawia się następujący komunikat o błędzie:

Argument 1: nie można przekonwertować z "pustki" na "System.Web. Strony internetowe.HelperResult '

Jak mogę to rozwiązać? Czy potrzebuję nowego rozszerzenia?

+2

ciekawy problem - łatwo rozwiązane tylko przez używając '@for (...)' w widoku zamiast metody rozszerzenia oczywiście. – James

+0

Inną kwestią jest to, że treść Twojej klauzuli foreach nie przekłada się na delegata akcji. Próbujesz sugerować przejście brzytwy z kodu do html, którego nie rozumie. –

Odpowiedz

5

Twój problem polega na tym, że Razor oczekuje, że Twoja metoda ForEach zwróci wartość, taką jak MvcHtmlString.

Ponadto, nie można po prostu oczekiwać, że Razor przetłumaczy treść klauzuli foreach, aby współpracować z delegatem Akcji. Jest sposób, aby to zadziałało, ale nie jest tak piękne. Sugeruję użycie klauzuli @for(...), ponieważ James zasugerował, czy chcesz użyć standardowej składni brzytwy.

Jednak tutaj jest wdrożenie że działa:

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

Zastosowanie:

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

Pojęciowo to reprezentuje 'Aggregate', a nie' ForEach', przekształcając każdy element w sekwencji w coś innego, a następnie łącząc wszystkie te rzeczy w wynik. Możesz go zaimplementować za pomocą operacji, które czynią to jaśniejszym, nie tym, że twoje jest złe, poprzez wykonanie czegoś w stylu 'return new MvcHtmlString (string.Join (" \ n ", source.Select (action));'. Ponadto 'action' nie jest już akcją, ponieważ generuje wartość. Teraz jest to 'selektor'; Sugerowałbym zmianę nazwy tego. – Servy

+0

@Servy Ya, to trochę kondensuje. Zaktualizuję to. Zostawię nazwę metody aż do op i zostaw tak jak jest. –

2

To działa, ale czuje hackish:

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> 
)