2012-06-14 19 views
6

Tengo una situación en la que necesito crear dinámicamente una lista de filtros para aplicar a una lista de objetos. Esos objetos pueden ser cualquier cosa que implemente una interfaz que contenga todas las propiedades que necesito filtrar.C# restricción genérica no funciona como se esperaba

public interface IStuff 
{ 
    bool SuitableForSomething { get; set; } 
    bool SuitableForSomethingElse { get; set; } 
} 

public class SomeStuff : IStuff 
{ 
    ... 
} 

public class SomeOtherStuff : IStuff 
{ 
    ... 
} 

Tengo una lista de criterios definidos como tal ...

public List<Expression<Func<IStuff, bool>>> Criteria { get; private set; } 

y añadir criterios como tal ...

Criteria.Add(x => x.SuitableForSomething); 
Criteria.Add(x => x.SuitableForSomethingElse); 

I a continuación, aplicar los criterios a mi consulta como tal ...

var stuff= _stuffCache 
    .GetAll() 
    .AsQueryable() 
    .ApplyCriteria(Criteria); 

que utiliza el siguiente método de extensión ...

public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<IStuff, bool>>> criteria) 
    where T : IStuff 
{ 
    foreach (var expression in criteria) 
    { 
     stuff = Queryable.Where(stuff, expression); 
    } 
    return stuff; 
} 

El compilador me está diciendo ...

cannot convert from 
    'System.Linq.Expressions.Expression<System.Func<IStuff,bool>>' 
to 
    'System.Linq.Expressions.Expression<System.Func<T,int,bool>>' 

Cuando se ciernen sobre la línea roja bajo el error en el IDE está diciendo que no puede resolver el método entre

IQueryable<IStuff> Where<IStuff>(this IQueryable<IStuff>, Expression<Func<IStuff, bool>>) in class Queryable 
and 
    IQueryable<T> Where<T>(this IQueryable<T>, Expression<Func<T,int,bool>>) in class Queryable 

Si intento convertir la expresión a Expression<Func<T, bool>>, que debería funcionar ya que T está obligado a implementar la interfaz IStuff. Consigo

Cannot cast expression of type 'Expression<Func<IStuff, bool>>' to type 'Expression<Func<T, bool>>' 

EDIT Gracias a la respuesta Raphaël 's He arreglado el método de extensión y, finalmente encontrado el verdadero problema que tenía, que era un problema de fundición cuando me estaba llamando el código. Se arregla fácilmente agregando un .Cast<SomeStuff>() después de la llamada ApplyCriteria.

Antes de

var stuff= _stuffCache 
    .GetAll() 
    .AsQueryable() 
    .ApplyCriteria(Criteria); 

Después de

var stuff= _stuffCache 
    .GetAll() 
    .AsQueryable() 
    .ApplyCriteria(Criteria) 
    .Cast<SomeStuff>(); 

Respuesta

7

cambio segundo tipo de parámetro a List<Expression<Func<T,bool>>> (T en lugar de IStuff)

public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<T, bool>>> criteria) 
    where T : IStuff 
{ 
    foreach (var expression in criteria) 
    { 
     stuff = Queryable.Where(stuff, expression); 
     //or stuff = stuff.Where(expression), as Where is an Extension method; 
    } 
    return stuff; 
} 

y el método puede ser (THX reshar por), reescrito a

public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<T, bool>>> criteria) 
      where T : IStuff 
     { 
      return criteria.Aggregate(stuff, (current, expression) => current.Where(expression)); 
     } 
+0

+1 para la respuesta correcta e imaginario +1 para sugerencia de mejora. – SimpleVar

+0

gracias. Ya lo había intentado y obtuve otros errores, que ahora he encontrado una solución. Actualizaré la pregunta con detalles. –

Cuestiones relacionadas