Динамическая сортировка с помощью SerializableDynamicObject

Мне нужно сортировать коллекцию из них на основе критериев, определенных во время выполнения.

Я использовал код из этой статьи для выполнения сортировки - изначально мой код использовал динамический класс.

Затем я ударил проблемы с сериализацией по WCF, поэтому я переключился на SerializableDynamicObject, и теперь код сортировки разбивается на строку:

  PropertyInfo pi = type.GetProperty(prop);

с ошибкой, что SerializableDynamicObject не имеет свойства под названием "Имя", где "Имя" было значением prop.

Я думаю, что самое простое - найти альтернативный способ сериализации динамического типа, с которым работает алгоритм сортировки. Любые указатели в этом направлении будут оценены!

Я рассмотрел этот пример, но я получил сообщение об ошибке:

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

Ответ 1

Здесь используется код 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);
            }
        }
    }
}

Возможно, стоит обратить внимание на то, что для типов, основанных на отражении, это означает не использование рефлексии по каждому элементу; все, что оптимизировано с помощью метапрограммирования.

Ответ 2

Ответ Марка Гравелла дал мне ответ, чтобы закончить это - мне нужно было создать сортировщик, который мог бы обрабатывать несколько критериев сортировки, неизвестных до выполнения. Я принимаю ответ Марка, но публикую его, поскольку кто-то может также найти его полезным.

Там может быть более элегантный способ достижения этого, если да, пожалуйста, дайте мне знать, и я обновлю ответ.

 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"}