Replacement answer following clarification in comments:
For successively building additional filters, you don't need expression trees; you can call .Where
multiple times (as necessary, once per search term) - for example:
IEnumerable<DataRow> query = tempResults.AsEnumerable();
if(!string.IsNullOrEmpty(value1)) {
query = query.Where(row => row.Field<string>("Col1") == value1);
}
if (!string.IsNullOrEmpty(value2)) {
query = query.Where(row => row.Field<string>("Col2") == value2);
}
The only thing to watch is the "capture" issue; be sure not to re-use any of the value1
, value2
etc - otherwise the last value will apply to earlier filters...
For an example of delegate combination (from comments) - note that I've dropped the DataTable
aspect here purely to make the example shorter (it will work identically):
public static class Predicate {
public static Func<T, bool> OrElse<T>(
this Func<T, bool> lhs, Func<T, bool> rhs) {
return lhs == null ? rhs : obj => lhs(obj) || rhs(obj);
}
public static Func<T, bool> AndAlso<T>(
this Func<T, bool> lhs, Func<T, bool> rhs) {
return lhs == null ? rhs : obj => lhs(obj) && rhs(obj);
}
}
class Data {
public string Color { get; set; }
}
class Program {
static void Main() {
bool redChecked = true, greenChecked = true; // from UI...
List<Data> list = new List<Data>() {
new Data { Color = "red"},
new Data { Color = "blue"},
new Data { Color = "green"},
};
Func<Data, bool> filter = null;
if (redChecked) {
filter = filter.OrElse(row => row.Color == "red");
}
if (greenChecked) {
filter = filter.OrElse(row => row.Color == "green");
}
if (filter == null) filter = x => true; // wildcard
var qry = list.Where(filter);
foreach (var row in qry) {
Console.WriteLine(row.Color);
}
}
}
(original answer)
Actually, that variant of LINQ won't use an expression tree... it will use a delegate; but you can build the tree and compile it if you really want... I'm not sure why you would, though. What do you want to do? I'll knock up an example...
Here you go; this uses an expression tree, but I can't think of a single good reason to do this, other than to prove that you can!
public static class MyExtensions
{
public static IQueryable<TRow> Where<TRow, TValue>(
this IQueryable<TRow> rows,
string columnName, TValue value)
where TRow : DataRow
{
var param = Expression.Parameter(typeof(TRow), "row");
var fieldMethod = (from method in typeof(DataRowExtensions).GetMethods()
where method.Name == "Field"
&& method.IsGenericMethod
let args = method.GetParameters()
where args.Length == 2
&& args[1].ParameterType == typeof(string)
select method)
.Single()
.MakeGenericMethod(typeof(TValue));
var body = Expression.Equal(
Expression.Call(null,fieldMethod,
param,
Expression.Constant(columnName, typeof(string))),
Expression.Constant(value, typeof(TValue))
);
var lambda = Expression.Lambda<Func<TRow, bool>>(body, param);
return rows.Where(lambda);
}
}
class Program
{
static void Main(string[] args)
{
DataTable tempResults = new DataTable();
tempResults.Columns.Add("ColumnName");
tempResults.Rows.Add("foo");
tempResults.Rows.Add("Column");
var test = tempResults.AsEnumerable().AsQueryable()
.Where("ColumnName", "Column");
Console.WriteLine(test.Count());
}
}