score:2
here is a way to do this. i am not going to editorialize on what you are doing - it looks like query by example, which is almost always problematic. it is as the others here have best avoided. the expression thing is interesting though - so i thought it was worth a crack at it.
class myclass
{
public string name { get; set; }
public bool hero { get; set; }
public int age { get; set; }
}
and we want to query it like this:
string name = null;
int? age = 18;
expression<func<myclass, bool>> myexpr =
x => (string.isnullorempty(name) || x.name == name) &&
(!age.hasvalue || x.age > (age ?? 0));
myexpr = myexpr.removecloture(); // this line here - removes the cloture -
// and replaces it with constant values - and shortcuts
// boolean evaluations that are no longer necessary.
// in effect this expression now becomes :
// x => x.age > 18
bool result = myexpr.compile()(
new myclass {name = "rondon", hero = true, age = 92});
so all you have to do is write removecloture();
- not a problem.
// using system;
// using system.linq.expressions;
public static class clotureremover
{
#region public methods
public static expression<texpressiontype> removecloture<texpressiontype>(
this expression<texpressiontype> e)
{
var converter = new removecloturevisitor();
var newbody = converter.visit(e.body);
return expression.lambda<texpressiontype>(newbody, e.parameters);
}
#endregion
private class removecloturevisitor : expressionvisitor
{
public removecloturevisitor()
{
}
public override expression visit(expression node)
{
if (!requiresparametervisitor.requiresparameter(node))
{
expression<func<object>> funct = () => new object();
funct = expression.lambda<func<object>>(expression.convert(node, typeof(object)), funct.parameters);
object res = funct.compile()();
return constantexpression.constant(res, node.type);
}
return base.visit(node);
}
protected override expression visitbinary(binaryexpression node)
{
if ((node.nodetype == expressiontype.andalso) || (node.nodetype == expressiontype.orelse))
{
expression newleft = visit(node.left);
expression newright = visit(node.right);
bool isor = (node.nodetype == expressiontype.orelse);
bool value;
if (isboolconst(newleft, out value))
{
if (value ^ isor)
{
return newright;
}
else
{
return newleft;
}
}
if (isboolconst(newright, out value))
{
if (value ^ isor)
{
return newleft;
}
else
{
return newright;
}
}
}
return base.visitbinary(node);
}
protected override expression visitunary(unaryexpression node)
{
if (node.nodetype == expressiontype.convert || node.nodetype == expressiontype.convertchecked)
{
expression newopperand = visit(node.operand);
if (newopperand.type == node.type)
{
return newopperand;
}
}
return base.visitunary(node);
}
private static bool isboolconst(expression node, out bool value)
{
constantexpression asconst = node as constantexpression;
if (asconst != null)
{
if (asconst.type == typeof(bool))
{
value = (bool)asconst.value;
return true;
}
}
value = false;
return false;
}
}
private class requiresparametervisitor : expressionvisitor
{
protected requiresparametervisitor()
{
result = false;
}
public static bool requiresparameter(expression node)
{
requiresparametervisitor visitor = new requiresparametervisitor();
visitor.visit(node);
return visitor.result;
}
protected override expression visitparameter(parameterexpression node)
{
result = true;
return base.visitparameter(node);
}
internal bool result;
}
}
score:0
your repository method definition suggests that you see findall as something that you pass criteria in and get a completed result back. why not instead just have the result be of type iqueryable and return session.queryover?
your service layer would then do something like this, chaining together the "wheres":
var query = _repository.findall();
if (!string.isnullorempty(name))
query = query.where(x => x.name == name);
if (stock.hasvalue)
query = query.where(x => x.stock == stock);
etc...
return query.tolist();
score:0
so here is how you could actually and lambdas together - it borrows most of it's code from this awesome answer from desco that deserves an up-vote.
public static class addexpressions
{
public static expression<func<tfrom, tto>> andlambdas<tfrom, tto>(this expression<func<tfrom, tto>> first, expression<func<tfrom, tto>> second)
{
parameterexpression paramtouse = first.parameters[0];
expression bodyleft = first.body;
conversionvisitor visitor = new conversionvisitor(paramtouse, second.parameters[0]);
expression bodyright = visitor.visit(second.body);
return expression.lambda<func<tfrom, tto>>(expression.makebinary(expressiontype.andalso, bodyleft, bodyright), first.parameters);
}
class conversionvisitor : expressionvisitor
{
private readonly parameterexpression newparameter;
private readonly parameterexpression oldparameter;
public conversionvisitor(parameterexpression newparameter, parameterexpression oldparameter)
{
this.newparameter = newparameter;
this.oldparameter = oldparameter;
}
protected override expression visitparameter(parameterexpression node)
{
return newparameter; // replace all old param references with new ones
}
protected override expression visitmember(memberexpression node)
{
if (node.expression != oldparameter) // if instance is not old parameter - do nothing
return base.visitmember(node);
var newobj = visit(node.expression);
var newmember = newparameter.type.getmember(node.member.name).first();
return expression.makememberaccess(newobj, newmember);
}
}
}
then calling the code is quite simple ....
class myclass
{
public string name { get; set; }
public bool hero { get; set; }
public int age { get; set; }
}
...
expression<func<myclass, bool>> expression1 = x => x.age > (age ?? 0);
expression<func<myclass, bool>> expression2 = x => x.name == name;
expression1 = expression1.andlambdas(expression2);
result = expression1.compile()(new myclass {
name = "rondon",
hero = true,
age = 92 });
score:1
first, i'd solve your problem by avoiding it in the first place. i'd have different methods for this.
public ienumerable<product> getproductsbyname(string name)
public ienumerable<product> getproudctsbynameandstock(string name, int stock)
public ienumerable<product> getproductsbynameandreserved(
string name,
int reserved
)
public ienumerable<product> getproducts(string name, int stock, int reserved)
these all have trivially easy implementations in terms of a lambda expression. for example:
public ienumerable<product> getproductsbyname(string name) {
return getproductsbyexpression(p => p.name == name);
}
private ienumerable<product> getproductsbyexpression(
expression<func<product, bool>> expression
) {
return _repository.findall(expression);
}
etc.
is it possible ? ta add some conditions when necessary (when my parameters has value) ?
second, yes what you want to do is possible but it's not the way i'd solve the problem.
Source: stackoverflow.com
Related Query
- Lambda Expression for Many to Many realtionship in C# EF 5 Code First
- Modifying Lambda Expression
- How to write the same code using Lambda Expression
- How to write following code in lambda expression or linq?
- ForEach loop with Lambda expression in Razor code MVC 5 For List<T>
- VS Code Coverage won't recognize only possible Expression Lambda Path
- Lambda expression with statement body error in previously working code
- How to insert a record in lambda expression and possible way to shorten the length of code
- Retrieving Property name from lambda expression
- "A lambda expression with a statement body cannot be converted to an expression tree"
- An expression tree lambda may not contain a null propagating operator
- Cannot convert lambda expression to type 'string' because it is not a delegate type
- C# Pass Lambda Expression as Method Parameter
- "Or" equivalent in Linq Where() lambda expression
- Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type
- How to write a VB.Net Lambda expression
- Pass a lambda expression in place of IComparer or IEqualityComparer or any single-method interface?
- LINQ: Passing lambda expression as parameter to be executed and returned by method
- Cannot convert lambda expression to type 'object' because it is not a delegate type
- Can you create a simple 'EqualityComparer<T>' using a lambda expression
- Like in Lambda Expression and LINQ
- What is the Efficiency and Performance of LINQ and Lambda Expression in .Net?
- lambda expression for exists within list
- Can I use Linq's Except() with a lambda expression comparer?
- LINQ: Get all selected values of a CheckBoxList using a Lambda expression
- Expression cannot contain lambda expressions
- Difference between expression lambda and statement lambda
- Lambda expression for multiple parameters
- Simple Examples of joining 2 and 3 table using lambda expression
- ReSharper gives an "@" prefix to a variable name in a lambda expression
More Query from same tag
- Linq query for ordering by ascending order except for one row
- How can I find the type of a property in an expression when the generic type is object?
- LINQ to entities - left join with condition
- Does Entity Framework query the database multiple times if I use different fields of the same Linq query at different times?
- Majority vote over strings that FAILS when equal
- Select 2nd column of stored procedure's output
- Duplicate Entries in many to many table when trying to update an object from EF CodeFirst
- C# Linq multiple queries in a single one
- How can I translate SQL query to LINQ Lambda Expression - Sum, LeftJoin, GroupBy
- How to Ignore Case in group by for multiple columns in Linq Query
- Roslyn Check Type of an Attribute
- how to make linq to display records that are two years old
- Which is fast : Query Syntax vs. Loops
- LINQ: Nullable value types in where clause
- How to get a complement list of objects using linq and EntityFramework
- How to code the partial extensions that Linq to SQL autogenerates?
- list of months and years
- Order of evaluation c#
- XML > LINQ Query > Tree View
- C# Linq execute method over results from Distinct() method
- How can I create a LINQ view?
- Creating menus at runtime depending on user role
- Looking way to make generic out of this code
- building dynamic linQ queries
- Dynamic Linq to Datatable Nullable Fields
- how to make Value cannot be null, null
- Get Row with Min Date in LINQ?
- Alternative to nesting when performing a left join and multiple inner joins
- Linq and SubSonic - returning nested complex types
- LINQ command for data reduction of GPS data