【问题标题】:Avoiding repeating code with Linq query + optional params避免使用 Linq 查询 + 可选参数重复代码
【发布时间】:2013-07-01 13:13:12
【问题描述】:

给定代码:

/// <summary>
/// Get a games high scores
/// </summary>
public static List<Score> GetGameHighScores(int gameID, HighScoreType type, int? skip = null, int? take  = null)
{
    var r = new List<Score>();

    using (var db = new ArcadeContext())
    {
        var q = new List<ArcadeScore>();

        if (skip != null && take != null)
        {
            switch (type)
            {
                case HighScoreType.ScoreRank:
                    q =
                        db.ArcadeScores.Where(c => c.GameID == gameID && c.ScoreRank > 0)
                            .OrderBy(c => c.ScoreRank)
                            .Skip(skip.Value)
                            .Take(take.Value)
                            .ToList();
                    break;
                case HighScoreType.UserRank:
                    q =
                        db.ArcadeScores.Where(c => c.GameID == gameID && c.UserRank > 0)
                            .OrderBy(c => c.UserRank)
                            .Skip(skip.Value)
                            .Take(take.Value)
                            .ToList();
                    break;
            }
        }
        else
        {
            switch (type)
            {
                case HighScoreType.ScoreRank:
                    q =
                        db.ArcadeScores.Where(c => c.GameID == gameID && c.ScoreRank > 0)
                            .OrderBy(c => c.ScoreRank)
                            .ToList();
                    break;
                case HighScoreType.UserRank:
                    q =
                        db.ArcadeScores.Where(c => c.GameID == gameID && c.UserRank > 0)
                            .OrderBy(c => c.UserRank)
                            .ToList();
                    break;
            }
        }
        r.AddRange(q.Select(arcadeScore => new Score(arcadeScore)));
    }
    return r;
} 

其中skiptake 是可选参数(用于需要分页时),在不重复上述内容的情况下获取正确记录的最佳方法是什么?

【问题讨论】:

  • 用三元运算符代替开关
  • 在我看来,重复的代码在 LINQ 查询中,而不是采取。唯一真正不同的是 orderBy 您可以将其简化为单个查询。

标签: c# linq refactoring dry


【解决方案1】:

不要在四个单独的查询之间切换,而是根据您的条件构建单个查询:

IQueryable<Score> query = db.ArcadeScores.Where(c => c.GameID == gameID);

switch(type)
{
    case HighScoreType.ScoreRank:
        query = query.Where(c => c.ScoreRank > 0).OrderBy(c => c.ScoreRank);
        break;
    case HighScoreType.UserRank:
        query = query.Where(c => c.UserRank > 0).OrderBy(c => c.UserRank);
        break;
}

if (skip.HasValue && take.HasValue)
   query = query.Skip(skip.Value).Take(take.Value);

return query.ToList();

【讨论】:

    【解决方案2】:

    鉴于 IEnumerable 在您调用 ToList 之前不会执行,您可以简单地将它们移到 switch 语句之外,然后调用 ToList

    【讨论】:

      【解决方案3】:

      只需使用合并运算符提供默认值:

      .Skip(skip ?? 0)
      .Take(take ?? int.MaxValue)
      

      【讨论】:

      • 这不会仍然导致有两个(本质上相同的)代码块吗?
      【解决方案4】:

      可能,将其提取到一个方法中,以便您只在需要分页的时候调用 OrderBy 和 Skip。

      db.ArcadeScores.Where(c => c.GameID == gameID && c.ScoreRank > 0)
                                      .OrderBy(c => c.ScoreRank).
      
      db.ArcadeScores.Where(c => c.GameID == gameID && c.UserRank > 0)
                                  .OrderBy(c => c.UserRank)
      

      进入

      private IEnumerable<ArcadeScore> GetArcadeOverallScore(int gameId)
      {
         return db.ArcadeScores.Where(c => c.GameID == gameID && c.ScoreRank > 0)
                                          .OrderBy(c => c.ScoreRank)
      }
      
      private IEnumerable<ArcadeScore> GetArcadeUserScore(int gameId)
      {
         return db.ArcadeScores.Where(c => c.GameID == gameID && c.UserRank > 0)
                                      .OrderBy(c => c.UserRank)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-10
        • 2014-03-07
        • 1970-01-01
        • 1970-01-01
        • 2014-07-18
        相关资源
        最近更新 更多