如何将多个 LINQ to objects 请求合并为一个请求

How to combine mulitiple LINQ to objects requests into single one

我想将 GetCurrentAuction 重写为单个 LINQ 请求:

private AuctionInfo GetCurrentAuction()
    {
        var auctions = Auctions.List().ToList();
        var liveAuction = auctions
            .Where(AuctionIsLive)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();

        if (liveAuction != null)
        {
            return liveAuction;
        }

        var openAuction = auctions
            .Where(AuctionIsOpen)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();

        if (openAuction != null)
        {
            return openAuction;
        }

        // next upcoming auction
        return auctions
            .Where(a => a.StartDate >= DateTime.UtcNow)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();
    }

    private bool AuctionIsLive(AuctionInfo auction)
    {
        // WorkflowStage is int
        return auction.WorkflowStage == LIVE_WORKFLOW_STAGE;
    }

    private bool AuctionIsOpen(AuctionInfo auction)
    {
        return auction.WorkflowStage == OPEN_WORKFLOW_STAGE;
    }

有人可以建议如何实现这一目标吗?看起来使用 auctions.GroupBy(a => a.WorkflowStage) 并没有让我更接近解决方案。

你可以用很有用?? ( https://msdn.microsoft.com/en-us/library/ms173224.aspx ) 运算符并实现这个:

        var result = auctions.Where(AuctionIsLive).OrderBy( x => x.StartDate).FirstOrDefault() ?? 
            auctions.Where(AuctionIsOpen).OrderBy( x => x.StartDate).FirstOrDefault() ??
            auctions.Where(a => a.StartDate >= DateTime.UtcNow).OrderBy(a => a.StartDate).FirstOrDefault();

        return result;

您可以通过订购它们来表明偏好 - 例如:

return
  Auctions.List().ToList()  //--> ToList() not needed here?
  .Where
  ( a =>
    AuctionIsLive(a) ||
    AuctionIsOpen(a) ||
    a.StartDate >= DateTime.UtcNow
  )
  .OrderBy
  ( a => 
    AuctionIsLive( a ) ? 0 :
    AuctionIsOpen( a ) ? 1 : 2
  )
  .ThenBy( a => a.StartDate )
  .FirstOrDefaut();

这取决于您使用的数据源和 LINQ 提供程序。 例如,如果您使用 LINQ 来 SQL,那么首选的做法是使用 Expressions 来节省您的记忆,并最终得到类似于 @fankyCatz 的答案:

return Auctions.Where(a => a.WorkflowStage == LIVE_WORKFLOW_STAGE).OrderBy(x => x.StartDate).FirstOrDefault() ??
        Auctions.Where(a => a.WorkflowStage == OPEN_WORKFLOW_STAGE).OrderBy(x => x.StartDate).FirstOrDefault() ??
        Auctions.Where(a => a.StartDate >= DateTime.UtcNow).OrderBy(a => a.StartDate).FirstOrDefault();

但是,仅使用 LINQ to Objects 我最终会得到与@Clay 的答案相似的答案,只是会通过映射提高可读性:

public static Dictionary<int, Func<AuctionInfo, bool>> Presedence = 
            new Dictionary<int, Func<AuctionInfo, bool>>
{
    { 0, a => a.WorkflowStage == LIVE_WORKFLOW_STAGE },
    { 1, a => a.WorkflowStage == OPEN_WORKFLOW_STAGE },
    { 2, a => a.StartDate >= DateTime.UtcNow },
};

//in your GetCurrentAuction()
return Auctions.Where(a => Presedence.Any(p => p.Value(a)))
                .OrderBy(a => Presedence.First(p => p.Value(a)).Key)
                .ThenBy(a => a.StartDate)
                .FirstOrDefault();