各种派生类型集合上的通用LINQ到SQL扩展方法

本文关键字:LINQ SQL 方法 扩展 派生 类型 集合 | 更新日期: 2023-09-27 18:29:18

我正在尝试为IQueryable<T>创建一个通用扩展方法。T是抽象的Player,并且IQueryable可以包含具体类型GoalkeeperStriker

public abstract class Player
{
    public string Name { get; set; }
    public string Fouls { get; set; }
}
public class Goalkeeper : Player
{
    public int Saves { get; set; }
}
public class Striker : Player
{
    public int Goals { get; set; }
}

正在工作的扩展方法(简单的)如下所示:

public static IQueryable<Goalkeeper> NotPerforming(this IQueryable<Goalkeeper> goalkeepers)
{
    return goalkeepers.Where(g => g.Saves < goalkeepers.Average(x => x.Saves));
}
public static IQueryable<Striker> NotPerforming(this IQueryable<Striker> strikers)
{
    return strikers.Where(g => g.Goals < strikers.Average(x => x.Goals));
}

我可以这样使用:

var badGoalies = players.OfType<Goalkeeper>().NotPerforming();
var badStrikers = players.OfType<Striker>().NotPerforming();

所以现在我想查询所有表现不佳的玩家

var badPlayers = players.NotPerforming();

我似乎无法正常工作。

public static IQueryable<T> NotPerforming<T>(this IQueryable<T> players)
    where T : Player
{
    // what to do here?
}

我试过。。。

return players.OfType<Striker>().NotPerforming()
          .Union(
              players.OfType<Goalkeeper>().NotPerforming()
          );

这不起作用。

做到这一点的最佳实践方式是什么?在不因为我想继续链接扩展方法而将LINQ留给SQL的情况下,并记住良好的性能?

各种派生类型集合上的通用LINQ到SQL扩展方法

您可以创建另一个扩展方法,并在其中放入一个逻辑:

public static IQueryable<Player> NotPerforming(this IQueryable<Player> players)
{
    var notPerformingGoalKeepers = players.NotPerformingGoalkeepers();
    var notPerformingStrikers = players.NotPerformingStrikers();
    return notPerformingGoalKeepers.Cast<Player>()
        .Concat(notPerformingStrikers);
}
public static IQueryable<Goalkeeper> NotPerformingGoalkeepers(this IQueryable<Player> players)
{
    var goalkeepers = players.OfType<Goalkeeper>();
    return goalkeepers.Where(g => g.Saves < goalkeepers.Average(x => x.Saves));
}
public static IQueryable<Striker> NotPerformingStrikers(this IQueryable<Player> players)
{
    var strikers = players.OfType<Striker>();
    return strikers.Where(g => g.Goals < strikers.Average(x => x.Goals));
}

使用:

var badPlayers = players.NotPerforming();

或者另一种方法:

public static IQueryable<Player> NotPerforming<T>(this IQueryable<Player> players) where T : Player
{
    if (typeof(T) == typeof(Goalkeeper))
    {
        return players.OfType<Goalkeeper>().NotPerforming();
    }
    if (typeof(T) == typeof(Striker))
    {
        return players.OfType<Striker>().NotPerforming();
    }
    return null;
}
private static IQueryable<Goalkeeper> NotPerforming(this IQueryable<Goalkeeper> goalkeepers)
{
    return goalkeepers.Where(g => g.Saves < goalkeepers.Average(x => x.Saves));
}
private static IQueryable<Striker> NotPerforming(this IQueryable<Striker> strikers)
{
    return strikers.Where(g => g.Goals < strikers.Average(x => x.Goals));
}

使用:

var badStrikers = players.NotPerforming<Striker>();
var badGoalkeepers = players.NotPerforming<Goalkeeper>();
var badPlayers = players.NotPerforming<Striker>()
    .Concat(players.NotPerforming<Goalkeeper>());