0

So i have a one class to deal with strings, splitting them and setting the whole expression (There is more than just contriesNames, but iam not introducing it here to make it simpler):

public class DealWithExpression
{
     public void DealWithExpression(Params params)
     {
        string[] countriesNames = {};
        if(params.Countries != null)
           countriesNames = params.Countries.Split(','); // params got Countries string prop.

        HandleQuery(someQuery, x => countriesNames.Contains(db.table.Name))
     }
}

And i have another class that gets the query from database and is supposed to filter with expected Filter expressions:

public class DealWithQuery()
{
     HandleQuery(IQueryable<TEntity> inputQuery, Expression<Func<T, bool>> Filter)
     {
          var query = inputQuery;

           if(Filter != null)
           {
               query.Where(Filter);
           }
     }
}

I think the expression i store in Filter object doesn't store the string[] countriesNames and it doesn't know what to compare against, but iam not sure. I dont want to store additional string arrays in DealWithQuery class, is there a way to do it? To avoid cluttering the classes?

PTK
  • 53
  • 7
  • You can achieve this by declaring a function of a function that takes in a list of strings (your filter). Now you have a function with a list in it that you can call from a LINQ statement. These functions are similar to "higher order functions" See below for an example: `Func, Func> filter = list => str => list.Contains(str); var queryParameters = new List() {"Nike", "Sweden", "Large"}; var countries = new List() {"Germany", "Sweden", "Denmark"}; var countryFilter = filter(countries); var filteredList = queryParameters.Where(countryFilter);` – Rasmus Edvardsen Sep 01 '20 at 10:05
  • Shamless plug: I've written a [VS debugging visualizer](https://github.com/zspitz/ExpressionTreeVisualizer) that allows you to inspect the structure of an expression tree; point it at `someQuery.Expression` and you'll be able to see the expression used to generate the query, including any closed-over variables. Also, if `countriesNames` is empty, I'm guessing the query won't return any results, because `countriesNames` doesn't contain any of the values; this may or may not be desired behavior. – Zev Spitz Sep 02 '20 at 16:18

1 Answers1

0

It will actually store the collection. You can check that as simple as that:

var x = new[] {"a","b"};
Expression<Func<string, bool>> expr = s => x.Contains(s);
Console.WriteLine(expr.Compile()("a")); // prints "True"
Console.WriteLine(expr.Compile()("a1")); // prints "False"

This is called closure. Closures in C# are achieved using special compiler generated class (and works for anonymous functions and expression trees as well). You can check decompilation here yourself. Or with something similar to your original code.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • That's weird because it doesn't filter my query at all, i checked with debugger and for sure i got the string[] there from params iam sending, it adds the Expression to my Filter but it doesn't work when iam adding it in query.Where(filter) – PTK Aug 31 '20 at 17:19
  • @PTK check the query which hits the db with the profiler first. – Guru Stron Aug 31 '20 at 17:22