扩展选择在Linq中使用哪个扩展名

时间:2012-11-01 01:56:09

标签: c# .net linq linq-to-objects

是否可以选择在Linq中应用哪个功能?
我现在拥有的例子:

List<int> list = new List<int>();
bool bDescend = false;
var listOrdered = bDescend ? list.OrderByDescending(it => it) : 
                             list.OrderBy(it => it);

您看到我根据bDescend值选择要应用的功能 - 因此实际上有两个Linq查询,而不是一个。
是否可以通过在一个查询中放置条件来避免它? 也许像是

list.ChooseFunction(bDescend ? OrderBy : OrderByDescending)...

真正的代码更加恭维,如果这样的技巧可能会使代码更具可读性。
看起来像是一种元编程......

3 个答案:

答案 0 :(得分:4)

您可以创建自己的扩展方法:

enum Ordering
{
    Ascending,
    Descending,
}

// trivial to convert to use booleans instead
// of an enum if that's truly what you need
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source, Ordering ordering, Func<TSource, TKey> keySelector) 
{
    if (ordering == Ordering.Ascending)
    {
        return source.OrderBy(keySelector);
    }
    else
    {
        return source.OrderByDescending(keySelector);
    }
}

然后将其称为

var order = Ordering.Descending;
....
MyList.OrderBy(order, it => it);

除此之外,它可以制作一个ChooseFunction类型的东西,但它必须看起来像ChooseFunction(bdescend ? "OrderBy" : "OrderByDescending")而我甚至不想进入这些神奇的字符串指的是多么丑陋功能名称是。您还必须对ChooseFunction扩展程序进行硬编码,或依赖于反射,这对于您正在尝试的简单操作来说是非常昂贵的

答案 1 :(得分:2)

您可以创建2个比较器:升序和降序,然后将其中一个传递给OrderBy方法,即:

list.OrderBy(it => it, asc ? new AscComparer() : new DescComparer())

答案 2 :(得分:0)

如果您不介意丢失扩展方法语法,可以使用委托来指定排序方法:

List<int> list = new List<int>();

Func<IEnumerable<int>, Func<int, int>,IEnumerable<int>> sorter;
if (cond)
{
   sorter = Enumerable.OrderBy<int, int>;
}
else
{
   sorter = Enumerable.OrderByDescending<int, int>;
}

var sorted = sorter(list, _ => _);