简体   繁体   English

将LINQ(OrderBy / ThenBy)代码转换为CompareTo

[英]Converting LINQ (OrderBy/ThenBy) Code to CompareTo

I have written a generic sort funciton to sort list and dicitonary. 我已经写了一个通用的排序函数来排序列表和字典。 But LINQ doesnt works on Unity due to JIT errors. 但是由于JIT错误,LINQ在Unity上不起作用。 I want to have the same generics and convert it into myList.Sort() which uses CompraeTo. 我想拥有相同的泛型并将其转换为使用CompraeTo的myList.Sort()。 But Im unable to figure out how to accomplish this as generic as this. 但是我无法弄清楚如何像这样通用。

    public static List<T> MySort<T>(this List<T> source, Type typeOfObject, bool isAscending = false, params string[] param) 
{
    if(param.Length == 0)
        return source;

    if (isAscending)
    {
        var temp = source.OrderBy (a => (typeOfObject.GetProperty (param [0])).GetValue (a, null));

        for (int i=1; i<param.Length; i++)
        {
            var myVar = i;
            temp = temp.ThenBy((a => (typeOfObject.GetProperty(param[myVar])).GetValue (a, null)));
        }
        return temp.ToList();
    }
    else
    {
        var temp = source.OrderByDescending (a => (typeOfObject.GetProperty (param [0])).GetValue (a, null));
        for (int i=1; i<param.Length; i++)
        {
            var myVar = i;
            temp.ThenByDescending((a => (typeOfObject.GetProperty(param[myVar])).GetValue (a, null)));
        }
        return temp.ToList();
    }
}

USage of this function 使用此功能

RealEstateItems.MySort(typeof(mIsoObjectExt), true, "UnlockLevel", "Coins", "Diamonds");

My current CompareTo Approac 我当前的CompareTo Approac

myList.Sort ((a,b) => {
int result = ((a.Value) as mIsoObjectExt).UnlockLevel.CompareTo(((b.Value) as mIsoObjectExt).UnlockLevel);
//  result == 0 ? result = a.Value.Coins.CompareTo(a.Value.Coins);
if(result == 0)
{
    result = ((a.Value) as mIsoObjectExt).Coins.CompareTo(((b.Value) as mIsoObjectExt).Coins);
}
else
{
    return result;
}
if(result == 0)
{
    return ((a.Value) as mIsoObjectExt).Diamonds.CompareTo(((b.Value) as mIsoObjectExt).Diamonds);
}
return result;
});

But Im not satisfied with this i have to do this every time i have to sort even on the same properties. 但是我对此并不满意,我必须每次都必须对相同的属性进行排序。 Basically i want to make something like above that i tell the function the type its properties to sort on and it sorts. 基本上,我想做类似上面的事情,我告诉函数要对其属性进行排序和排序的类型。 How can i do this with Compare/CompareTo? 如何使用“比较/比较”来做到这一点?

So we're going to need a few different building blocks to begin with. 因此,我们首先需要一些不同的构建基块。 First off, what you're really doing here is sorting each item on a collection of values, as is seen in this other question . 首先,您真正要在这里做的是对值集合上的每个项目进行排序,就像在另一个问题中看到的那样。 We can pull the solution from there to have a comparer for sorting items based on a collection of values: 我们可以从那里获取解决方案,以便有一个比较器来根据值的集合对项目进行排序:

public class SequenceComparer<T> : IComparer<IEnumerable<T>>
{
    private IComparer<T> comparer;
    public SequenceComparer(IComparer<T> compareer = null)
    {
        this.comparer = comparer ?? Comparer<T>.Default;
    }

    public int Compare(IEnumerable<T> x, IEnumerable<T> y)
    {
        using (var first = x.GetEnumerator())
        using (var second = x.GetEnumerator())
        {
            while (true)
            {
                var firstHasMore = first.MoveNext();
                var secondHasMore = second.MoveNext();
                if (!firstHasMore && !secondHasMore)
                    return 0;
                var lengthComparison = firstHasMore.CompareTo(secondHasMore);
                if (lengthComparison != 0)
                    return lengthComparison;
                var nextComparison = comparer.Compare(first.Current, second.Current);
                if (nextComparison != 0)
                    return nextComparison;
            }
        }
    }
}

We also want a way of creating a Comparison<T> delegate (which List.Sort accepts) from a projection delegate. 我们还希望有一种从投影委托中创建List.Sort Comparison<T>委托( List.Sort接受)的方法。 This method is simple enough to write: 该方法很简单,可以编写:

public static Comparison<T> CreateComparison<T, TKey>(Func<T, TKey> selector,
    IComparer<TKey> comparer = null)
{
    comparer = comparer ?? Comparer<TKey>.Default;
    return (a, b) => comparer.Compare(selector(a), selector(b));
}

It'll also be useful for us to be able to reverse a Comparison<T> (to handle descending ordering): 对于我们来说,能够反转Comparison<T> (以处理降序)也将非常有用:

public static Comparison<T> Reverse<T>(this Comparison<T> comparison)
{
    return (a, b) => comparison(b, a);
}

Now to pull all of the pieces together. 现在将所有片段组合在一起。 We can create a comparison that, for the projection, projects each item into a sequence of values that represent fetching each of the property names from the item using reflection. 我们可以创建一个比较,对于投影,将每个项目投影到一系列值中,这些值表示使用反射从该项目中获取每个属性名称。 We can then reverse the comparer if we need a descending sort. 然后,如果需要降序排序,可以反转比较器。

public static void MySort<T>(this List<T> source,
    bool isAscending = false,
    params string[] properties)
{
    var type = typeof(T);
    var comparison = CreateComparison((T item) =>
        properties.Select(prop => type.GetProperty(prop).GetValue(item)),
        new SequenceComparer<object>());
    if (!isAscending)
        comparison = comparison.Reverse();
    source.Sort(comparison);
}

Note that if you can also use the sequence comparer to simplify the LINQ approach: 请注意,如果您还可以使用序列比较器来简化LINQ方法:

public static IEnumerable<T> MyOrdering<T>(this IEnumerable<T> source,
    bool isAscending = false,
    params string[] properties)
{
    var type = typeof(T);

    Func<T, IEnumerable<object>> selector = item =>
        properties.Select(prop => type.GetProperty(prop).GetValue(item))
        .ToList();

    if (isAscending)
        return source.OrderBy(selector, new SequenceComparer<object>());
    else
        return source.OrderByDescending(selector, new SequenceComparer<object>());
}

You can use Servy's approach with reflection. 您可以将Servy的方法与反思结合使用。 If you decide against reflection, you can use the below approach, but it still needs the comparison to be provided from the caller. 如果您决定不进行反射,则可以使用以下方法,但仍需要调用方提供比较。

public class MultiValueComparer<T> : IComparer<T>
{
   private IEnumerable<Comparison<T>> _comparisons;

   public MultiValueComparer(IEnumerable<Comparison<T>> comparisons)
   {
      _comparisons = comparisons;
   }

   public int Compare(T x, T y)
   {
     foreach (var comparison in _comparisons)
     {
        var result = comparison(x, y);
        if (result != 0)
           return result;
     }
     return 0;
   }
}

An extension method which takes a variable number of parameters 一种扩展方法,采用可变数量的参数

public static void Sort<T>(List<T> source, params Comparison<T>[] comparisons)
{
   if (comparisons.Count() == 0)
      return;

   source.Sort(new MultiValueComparer<T>(comparisons));
}

Usage: 用法:

Ascending Order: 升序:

Sort(samples, (x, y) => x.Name.CompareTo(y.Name), (x, y) => x.Test.CompareTo(y.Test));

Descending Order: 降序排列:

Sort(samples, (x, y) => y.Name.CompareTo(x.Name), (x, y) => y.Test.CompareTo(x.Test));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM