2012-06-26 27 views
1

我需要根據運行時確定的條件對它們進行排序。使用SerializableDynamicObject進行動態分類

我在使用this文章中的代碼來執行排序 - 最初我的代碼使用了動態類。

然後我打的問題系列化超過WCF所以我切換到使用SerializableDynamicObject,現在上線的排序代碼遊:

PropertyInfo pi = type.GetProperty(prop); 

與錯誤SerializableDynamicObject沒有一個所謂的「名稱」屬性 - 其中「名稱」是道具的價值。

我想最簡單的做法是找到序列化排序算法的動態類型的替代方法。任何指針在這個方向將不勝感激!

我已經看過this例子,但我得到的錯誤信息:

The constructor with parameters (SerializationInfo, StreamingContext) is not found in ISerializable type 

回答

2

下面是一些代碼使用FastMember對於這一點,這既適用於反射型和dynamic基於對象(取決於您傳遞給TypeAccessor.Create

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Dynamic; 
using FastMember; 

namespace ConsoleApplication6 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var list = new List<dynamic>(); 
      dynamic obj = new ExpandoObject(); 
      obj.Foo = 123; 
      obj.Bar = "xyz"; 
      list.Add(obj); 
      obj = new ExpandoObject(); 
      obj.Foo = 456; 
      obj.Bar = "def"; 
      list.Add(obj); 
      obj = new ExpandoObject(); 
      obj.Foo = 789; 
      obj.Bar = "abc"; 
      list.Add(obj); 

      var accessor = TypeAccessor.Create(
       typeof(IDynamicMetaObjectProvider)); 
      string propName = "Bar"; 
      list.Sort((x,y) => Comparer.Default.Compare(
       accessor[x, propName], accessor[y,propName])); 

      foreach(var item in list) { 
       Console.WriteLine(item.Bar); 
      } 
     } 
    } 
} 

這可能是值得mentioining,對於基於反射的類型,這並不以每個使用反射項目基礎;所有這些都是通過元編程優化的。

+0

輝煌 - 感謝Marc,以及對您其他文章的有用評論 - 我會花費很多時間試圖走錯方向。 – BonyT

0

Marc Gravell的回答給了我完成這個答案 - 我需要實現一個可以處理多種排序條件的分揀器,直到運行時才能知道。我接受馬克的回答,但發佈這個作爲人可能會發現它也很有用。

有可能是一個更優雅的方式來實現這一點,如果是這樣,請讓我知道,我會更新答案。

public class SerializableDynamicObjectComparer: IComparer 
{ 
    private readonly List<KeyValuePair<string, bool>> sortCriteria = new List<KeyValuePair<string, bool>>(); 

    private readonly TypeAccessor accessor; 

    public SerializableDynamicObjectComparer(IEnumerable<string> criteria) 
    { 
     foreach (var criterium in criteria) 
     { 
      string[] sortCriterium = criterium.Split('.'); 

      this.sortCriteria.Add(new KeyValuePair<string, bool>(sortCriterium[0], 
                   sortCriterium.Length == 0 
                    ? sortCriterium[1].ToUpper() == "ASC" 
                    : false)); 
     } 

     this.accessor = TypeAccessor.Create(typeof (IDynamicMetaObjectProvider)); 
    } 

    public int Compare(object x, object y) 
    { 
     for(int i=0; i< this.sortCriteria.Count; i++) 
     { 
      string fieldName = this.sortCriteria[i].Key; 
      bool isAscending = this.sortCriteria[i].Value; 
      int result = Comparer.Default.Compare(this.accessor[x, fieldName], this.accessor[y, fieldName]); 
      if(result != 0) 
      { 
       //If we are sorting DESC, then return the -ve of the default Compare result 
       return isAscending ? result : -result; 
      } 
     } 

     //if we get here, then objects are equal on all sort criteria. 
     return 0; 
    } 
} 

用法:

var sorter = new SerializableDynamicObjectComparer(sortCriteria); 

var sortableData = reportData.ToList(); 
sortableData.Sort(sorter.Compare); 

其中SortCriteria是一個字符串數組例如

new {"Name.DESC", "Age.ASC", "Count"} 
+0

我最關心的是你調用'ToUpper'的次數。小心那個!我會首先測試這個「布爾」。事實上,你想在'Compare(x,y)'中做**幾乎沒有任何事情** - 這會被調用***很多***。改爲在構造函數中執行。 –

+0

是的 - 非常好的一點! - 將更正並更新 - 再次感謝! – BonyT