How can I make this query work in LINQ to Entities? - c#

I have to following code:
private static bool DoesColValueExist<T>(IQueryable dataToSearchIn, string colName, string colValue)
{
int noOfClients = 1;
Type type = typeof(T);
if (colValue != "" && colName != "")
{
var property = type.GetProperty(colName);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
Expression left = Expression.Call(propertyAccess, typeof(object).GetMethod("ToString", System.Type.EmptyTypes));
left = Expression.Call(left, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
Expression right = Expression.Constant(colValue.ToLower(), typeof(string));
MethodInfo method = typeof(string).GetMethod("Equals", new[] { typeof(string) });
Expression searchExpression = Expression.Call(left, method, right);
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { type },
dataToSearchIn.Expression,
Expression.Lambda<Func<T, bool>>(searchExpression, new ParameterExpression[] { parameter }));
var searchedData = dataToSearchIn.Provider.CreateQuery(whereCallExpression);
noOfClients = searchedData.Cast<T>().Count();
if (noOfClients == 0)
return false;
else
return true;
}
return true;
}
It works with LINQ to SQL but with LINQ to Entities, I get the error:
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.

Linq to Entities does not support .ToString() method. I also am not sure if this is a great idea to use string comparison for types that are not strings. But not all is lost. I came up with the following solution:
public partial class MyEntity
{
public int ID { get; set; }
public int Type { get; set; }
public string X { get; set; }
}
public class MyContext : DbContext
{
public DbSet<MyEntity> Entities { get; set; }
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
using (var ctx = new MyContext())
{
if (!ctx.Entities.Any())
{
ctx.Entities.Add(new MyEntity() { ID = 1, Type = 2, X = "ABC" });
ctx.SaveChanges();
}
Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.X, "aBc"));
Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.X, "aBcD"));
Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.Type, 2));
Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.Type, 5));
}
}
private static bool DoesColValueExist<TEntity, TProperty>(IQueryable<TEntity> dataToSearchIn, Expression<Func<TEntity, TProperty>> property, TProperty colValue)
{
var memberExpression = property.Body as MemberExpression;
if (memberExpression == null || !(memberExpression.Member is PropertyInfo))
{
throw new ArgumentException("Property expected", "property");
}
Expression left = property.Body;
Expression right = Expression.Constant(colValue, typeof(TProperty));
if (typeof(TProperty) == typeof(string))
{
MethodInfo toLower = typeof(string).GetMethod("ToLower", new Type[0]);
left = Expression.Call(left, toLower);
right = Expression.Call(right, toLower);
}
Expression searchExpression = Expression.Equal(left, right);
var lambda = Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(left, right), new ParameterExpression[] { property.Parameters.Single() });
return dataToSearchIn.Where(lambda).Any();
}
}
The nice thing about it is that it is more type safe than string based solution - the value of the parameter has to be the same as the value of the property. The property in turn has to be a member of the entity that is the generic type of the IQueryable'1 passed as the first parameter. Another helpful thing is that when coding against this method intellisense will show you member of the entity when you start typing the lambda expression for the second parameter. In the method itself I added an exception for string type when I call .ToLower() on both property value and the requested value to make the comparison case insensitive. For non-string types the values are compared "as is" i.e. without any modifications.
The example above is complete - you can copy and paste it to a console app project (you need to reference EntityFramework.dll though).
Hope this helps.

Try this:
private static bool DoesColValueExist<T>(IQueryable dataToSearchIn, string colName, string colValue)
{
int noOfClients = 1;
Type type = typeof(T);
if (colValue != "" && colName != "")
{
var property = type.GetProperty(colName);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
Expression left = property.PropertyType == typeof(string) ? propertyAccess : Expression.Call(propertyAccess, typeof(object).GetMethod("ToString", System.Type.EmptyTypes));
left = Expression.Call(left, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
Expression right = Expression.Constant(colValue.ToLower(), typeof(string));
MethodInfo method = typeof(string).GetMethod("Equals", new[] { typeof(string) });
Expression searchExpression = Expression.Call(left, method, right);
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { type },
dataToSearchIn.Expression,
Expression.Lambda<Func<T, bool>>(searchExpression, new ParameterExpression[] { parameter }));
var searchedData = dataToSearchIn.Provider.CreateQuery(whereCallExpression);
noOfClients = searchedData.Cast<T>().Count();
if (noOfClients == 0)
return false;
else
return true;
}
return true;
}
Basically, if the property is string then it doesn't call the ToString() method.
Hope it helps.

Related

C# Expression String.IndexOf case insensitive with the property selector

I have the following class and extension method to invoke String.Contains method. How can I change it to be case insensitive ? Something like in Expression tree for String.IndexOf method but I don't have an ideas so far how to adjust that code into my code. Any help ?
public class testItem
{
public string SomeProperty { get; set; }
}
public static IQueryable<testItem> PropertyContainsNEW<testItem>(this IQueryable<testItem> source,
Expression<Func<testItem, string>> selector,
string value)
{
ParameterExpression parameter = Expression.Parameter(typeof(testItem), "x");
Expression property = Expression.Property(parameter, ((MemberExpression)selector.Body).Member.Name);
var search = Expression.Constant(value, typeof(string));
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(property, method, search);
var predicate = Expression.Lambda<Func<testItem, bool>>(containsMethodExp, parameter);
return source.Where(predicate);
}
In order to use the StringComparison parameter, you need to correctly identify that method.
Is this what you need?:
public static IQueryable<testItem> PropertyContainsNEW(this IQueryable<testItem> source,
Expression<Func<testItem, string>> selector,
string value)
{
var parameter = Expression.Parameter(typeof(testItem), "x");
var property = Expression.Property(parameter, ((MemberExpression)selector.Body).Member.Name);
var search = Expression.Constant(value, typeof(string));
var parms = new Expression[] { search,
Expression.Constant(StringComparison.OrdinalIgnoreCase) };
var method = typeof(string).GetMethod("Contains", new[] { typeof(string), typeof(StringComparison) });
var containsMethodExp = Expression.Call(property, method, parms);
var predicate = Expression.Lambda<Func<testItem, bool>>(containsMethodExp, parameter);
return source.Where(predicate);
}

Build Lambda Expressions with Contains

I have a problem converting simple linq query to Lambda Expression.
My queries look like this:
int[] array = List<int> array2 = sql.OfType<Table1>().Select(x=>x.ID).Take(10).ToList();
var result = sql.OfType<Table1>().Where(x => array.Contains(x.ID)).Take(10).ToList();
and the final result should be:
static void DynamicSQLQuery<T>(IQueryable<T> sql, string fieldName)
{
List<int> array = sql.OfType<T>().Select(SelectExpression<T>(fieldName)).Take(10).ToList();
var result = sql.OfType<T>().Where(InExpression<T>(fieldName, array)).Take(10).ToList();
}
Class
public class Table1
{
public int ID { get; set; }
public string Name { get; set; }
}
I already converted the first lambda:
public static Expression<Func<T, int>> SelectExpression<T>(string fieldName)
{
ParameterExpression param = Expression.Parameter(typeof(T), "x");
MemberExpression selection = Expression.PropertyOrField(param, fieldName);
var lambdaExp = Expression.Lambda<Func<T, int>>(selection, param);
return lambdaExp;
}
But stuck on the second one:
static Expression<Func<T, bool>> InExpression<T>(string propertyName,IEnumerable<int> array)
{
System.Reflection.MethodInfo containsMethod = typeof(IEnumerable<int>).GetMethod("Contains");
ParameterExpression param = Expression.Parameter(typeof(T), "x");
MemberExpression member = Expression.PropertyOrField(param, propertyName);//x.{property}
var constant = Expression.Constant(3);
var body = Expression.GreaterThanOrEqual(member, constant); //x.{property} >= 3 but I need array.Contains(x.{property})
var finalExpression = Expression.Lambda<Func<T, bool>>(body, param);
return finalExpression;
}
Can anyone help me to make the lambda expression x=>array2.Contains(x.ID) in InExpression method?
Also, I'll be very grateful for some link to article/tutorial about creating these type of expressions.
Probably something like:
static Expression<Func<T, bool>> InExpression<T>(
string propertyName, IEnumerable<int> array)
{
var p = Expression.Parameter(typeof(T), "x");
var contains = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Single(x => x.Name == "Contains" && x.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
var property = Expression.PropertyOrField(p, propertyName);
var body = Expression.Call(contains, Expression.Constant(array), property);
return Expression.Lambda<Func<T, bool>>(body, p);
}
The trick here is to start off with something simple that compiles; for example:
using System.Linq;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;
public class C {
static Expression<Func<Foo, bool>> InExpression<T>(
string propertyName,IEnumerable<int> array)
{
return x => array.Contains(x.Id);
}
}
class Foo {
public int Id {get;set;}
}
Now either compile it and look in ildasm/reflector, or (and much simpler): run that through https://sharplab.io specifying C# as the output, like this
This shows you the code that the compiler generated:
private static Expression<Func<Foo, bool>> InExpression<T>(string propertyName, IEnumerable<int> array)
{
C.<>c__DisplayClass0_0<T> <>c__DisplayClass0_ = new C.<>c__DisplayClass0_0<T>();
<>c__DisplayClass0_.array = array;
ParameterExpression parameterExpression = Expression.Parameter(typeof(Foo), "x");
Expression arg_77_0 = null;
MethodInfo arg_77_1 = methodof(IEnumerable<!!0>.Contains(!!0));
Expression[] expr_38 = new Expression[2];
expr_38[0] = Expression.Field(Expression.Constant(<>c__DisplayClass0_, typeof(C.<>c__DisplayClass0_0<T>)), fieldof(C.<>c__DisplayClass0_0<T>.array));
Expression[] expr_5F = expr_38;
expr_5F[1] = Expression.Property(parameterExpression, methodof(Foo.get_Id()));
Expression arg_86_0 = Expression.Call(arg_77_0, arg_77_1, expr_5F);
ParameterExpression[] expr_82 = new ParameterExpression[1];
expr_82[0] = parameterExpression;
return Expression.Lambda<Func<Foo, bool>>(arg_86_0, expr_82);
}
Note that there's a few things in here we need to fixup, but it allows us to see what it is doing - things like memberof and fieldof don't actually exist, for example, so we need to look them up via reflection.
A humanized version of the above:
private static Expression<Func<Foo, bool>> InExpression<T>(string propertyName, IEnumerable<int> array)
{
ExpressionState state = new ExpressionState();
state.array = array;
ParameterExpression parameterExpression = Expression.Parameter(typeof(Foo), "x");
MethodInfo contains = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Single(x => x.Name == nameof(Enumerable.Contains) && x.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
Expression[] callArgs = new Expression[2];
callArgs[0] = Expression.Field(Expression.Constant(state, typeof(ExpressionState)), nameof(ExpressionState.array));
callArgs[1] = Expression.Property(parameterExpression, propertyName);
Expression body = Expression.Call(null, contains, callArgs);
ParameterExpression[] parameters = new ParameterExpression[1];
parameters[0] = parameterExpression;
return Expression.Lambda<Func<Foo, bool>>(body, parameters);
}
with:
class ExpressionState
{
public IEnumerable<int> array;
}

Expression tree for child collection List<string>.Any

I am building generic linq query using expression tree. I am stuck when creating expression on child collection. Method call blows up because of incompatible types. Normally I know what to put there, but the Any() method call has me confused. I've tried every type I can think of and no luck. Any help would be appreciated.
Here is my entity class:
public class Story : Entity
{
public string Author { get; set; }
public IList<string> Contributors { get; set; }
}
Query for which I want to generate expression tree:
var stories = new List<Story>();
stories.Where(p => p.Author.Contains("Test") || p.Contributors.Any(c => c.Contains("Test")));
What I have got so far
public interface IFilterCriteria
{
string PropertyToCompare { get; set; }
object ValueToCompare { get; set; }
FilterOperator FilterOperator { get; set; }
bool IsList { get; set; }
Expression Expression { get; set; }
}
public static IQueryable<T> Filter<T>(this IQueryable<T> query, IList<IFilterCriteria> filterCriterias, LogicalOperator logicalOperator = LogicalOperator.And)
{
if (filterCriterias != null && filterCriterias.Any())
{
var resultCondition = filterCriterias.ToExpression(query, logicalOperator);
var parameter = Expression.Parameter(query.ElementType, "p");
if (resultCondition != null)
{
var lambda = Expression.Lambda(resultCondition, parameter);
var mce = Expression.Call(
typeof(Queryable), "Where",
new[] { query.ElementType },
query.Expression,
lambda);
return query.Provider.CreateQuery<T>(mce);
}
}
return query;
}
public static Expression ToExpression<T>(this IList<IFilterCriteria> filterCriterias, IQueryable<T> query, LogicalOperator logicalOperator = LogicalOperator.And)
{
Expression resultCondition = null;
if (filterCriterias.Any())
{
var parameter = Expression.Parameter(query.ElementType, "p");
foreach (var filterCriteria in filterCriterias)
{
var propertyExpression = filterCriteria.PropertyToCompare.Split('.').Aggregate<string, MemberExpression>(null, (current, property) => Expression.Property(current ?? (parameter as Expression), property));
Expression valueExpression;
var constantExpression = Expression.Constant(filterCriteria.ValueToCompare);
if (!filterCriteria.IsList)
{
valueExpression = Expression.Convert(constantExpression, propertyExpression.Type);
}
else
{
valueExpression = Expression.Call(typeof (Enumerable), "Any", new[] {typeof (string)},
propertyExpression, filterCriteria.Expression,
Expression.Constant(filterCriteria.ValueToCompare,
typeof (string)));
}
Expression condition;
switch (filterCriteria.FilterOperator)
{
case FilterOperator.IsEqualTo:
condition = Expression.Equal(propertyExpression, valueExpression);
break;
case FilterOperator.IsNotEqualTo:
condition = Expression.NotEqual(propertyExpression, valueExpression);
break;
case FilterOperator.IsGreaterThan:
condition = Expression.GreaterThan(propertyExpression, valueExpression);
break;
case FilterOperator.IsGreaterThanOrEqualTo:
condition = Expression.GreaterThanOrEqual(propertyExpression, valueExpression);
break;
case FilterOperator.IsLessThan:
condition = Expression.LessThan(propertyExpression, valueExpression);
break;
case FilterOperator.IsLessThanOrEqualTo:
condition = Expression.LessThanOrEqual(propertyExpression, valueExpression);
break;
case FilterOperator.Contains:
condition = Expression.Call(propertyExpression, typeof(string).GetMethod("Contains", new[] { typeof(string) }), valueExpression);
break;
case FilterOperator.StartsWith:
condition = Expression.Call(propertyExpression, typeof(string).GetMethod("StartsWith", new[] { typeof(string) }), valueExpression);
break;
case FilterOperator.EndsWith:
condition = Expression.Call(propertyExpression, typeof(string).GetMethod("EndsWith", new[] { typeof(string) }), valueExpression);
break;
default:
condition = valueExpression;
break;
}
if (resultCondition != null)
{
switch (logicalOperator)
{
case LogicalOperator.And:
resultCondition = Expression.AndAlso(resultCondition, condition);
break;
case LogicalOperator.Or:
resultCondition = Expression.OrElse(resultCondition, condition);
break;
}
}
else
{
resultCondition = condition;
}
}
}
return resultCondition;
}
That's how I am using expressions:
var stories = new List<Story>();
var filters = new List<FilterCriteria>();
filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Author", FilterOperator = FilterOperator.Contains });
Expression<Func<string, bool>> func = t => t.Contains("Test");
filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Contributors", FilterOperator = FilterOperator.Contains, Expression = func });
stories.Filter(filters, LogicalOperator.Or).ToList();
But after running this code, I get this error which I am not able to resolve
No generic method 'Any' on type 'System.Linq.Queryable' is compatible
with the supplied type arguments and arguments. No type arguments
should be provided if the method is non-generic. Description: An
unhandled exception occurred during the execution of the current web
request. Please review the stack trace for more information about the
error and where it originated in the code.
Exception Details: System.InvalidOperationException: No generic method
'Any' on type 'System.Linq.Queryable' is compatible with the supplied
type arguments and arguments. No type arguments should be provided if
the method is non-generic.
Source Error:
Line 184: { Line 185:
var overload = typeof(Queryable).GetMethods().Single(mi => mi.Name ==
"Any" && mi.GetParameters().Count() == 2); Line 186:
Expression.Call(typeof(Queryable), "Any", new[] { typeof(string) },
propertyExpression, or); Line 187:
valueExpression = Expression.Call(typeof(Enumerable), "Any", new[] {
typeof(string)}, propertyExpression, or, Expression.Constant("Test",
You don't call Any method anywhere in your code.
You should extend Contains, example:
case FilterOperator.Contains:
// if collection
if (propertyExpression.Type.IsGenericType &&
typeof(IEnumerable<>)
.MakeGenericType(propertyExpression.Type.GetGenericArguments())
.IsAssignableFrom(propertyExpression.Type))
{
// find AsQueryable method
var toQueryable = typeof(Queryable).GetMethods()
.Where(m => m.Name == "AsQueryable")
.Single(m => m.IsGenericMethod)
.MakeGenericMethod(typeof(string));
// find Any method
var method = typeof(Queryable).GetMethods()
.Where(m => m.Name == "Any")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(string));
// make expression
condition = Expression.Call(
null,
method,
Expression.Call(null, toQueryable, propertyExpression),
filterCriteria.Expression
);
}
else
{
condition = Expression.Call(propertyExpression, typeof(string).GetMethod("Contains", new[] { typeof(string) }), valueExpression);
}
break;
Also you should have created one p parameter (Expression.Parameter(query.ElementType, "p")) otherwise you'll get variable 'p' of type 'WpfApplication2.Story' referenced from scope '', but it is not defined error.
You may pass parameter from Filter method to ToExpression method.

Linq "Full Text" Search

I'm using this search function. but I need it to do an "and" not an "or" I cant seem to get it to return the results I want. I need to perform a search function where the search results match the text entered in box. But only a partial search. For example if I type in "Super D" I want it to find everything that contains a "Super" AND a "D".
public static class ObjectContextExtensions
{
public static IQueryable<T> FullTextSearch<T>(this IQueryable<T> queryable, string searchKey)
{
return FullTextSearch<T>(queryable, searchKey, false);
}
public static IQueryable<T> FullTextSearch<T>(this IQueryable<T> queryable, string searchKey,
bool exactMatch)
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "c");
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
// MethodInfo toStringMethod = typeof (object).GetMethod("ToString", new Type[] {});
var publicProperties =
typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(p => p.PropertyType == typeof(string));
Expression orExpressions = null;
string[] searchKeyParts;
if (searchKey == null)
{
searchKey = "0";
}
searchKeyParts = !exactMatch ? searchKey.Split(' ') : new[] { searchKey };
foreach (MethodCallExpression callContainsMethod in from property in publicProperties
select Expression.Property(parameter, property) into nameProperty
from searchKeyPart in searchKeyParts
let searchKeyExpression = Expression.Constant(searchKeyPart) let containsParamConverted = Expression.Convert(searchKeyExpression, typeof(string))
select Expression.Call(nameProperty, containsMethod, (Expression)containsParamConverted))
{
if (orExpressions == null)
{
orExpressions = callContainsMethod;
}
else
{
orExpressions = Expression.Or(orExpressions,callContainsMethod);
}
}
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { queryable.ElementType },
queryable.Expression,
Expression.Lambda<Func<T, bool>>(orExpressions, new ParameterExpression[] { parameter }));
return queryable.Provider.CreateQuery<T>(whereCallExpression);
}
}
Looks as though setting exactMatch to true would do the trick as it wouldn't split the search terms up.
FullTextSearch<MyType>(searchKey, true)
Failing that, change
orExpressions = Expression.Or(orExpressions,callContainsMethod);
to
andExpressions = Expression.And(andExpressions,callContainsMethod);

How do I create an expression tree to represent 'String.Contains("term")' in C#?

I am just getting started with expression trees so I hope this makes sense. I am trying to create an expression tree to represent:
t => t.SomeProperty.Contains("stringValue");
So far I have got:
private static Expression.Lambda<Func<string, bool>> GetContainsExpression<T>(string propertyName, string propertyValue)
{
var parameterExp = Expression.Parameter(typeof(T), "type");
var propertyExp = Expression.Property(parameter, propertyName);
var containsMethodExp = Expression.*SomeMemberReferenceFunction*("Contains", propertyExp) //this is where I got lost, obviously :)
...
return Expression.Lambda<Func<string, bool>>(containsMethodExp, parameterExp); //then something like this
}
I just don't know how to reference the String.Contains() method.
Help appreciated.
Something like:
class Foo
{
public string Bar { get; set; }
}
static void Main()
{
var lambda = GetExpression<Foo>("Bar", "abc");
Foo foo = new Foo { Bar = "aabca" };
bool test = lambda.Compile()(foo);
}
static Expression<Func<T, bool>> GetExpression<T>(string propertyName, string propertyValue)
{
var parameterExp = Expression.Parameter(typeof(T), "type");
var propertyExp = Expression.Property(parameterExp, propertyName);
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var someValue = Expression.Constant(propertyValue, typeof(string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}
You might find this helpful.
To perform a search like:
ef.Entities.Where(entity => arr.Contains(entity.Name)).ToArray();
which the trace string will be:
SELECT .... From Entities ... Where Name In ("abc", "def", "qaz")
I use the method I created below:
ef.Entities.Where(ContainsPredicate<Entity, string>(arr, "Name")).ToArray();
public Expression<Func<TEntity, bool>> ContainsPredicate<TEntity, T>(T[] arr, string fieldname) where TEntity : class {
ParameterExpression entity = Expression.Parameter(typeof(TEntity), "entity");
MemberExpression member = Expression.Property(entity, fieldname);
var containsMethods = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains");
MethodInfo method = null;
foreach (var m in containsMethods) {
if (m.GetParameters().Count() == 2) {
method = m;
break;
}
}
method = method.MakeGenericMethod(member.Type);
var exprContains = Expression.Call(method, new Expression[] { Expression.Constant(arr), member });
return Expression.Lambda<Func<TEntity, bool>>(exprContains, entity);
}
How about this:
Expression<Func<string, string, bool>> expFunc = (name, value) => name.Contains(value);
In the client code:
bool result = expFunc.Compile()("FooBar", "Foo"); //result true
result = expFunc.Compile()("FooBar", "Boo"); //result false
Here is how to create an expression tree of string.Contains.
var method = typeof(Enumerable)
.GetRuntimeMethods()
.Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2);
var containsMethod = method.MakeGenericMethod(typeof(string));
var doesContain = Expression
.Call(containsMethod, Expression.Constant(criteria.ToArray()),
Expression.Property(p, "MyParam"));
Actual usage at https://raw.githubusercontent.com/xavierjohn/Its.Cqrs/e44797ef6f47424a1b145d69889bf940b5581eb8/Domain.Sql/CatchupEventFilter.cs

Categories