2012-06-26 34 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