2011-10-19 10 views
8

में निर्माण बहुत सारे टेम्पलेटिंग इंजनों में एक विशेष प्रकार का वाक्यविन्यास होता है जो foreach और else का संयोजन होता है। मूल रूप से else खंड निष्पादित किया जाता है जब foreach लूप में कोई पुनरावृत्ति नहीं होती है। यह उपयोगी हो सकता है यदि आप किसी प्रकार का सूची फ़ॉलबैक में कोई आइटम प्रदर्शित नहीं करना चाहते हैं।सुरुचिपूर्ण foreach - अन्यथा रेजर

Twig में उदाहरण के लिए, for loop इस

{% for user in users %} 
    <li>{{ user.username|e }}</li> 
{% else %} 
    <li><em>no user found</em></li> 
{% endfor %} 

उस्तरा दृश्य इंजन का उपयोग की तरह लग सकता है, टेम्पलेट इस तरह चाहते हैं, संग्रह में आइटम की संख्या के लिए एक अतिरिक्त जांच से जुड़े:

@foreach (var user in users) { 
    <li>@user.UserName</li> 
} 
@if (!users.Any()) { 
    <li><em>no user found</em></li> 
} 

तो मेरे प्रश्न यह है: क्या हम रेजर व्यू इंजन का उपयोग करके किसी तरह का लालित्य प्राप्त कर सकते हैं।

public static class IEnumerableExtensions 
{ 
    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) 
    { 
     foreach(T item in enumerable) 
      action(item); 

     return enumerable; 
    } 

    public static IEnumerable<T> WhenEmpty<T>(this IEnumerable<T> enumerable, Action action) 
    { 
     if(!enumerable.Any()) 
      action(); 
     return enumerable; 
    } 
} 

2 कॉल पर एक दूसरे को इस लाइव उदाहरण के द्वारा demonstarted के रूप में श्रृंखला में सक्षम बनाता है:

उत्तर

9

जैमिक और मार्टिन बूथ के उत्तरों को समेकित करना। मैंने निम्नलिखित विस्तार विधि बनाई है। यह पहली तर्क के रूप में एक आईनेमरेबल लेता है, और उसके बाद टेक्स्ट को प्रस्तुत करने के लिए दो प्रतिनिधि होते हैं। रेजर व्यू में हम टेम्पलेटेड प्रतिनिधि इन दो पैरामीटर में पास कर सकते हैं। संक्षेप में इसका मतलब है कि आप टेम्पलेट्स में दे सकते हैं। तो यहाँ विस्तार विधि है और आप इसे कैसे फोन कर सकते हैं:

public static HelperResult Each<TItem>(this IEnumerable<TItem> items, 
     Func<TItem, HelperResult> eachTemplate, 
     Func<dynamic, HelperResult> other) 
    { 
     return new HelperResult(writer => 
     { 
      foreach (var item in items) 
      { 
       var result = eachTemplate(item); 
       result.WriteTo(writer); 
      } 

      if (!items.Any()) 
      { 
       var otherResult = other(new ExpandoObject()); 
       // var otherResult = other(default(TItem)); 
       otherResult.WriteTo(writer); 
      } 
     }); 
    } 

और उस्तरा विचारों में:

@Model.Users.Each(
    @<li>@item.Name</li>, 
    @<li> 
     <b>No Items</b> 
    </li> 
) 

कुल मिलाकर, बहुत साफ।

अद्यतन टिप्पणियों में किए गए सुझावों को लागू करना। यह एक्सटेंशन विधि संग्रह में आइटम्स पर लूप के लिए एक तर्क लेती है और कस्टम हेल्पर रिसेट देता है। उस सहायक पर, कोई आइटम नहीं मिलने पर टेम्पलेट प्रतिनिधि में पास करने के लिए Else विधि को कॉल कर सकता है।

public static class HtmlHelpers 
{ 
    public static ElseHelperResult<TItem> Each<TItem>(this IEnumerable<TItem> items, 
     Func<TItem, HelperResult> eachTemplate) 
    { 
     return ElseHelperResult<TItem>.Create(items, eachTemplate); 
    } 
} 

public class ElseHelperResult<T> : HelperResult 
{ 
    private class Data 
    { 
     public IEnumerable<T> Items { get; set; } 
     public Func<T, HelperResult> EachTemplate { get; set; } 
     public Func<dynamic, HelperResult> ElseTemplate { get; set; } 

     public Data(IEnumerable<T> items, Func<T, HelperResult> eachTemplate) 
     { 
      Items = items; 
      EachTemplate = eachTemplate; 
     } 

     public void Render(TextWriter writer) 
     { 
      foreach (var item in Items) 
      { 
       var result = EachTemplate(item); 
       result.WriteTo(writer); 
      } 

      if (!Items.Any() && ElseTemplate != null) 
      { 
       var otherResult = ElseTemplate(new ExpandoObject()); 
       // var otherResult = other(default(TItem)); 
       otherResult.WriteTo(writer); 
      } 
     } 
    } 

    public ElseHelperResult<T> Else(Func<dynamic, HelperResult> elseTemplate) 
    { 
     RenderingData.ElseTemplate = elseTemplate; 
     return this; 
    } 

    public static ElseHelperResult<T> Create(IEnumerable<T> items, Func<T, HelperResult> eachTemplate) 
    { 
     var data = new Data(items, eachTemplate); 
     return new ElseHelperResult<T>(data); 
    } 

    private ElseHelperResult(Data data) 
     : base(data.Render) 
    { 
     RenderingData = data; 
    } 

    private Data RenderingData { get; set; } 
} 

यह तो इस प्रकार कहा जा सकता है:

@(Model.Users 
    .Each(@<li>@item.Name</li>) 
    .Else(
     @<li> 
      <b>No Users</b> 
     </li> 
     ) 
) 
+0

अल्पविराम अदृश्य है। : पी –

+0

मैं सहमत हूं, लेकिन कोई वास्तविक तरीका नहीं है जिसे हम इसे रोक सकते हैं, क्या हम कर सकते हैं? :) – Thomas

+1

यदि आप किसी अन्य खंड के लिए नामित पैरामीटर का उपयोग करते हैं तो यह शायद और भी पठनीय है और आप इसे वैकल्पिक –

2

एक ही रास्ता मैं कुछ इस तरह प्राप्त करने के लिए सोच सकता है IEnumerable<T> करने के लिए एक्सटेंशन के एक जोड़े के साथ है http://rextester.com/runcode?code=AEBQ75190 जो निम्नलिखित कोड का उपयोग करता है:

var listWithItems = new int[] {1,2,3}; 
var emptyList = new int[]{}; 

listWithItems.ForEach(i => Console.WriteLine(i)) 
    .WhenEmpty(() => Console.WriteLine("This should never display")); 

emptyList.ForEach(i => Console.WriteLine(i)) 
    .WhenEmpty(() => Console.WriteLine("This list was empty")); 

काफी कि यह कैसे एक उस्तरा टेम्पलेट im अभी भी अनिश्चित के साथ में फिट होगा .... लेकिन शायद यह आप पर जाने के लिए कुछ देता है।

1

कुछ भी नहीं है afaik में बनाया गया है, लेकिन आप शायद इस का विस्तार कर सकता है आपकी आवश्यकताओं के अनुरूप:

http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx

मैं बाद में मदद करने के लिए अगर आप अभी भी नहीं है जब मैं अपने फोन का उपयोग नहीं कर सकता है उत्तर

+1

मुझे लगता है कि अगर आप इसे जैमिक के जवाब से जोड़ते हैं तो आपके पास समाधान होगा! –

0

हो सकता है कि यह जब सवाल उठाया गया था संभव नहीं था, लेकिन मैं सिर्फ इस तरह यह हासिल कर लिया है:

@if (Model.EmailAddress.Count() > 0) 
{ 
    foreach (var emailAddress in Model.EmailAddress) 
    { 
     <div>@emailAddress.EmailAddress</div> 
    } 
} else { <span>No email addresses to display</span> }