2009-06-05 13 views
21

मैं एक नकली डेटा स्रोत बना रहा हूं जिसे मैं SortExpressions की सूची में पास करने में सक्षम होना चाहता हूं।एकाधिक फ़ील्ड द्वारा सॉर्ट करने के लिए मैं linq का उपयोग कैसे कर सकता हूं?

public SortExpression(string name, SortDirection direction) 
{ 
    this.name = name; 
    this.direction = direction; 
} 

जॉन स्कीट के कोड और भी पूरे वर्ग के साथ अद्यतन। GetData() केवल ऑब्जेक्ट को एक्स रिकॉर्ड्स के साथ पॉप्युलेट कर रहा है।

public class Data 
{ 

public int Id { get; set; } 
public Guid gId { get; set; } 
public string Name { get; set; } 
public string Phone { get; set; } 
public string Address { get; set; } 
public DateTime Created { get; set; } 
public string SortMe { get; set; } 
public static List<Data> GetFakeData(int start, int numberToFetch, IList<SortExpression> sortExpressions, IList<FilterExpression> filterExpressions, out int totalRecords) 
{ 
    DataCollection items = GetData(); 
    IEnumerable<Data> query = from item in items select item; 

    bool sortExpressionsExist = sortExpressions != null; 
    if (sortExpressionsExist) 
    { 
     // Won't be read in the first iteration; will be written to 
     IOrderedEnumerable<Data> orderedQuery = null; 
     for (int i = 0; i < sortExpressions.Count; i++) 
     { 
      // Avoid single variable being captured: capture one per iteration. 
      // Evil bug which would be really hard to find :) 
      int copyOfI = i; 
      // Tailor "object" depending on what GetProperty returns. 
      Func<Data, object> expression = item => 
        item.GetType().GetProperty(sortExpressions[copyOfI].Name); 

      if (sortExpressions[i].Direction == SortDirection.Ascending) 
      { 
       orderedQuery = (i == 0) ? query.OrderBy(expression) 
             : orderedQuery.ThenBy(expression); 
      } 
      else 
      { 
       orderedQuery = (i == 0) ? query.OrderByDescending(expression) 
             : orderedQuery.ThenByDescending(expression); 
      } 
     } 
     query = orderedQuery; 
    } 

    bool filterExpressionsExist = filterExpressions != null; 
    if (filterExpressionsExist) 
    { 
     foreach (var filterExpression in filterExpressions) 
     { 
      query.Where(item => item.GetType().GetProperty(filterExpression.ColumnName).GetValue(item, null).ToString().Contains(filterExpression.Text)); 
     } 
    } 
    totalRecords = query.Count(); 


     return query.Skip(start).Take(numberToFetch).ToList<Data>(); 
    } 
} 

कुछ भी नहीं कर रहा प्रतीत होता है। संकलन, कोई त्रुटि नहीं, बस कोई तरह नहीं। कोई विचार?

उत्तर

27

दो समस्याएं हैं। पहला यह है कि दूसरे ने संकेत दिया है - आपको OrderBy आदि द्वारा दिए गए मान का उपयोग करने की आवश्यकता है। दूसरा यह है कि प्रत्येक बार जब आप OrderBy पर कॉल करते हैं, तो यह एक नया "प्राथमिक" ऑर्डरिंग जोड़ रहा है। पहले ऑर्डरिंग लागू होने के बाद आप वास्तव में ThenBy चाहते हैं। दुर्भाग्यवश, यह बहुत बदसूरत बनाता है। यह अभी भी एक पुनर्रचना के बाद बहुत बदसूरत है, लेकिन नहीं भी बुरा ...

IEnumerable<Data> query = from item in items select item; 
if (sortExpressionsExist) 
{ 
    // Won't be read in the first iteration; will be written to 
    IOrderedEnumerable<Data> orderedQuery = null; 
    for (int i = 0; i < sortExpressions.Count; i++) 
    { 
     // Avoid single variable being captured: capture one per iteration. 
     // Evil bug which would be really hard to find :) 
     int copyOfI = i; 
     // Tailor "object" depending on what GetProperty returns. 
     Func<Data, object> expression = item => 
       item.GetType() 
        .GetProperty(sortExpressions[copyOfI].Name) 
        .GetValue(item, null); 

     if (sortExpressions[i].Direction == SortDirection.Ascending) 
     { 
      orderedQuery = (i == 0) ? query.OrderBy(expression) 
            : orderedQuery.ThenBy(expression); 
     } 
     else 
     { 
      orderedQuery = (i == 0) ? query.OrderByDescending(expression) 
            : orderedQuery.ThenByDescending(expression); 
     } 
    } 
    query = orderedQuery; 
} 
+0

हाँ, यह कारण है कि मैं foreach के बजाय पाश के लिए कर रहा हूँ है, क्योंकि मैं सोच रहा था कि मुझे वहां कुछ जगह चाहिए। – rball

+0

मैंने अभी तक एक बग तय कर लिया है - आपको कॉपीऑफआई भाग की आवश्यकता है अन्यथा गलत वैरिएबल कैप्चर किया जाएगा! –

+0

बकवास, अभी भी काम नहीं कर रहा है। – rball

5

OrderBy एक नया IEnumerable देता है, ताकि आप की तरह कुछ करने की जरूरत है:

IEnumerable<Data> results 
    = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name)); 
2

OrderBy/OrderByDescending 'ऑपरेटरों' String.ToUpper(), यानी की तरह काम करते हैं, वे बात ले आप उस पर आह्वान , और एक 'प्रतिलिपि' उत्पन्न करें जिसमें आपने जो पूछा है।

दूसरे शब्दों में, कहने के बजाय:

query.Orderby(item->item.X) 

आपको क्या करना चाहिए

query = query.Orderby(item->item.X) 

या

sortedResult = query.Orderby(item->item.X) 

[और के रूप में जॉन स्कीट बताते हैं, ThenBy/ThenByDescending के रूप में उपयोग उनके जवाब में]

2

क्वेरी उत्परिवर्तनीय नहीं है, इसलिए ऑर्डरबी एक नई वस्तु देता है। आपको एक ही कॉल करने की आवश्यकता है, लेकिन शुरुआत में "query =" जोड़ें।

query = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name)); 
2

OrderBy on IEnumerable रिटर्न एक IOrderedEnumerable देता है। यह उन्हें लाइन में क्रमबद्ध नहीं करता है। तो अपने से वापसी मूल्य प्राप्त करें। ठीक है और आप ठीक हो जाएंगे।

1

यह काम करेगा:

YourCollection.Orderby(item => item.Property1).ThenBy(item => item.Property2); 
संबंधित मुद्दे

 संबंधित मुद्दे