2016-01-07 2 views
1

Я пытаюсь создать общий метод расширения для IQueryable<T>. T - аннотация Player, а IQueryable может содержать конкретные типы Goalkeeper и Striker.Общие методы расширения LINQ to SQL при сборе различных производных типов

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-to-SQL, потому что я хотел бы сохранить методы расширения цепочек и сохранить хорошую производительность?

ответ

0

Вы можете создать еще один метод расширения и поместить туда логику:

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>());