I have seen that is is possible to add compiled methods together.
Expression<Func<Customer, bool>> ln = c => c.lastname.Equals(_customer.lastName, StringComparison.InvariantCultureIgnoreCase);
Expression<Func<Customer, bool>> fn = c => c.firstname.Equals(_customer.firstName, StringComparison.InvariantCultureIgnoreCase);
Expression<Func<Customer, bool>> fdob = c => c.DOB.ToString("yyyyMMdd").Equals(_customer.DOB.ToString("yyyyMMdd"));
var filter = ln.Compile() + fn.Compile() + fdob.Compile();
Does it make sense to do this?
I would intend to use the filter in place of a lambda expression to filter a repository of customers:
IEnumerable<Customer> customersFound = _repo.Customers.Where(filter);
Depending on business logic, I may or may not add the three compiled methods together, but pick and choose, and possibly add more compiled methods as I go.
Can anyone explain if adding them together would build up a query string or not? Anyone got a better suggestion?
I could chain "Where" statements and use regular lambda expressions, but I am intrigued by what you might gain from compiling methods and adding them up!
Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are static methods, but they're called as if they were instance methods on the extended type.
Each C++ source file needs to be compiled into an object file. The object files resulting from the compilation of multiple source files are then linked into an executable, a shared library, or a static library (the last of these being just an archive of object files).
Compiling and Linking in C++ The compilation is the process which convert the program written in human readable language like C, C++ etc into a machine code, directly understood by the Central Processing Unit. There are many stages involved in creating a executable file from the source file.
Methods and Functions are the same in C#. However, Methods are used in C# and are functions that operate through a designated class. A method is a group of statements that together perform a task. Every C# program has at least one class with a method named Main.
That's a side-effect of the fact that the Compile method returns a delegate.
Internally, a delegate is a multicast-delegate, it can involve multiple chained references to methods.
The +
is in this case just a quick way to chain them together. You can read more about combining delegates in the How to: Combine Delegates on MSDN.
Here's a LINQPad program that demonstrates:
void Main()
{
var filter = GetX() + GetY() + GetZ();
filter().Dump();
}
public int X() { Debug.WriteLine("X()"); return 1; }
public int Y() { Debug.WriteLine("Y()"); return 2; }
public int Z() { Debug.WriteLine("Z()"); return 3; }
public Func<int> GetX() { return X; }
public Func<int> GetY() { return Y; }
public Func<int> GetZ() { return Z; }
Output:
X()
Y()
Z()
3
Note that it thus seems to just disregard the return value from the first method calls, and returns only the last, although it fully calls the prior methods as well.
Note that the above code is similar to this:
void Main()
{
Func<int> x = X;
Func<int> y = Y;
Func<int> z = Z;
var filter = x + y + z;
filter().Dump();
}
public int X() { Debug.WriteLine("X()"); return 1; }
public int Y() { Debug.WriteLine("Y()"); return 2; }
public int Z() { Debug.WriteLine("Z()"); return 3; }
The short answer is thus that no, this does not do what you want it to do.
When you call Compile()
, you are creating instances of type Func<Customer, bool>
, which is a delegate.
Delegates overload the operator+
to return Multicast Delegates, which is what is happening here.
See MSDN: How to: Combine Delegates (Multicast Delegates)
So, no - adding them together would not build up a query string.
If this is for EF, you want to use Expression Trees, not Lambdas.
You can create and modify Expression Trees using the System.Linq.Expressions
namespace:
MSDN: System.Linq.Expressions Namespace
and
MSDN: How to: Use Expression Trees to Build Dynamic Queries
It is a creative effort to chain predicates and too bad it does not work. The reason why has been explained excellently by Lasse and Nicholas (+2). But you also ask:
Anyone got a better suggestion?
The drawback of compiled expressions is that they're not expressions any more and thus, can't be used with IQueryable
s that are backed by SQL query providers (like linq to sql or linq to entities). I assume _repo.Customers
is such an IQueryable
.
If you want to chain expressions dynamically, LINQKit's PredicateBuilder is an excellent tool to do this.
var pred = Predicate.True<Customer>();
pred = pred.And(c => c.lastname.Equals(_customer.lastName, StringComparison.InvariantCultureIgnoreCase);
pred = pred.And(c => c.firstname.Equals(_customer.firstName, StringComparison.InvariantCultureIgnoreCase);
pred = pred.And(c => c.DOB.ToString("yyyyMMdd").Equals(_customer.DOB.ToString("yyyyMMdd"));
var customersFound = _repo.Customers.Where(pred.Expand());
This is what the Expand
is for:
Entity Framework's query processing pipeline cannot handle invocation expressions, which is why you need to call AsExpandable on the first object in the query. By calling AsExpandable, you activate LINQKit's expression visitor class which substitutes invocation expressions with simpler constructs that Entity Framework can understand.
Or: without it an expression is Invoke
d, which causes an exception in EF:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
BTW. If you use linq to sql/entities you may as well use c.lastname == _customer.lastName
because it is translated into SQL and the database collation will determine case sensitiveness.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With