I’m pushing the limits of my knowledge in c# and linq here, so please bear with me if I’m completely off with my example or understanding of linq, c#, generic types, lambda expressions,design patterns, etc.
I have a class that holds two collections, one is the collection to be filtered: IEnumberable<InstagramUser> and the second is the collection of expressions to filter on: IEnumerable<IInstagramFilter>.
public class InstagramDisplay {
public IEnumerable<InstagramUser> instagramUsers;
public IEnumerable<IInstagramFilter> instagramFilters;
public InstagramDisplay() {
instagramUsers = new List<InstagramUser>();
instagramFilters = new List<IInstagramFilter>();
}
public IEnumerable<InstagramUser> display() {
instagramFilters.ToList().ForEach(x => instagramUsers.Where(x.filter(instagramUsers)));
return instagramFilters;
}
}
public interface IInstagramFilter {
Expression<Func<T, bool>> filter<T>(IQueryable<T> source);
}
I would have classes extend IInstagramFilter. Each IInstagramFilter class would have a property (or function – not sure what’s best) that would return the lambda expression that would be applied to IEnumerable<InstagramUser> in the display() method.
public class UserFilter : IInstagramFilter {
public Expression<Func<T, bool>> filter<T>(IQueryable<T> source) {
//return some expression - but how?
}
}
I’m struggling to understand a few things:
-
How to set the expression for each
IInstagramFilterclass and then call it in thedisplay()method? -
Each
IInstagramFilterclass would have a lambda that would be used to filterIEnumerable<InstagramUser>but since the Filter class has no knowledge ofIEnumerable<InstagramUser>how would I create the appropriate lambda in the first place? -
I think this roughly follows the Decorator Pattern but perhaps there’s a better design all together that I’m not aware of.
UPDATED CODE
Based on Olivier’s answer this is what I have now. On the return for display() I’m getting the error when using .Where(filter)
The type arguments for method ‘
System.Linq.Enumerable.Where<TSource>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,bool>)‘ cannot be inferred from the usage. Try specifying the type arguments explicitly.
public class InstagramDisplay {
public IEnumerable<InstagramUser> instagramUsers;
public List<Expression<Func<InstagramUser, bool>>> instagramFilters;
public InstagramDisplay() {
instagramUsers = new List<InstagramUser>();
instagramFilters = new List<Expression<Func<InstagramUser, bool>>>();
}
public void addFilter(Expression<Func<InstagramUser, bool>> filter) {
instagramFilters.Add(filter);
}
public IEnumerable<InstagramUser> display() {
return instagramFilters.SelectMany(filter => instagramUsers.Where(filter)).Distinct(); //error on this line
}
}
You have to decide whether you want to perfom some action or whether you want to return something.
List<T>.ForEach()performs an action on each item but has a void return type and does not return anything.This
IInstagramFilterinterface seems superfluous to me. You can declare a filter list like thisIf you have a source of users you can do something like this to all users returned by all filters
SelectManyflattens the nested enumerations. The example returns all users whos name starts with “A” or who have a score >= 100. This might return a user twice, therfore I would suggest to append a.Distinct()