This question already has answers here:
Understanding how lambda expression works [closed]
(4 answers)
Closed 3 years ago.
[Route("{year:min(2000)}/{month:range(1,12)}/{key}")]
public IActionResult Post(int year, int month, string key)
{
var post = _db.Posts.FirstOrDefault(x => x.Key == key);
return View(post);
}
Hi,
I'm doing this in ASP.NET Core with C#.
Vague part for me is this: _db.Posts.FirstOrDefault(x => x.Key == key);
So what I'm guessing is that:
execute FirstOrDefault method.
parameter x is passed (I don't what it is being passed exactly though).
then, compare x.Key with key
what is next step?
parameter x is passed (I don't what it is being passed exactly though).
No, this does not happen. What is passed is an expression defining an anonymous function. Such expressions, when using the => operator, are commonly called lambda expressions. x is the part of the expression which determines how the function is called. It's a placeholder for the input variable used by the function expression.
It will help you understand if I give you a pretend version of how the FirstOrDefault() method might be implemented:
public T FirstOrDefault<T>(this IEnumerable<T> items, Func<T, boolean> predicate)
{
foreach(T item in items)
{
if(predicate(item)) return item;
}
return default(T);
}
Some things to understand in that code:
this in front of the first parameter turns the function into an extension method. Instead of calling the method with two arguments, you skip the first argument... call it with only the second argument as if it were a member of the type from the first argument. ie, _db.Posts.FirstOrDefault(foo) instead of FirstOrDefault(_db.Posts, foo).
The key variable in the expression is called a closure. It is available as part of the predicate() function inside this method, even though it's not passed as an argument. This is why the predicate(item) call is able to determine true or false with only item as an input.
The predicate() function call within this method was passed as an argument to the method. That is how the x => x.Key == key argument is interpreted; it becomes the predicate() method used by the FirstOrDefault() function. You can think of it as if predicate() were defined like this:
bool predicate(T x)
{
return x.Key == key;
}
The C# compiler makes this translation for you automatically, and even infers the correct run-time type for T and automatically handles scope for the key closure.
The other answers are close, but not completely correct.
I assume that _db is an Entity Framework DbContext, and _db.Posts is a DbSet<Post>.
As such the .FirstOrDefault() method you are seeing is actually an Extension method and the x => x.Key == key part is an Expression tree.
What happens behind the scenes is that the call to _db.Posts.FirstOrDefault(x => x.Key == key) is translated to a SQL statement like SELECT TOP(1) Key, Content, ... FROM posts WHERE Key = #key, the result of which is mapped into a Post entity.
There are a lot of language features at play to make all this work, so let's have a look!
Extension methods
Extension methods are static methods, but can be called like instance methods.
They are defined in static classes and have a 'receiver' argument. In the case of FirstOrDefault the extension method looks like this:
public static class Queryable {
public static T FirstOrDefault<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate = null) {
// do something with source and predicate and return something as a result
}
}
It's usage _db.Posts.FirstOrDefault(...) is actually syntactic sugar and will be translated by the C# compiler to a static method call a la Queryable.FirstOrDefault(_db.Posts, ...).
Note that extension methods are, despite the syntactic sugar, still static methods do not have have access to their receiver's internal state. They can only access public members.
Delegates
C# has support for pseudo-first-class functions, called delegates. There are several ways to instantiate a delegate.
They can be used to capture existing methods or they can be initialized with an anonymous function.
The most elegant way to initialize a delegate with an anonymous function is to use lambda style functions like x => x + 10 or (x, y) => x + y.
The reason you don't see type annotations in these examples is that the compiler can infer the types of the arguments in many common situations.
Here is another example:
// This is a normal function
bool IsEven(int x) {
return x % 2 == 0;
}
// This is an anonymous function captured in a delegate of type `Func<T1, TResult>`
Func<int, bool> isEven = x => x % 2 == 0;
// You can also capture methods in delegates
Func<int, bool> isEven = IsEven;
// Methods can be called
int a = IsEven(5); // result is false
// Delegates can be called as well
int b = isEven(4); // result is true
// The power of delegates comes from being able to pass them around as arguments
List<int> Filter(IEnumerable<int> array, Func<int, bool> predicate) {
var result = new List<int>();
foreach (var n in array) {
if (predicate(n)) {
result.Add(n);
}
}
return result;
}
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
var evenNumbers = Filter(numbers, isEven); // result is a list of { 2, 4, 6 }
var numbersGt4 = Filter(numbers, x => x > 4); // result is a list of { 5, 6 }
Expression trees
The C# compiler has a feature that allows you to create an Expression tree with normal-looking code.
For example Expression<Func<int, int>> add10Expr = (x => x + 10); will initialize add10Expr not with an actual function but with an expression tree, which is an object graph.
Initialized by hand it would look like this:
Expression xParameter = Expression.Parameter(typeof(int), "x");
Expression<Func<int, int>> add10Expr =
Expression.Lambda<Func<int, int>>(
Expression.Add(
xParameter,
Expression.Constant(10)
),
xParameter
);
(which is super cumbersome)
The power of expression trees comes from being able to create, inspect and transform them at runtime.
Which is what Entity Framework does: it translates these C# expression trees to SQL code.
Entity Framework
With all of these features together you can write predicates and other code in C# which gets translated by Entity Framework to SQL, the results of which are "materialized" as normal C# objects.
You can write complex queries to the database all within the comfort of C#.
And best of all, your code is statically typed.
The x is the range variable of the object you called the function on. The same object you would get in foreach (var x in _db.Posts) It then iterates through that collection looking for x.Key == key and returns the first object that fulfills that. So that function will return the first object in db.Posts where Key == key
edit: corrected term
Your lambda expression with FirstOrDefault is equivalent to the following extension method
public static Post FirstOrDefault(this YourDBType _db, string Key)
{
foreach(Post x in _db.Posts)
{
if(x.Key == Key)
{
return x
}
}
return null
}
X isn't an parameter, its just a shorthand way of referring to the individual item in the collection you are working on like we would have in a foreach statement. The last step in your question is "either return the first Post that has the same key we are comparing against, or return the default value of a Post object (which is null for objects)"
Related
TLDR: How does this compile?
class A{};
Expression<Func<A, int>> e = x => 24; // I don't understant what makes this compile
// and what happens at this assignment
What is the minimum class E to be able to compile E e = x => 24;
Some investigation
class E {};
E e = x => 24;
Visual Studio error is "Cannot convert lambda expression to type 'E' because it is not a delegate type" which is confusing because as far as I know a delegate is declared like this:
int delegate MyHandle();
and I didn't find any way of making a class a delegate.
Furthermore I have looked at the metadata of Expression -> LambdaExpression -> Expression<TDelegate> and wasn't able to identify what syntax/declaration makes Expression<TDelegate> act like a delegate.
Even more I have tried to create my own class E to mimic Expression<TDelegate> and I wasn't even able to compile the class
// basically a copy-paste of the metadata of `Expression<TDelegate>`
public sealed class E<TDelegate> : LambdaExpression
{
public TDelegate Compile() => default(TDelegate);
public TDelegate Compile(DebugInfoGenerator debugInfoGenerator) => default(TDelegate);
public TDelegate Compile(bool preferInterpretation) => default(TDelegate);
public Expression Update(Expression body, IEnumerable<ParameterExpression> parameters)
=> default(Expression);
protected override Expression Accept(ExpressionVisitor visitor) => null;
}
getting the error "'LambdaExpression' does not contain a constructor that takes 0 arguments"
Context (can be skipped):
I am getting started with Moq and because I just cannot take things for granted I am trying to understand how it works / how it is implemented. So this the first part of a series of inquiries about that.
I am now specifically trying to understand
public class A
{
public virtual int Foo() => throw new NotImplementedException();
public virtual int Bar() => throw new NotImplementedException();
}
var a = new Mock<A>();
a.Setup(x => x.Foo()).Returns(24); // ??
Console.WriteLine(a.Object.Foo());
I am trying to understand how the information "the method Foo" is passed to a
by passing that lambda? As far as I know a lambda is just a callable object, but somehow magically a knows the actual body of the lambda, i.e. will throw if you pass x => 24 or x => x.Foo() + x.Bar() but will accept x => x.Foo()
And I see that Setup parameter is of type Expression<Func<A, int>> hence my current question.
The C# specification gives special treatment to System.Linq.Expressions.Expression<D>; you cannot get the same treatment for your own type.
Expression trees permit lambda expressions to be represented as data structures instead of executable code. Expression trees are values of expression tree types of the form System.Linq.Expressions.Expression<D>, where D is any delegate type.
Source: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/types#expression-tree-types
This is a Lambda expression:
x => 24
According to MSDN Lambda expressions a lambda expression can be used to create a delegate or an expression tree type.
A Func<T, int> is a delegate function that takes a T as input and returns an int as output. If you assign the lambda expression above to this Func, then the compiler assumes that the x in the lambda expression is the input of the Func, and the part after the => is the output of the Func:
Func<string, int> func = x => x.Length;
Here x is expected to be a string, the part after the => may use, but is not obliged to use, this x to produce the output which has to be an int.
Func<int, int> func = x => x = -x;
Here x is expected to be an int. The return of the function is -x which is also an int.
Expression is the base class of all kinds of expressions. Expressions represent an operation that return a value. The most basic expressions are constants, they represent just a constant value, like 24. Other expressions might be additions, which take as input two expressions and have one output value. Other expressions are multiplication, negation, etc, which return a "number", or boolean expressions like AND OR NOR etc which return a Boolean.
A special kind of expression (so a derived class) is a LambdaExpression. A LambdaExpression usually represents a function-like object: it has zero or more input parameters and one output parameter. You assign a value to a LambdaExpression using a lambda expression (note the space in lambda expression!):
Expression<Func<string, int>> myExpression = x => x.Length;
I wrote earlier what the lambda expression x => x.Length does. the statement above creates an object of type System.Linq.Expressions.Expression<TDelegate>, which is of type LambdaExpression, hence you can assign it to an Expression<Func<string, int>>.
Your question:
What is the minimum class E to be able to compile E e = x => 24?
Your class E will need a constructor (or assignment operator) that accepts a System.Linq.Expressions.Expression<Func<MyClass, int> as parameter. If you don't use the x from your lambda expression MyClass can be object
Of course it is also accepted if the constructor takes any of the base classes, like Expression. However, if you do so you won't be able to used any of the Expression<Func<MyClass, int> functionality.
About your Mock code
Apparently you have a class A with two functions Foo and Bar, and you want to instantiate a Mock object to mock the functionality of A.
var myAmock = new Mock<A>();
myAmock.Setup(x => x.Foo()).Returns(24);
This says, that myAmock is an object that should mock behaviour of class A. Whenever someone calls the Foo function it should return a value of 24.
Supposing I have a string which I want to convert to an integer, I would do
int i;
int.TryParse(someString, out i);
Now I would like to do the same in a Linq query:
int i;
var numbers =
from s in someStrings
where int.TryParse(s, out i)
select i;
But this refuses to compile with the error
CS0165 Use of unassigned local variable 'i'
It compiles and works as intended when I initialize i to an arbitraty value. But why do I have to?
The query expression is translated into:
var numbers = someStrings.Where(s => int.TryParse(s, out i))
.Select(s => i);
Now, we know that the delegate created from the lambda expression for the Where call will be executed before the delegate created from the lambda expression for the Select call, but the compiler doesn't. And indeed, you could easily write your own extension method that didn't obey that:
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source,
Func<T, bool> predicate)
{
// I can't be bothered to check the predicate... let's just return everything
return source;
}
At that point, with the normal Select call, your delegate returning i would be executed without every assigning a value to it.
Basically, the definite assignment rules are deliberately quite conservative, avoiding making any assumptions about what methods do etc.
This compiles to a pair of lambda expressions that are passed to Where() and Select().
The compiler does not know what Where() and Select() do, and cannot prove that Where()'s lambda will always run before Select().
The compiler cannot determine until runtime whether or not there will be any records returned. So in order for i to have a determined value, one must be explcitly assigned. Just think "what would i be if my Query returned no rows ?"
I have the following filter :
Expression<Func<Employee, bool>> fromDateFilterFourDays = z => EntityFunctions.TruncateTime(z.FiringDate) >= EntityFunctions.TruncateTime(DateTime.Now.AddDays(-4));
Expression<Func<Employee, bool>> fromDateFilterSixDays = z => EntityFunctions.TruncateTime(z.FiringDate) >= EntityFunctions.TruncateTime(DateTime.Now.AddDays(-6));
How can I make a delegate out of this filter ?
I don't want to create a variable for each given number , i.e. for four days or six days .
My understanding is that you want to:
Take in two parameters to the delegate, the employee and the number of days.
Compile that expression into a delegate.
The first part can be done by adding the days to the parameter list:
Expression<Func<Employee, int, bool>> fromDateFilter = (z, n) => EntityFunctions.TruncateTime(z.FiringDate) >= EntityFunctions.TruncateTime(DateTime.Now.AddDays(n));
The second by using the Compile method:
var del = fromDateFilter.Compile();
// use it
del(employee, -4);
You can easily turn Expression<Func<...>> to Func<...> by using Compile method.
However, keep in mind that the sample expressions you provided will not work, because they are using Canonical Functions which are just placeholders for mapping the corresponding database SQL functions, and will throw exception if you try to actually evaluate them (which will happen with Func).
From the other side, if the question is actually how to parametrize the sample expressions, it could be like this
static Expression<Func<Employee, bool>> DateFilter(int currentDateOffset)
{
return e => EntityFunctions.TruncateTime(e.FiringDate) >= DateTime.Today.AddDays(currentDateOffset);
}
This is done by calling the Invoke() method:
fromDateFilterFourDays.Invoke(employee);
Or you can Compile() the expression to a func and then call the func:
var fromDateFilterFourDaysFunc = fromDateFilterFourDays.Compile();
fromDateFilterFourDaysFunc(employee);
This code correctly returns one row:
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where t.GetInterfaces().Contains(typeof(TInterface))
&& t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`')
select t);
}
However, when I use PredicateBuilder, I get zero rows:
var compiledPredicate = CompiledPredicate<TInterface>();
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where compiledPredicate.Invoke(typeof(TInterface))
select t);
}
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
// True means all records will be returned if no other predicates are applied.
var predicate = PredicateBuilder.True<Type>();
// Get types that implement the interface (T).
predicate = predicate.And(t => t.GetInterfaces().Contains(typeof(T)));
// If the config file includes filtering by base class, then filter by it.
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
predicate = predicate.And(t => t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`'));
}
return predicate.Compile();
}
Someone suggested creating a copy of my loop variable, but I tried that and I still get zero rows. I'm not sure why using PredicateBuilder returns no rows. Any idea what I'm missing?
The change that you mentioned in comments (foundTypes.AddRange(x.GetTypes().AsQueryable().Where(compiledPredicate));) had nothing at all to do with the fact that you were using AsQueryable. In the first case you're passing in a hard coded type to each call of your predicate, in the second you're passing the given item from the sequence. Had you removed the AsQueryable and used Enumerable.Where it would also work, or had you passed the current item, rather than a hard coded type, when invoking it that would also work.
So you can simply do:
foundTypes.AddRange(x.GetTypes().Where(compiledPredicate));
Also, when creating the predicate, there's no need to do as much work as you're doing. Expressions take a fair amount of extra work to deal with. With linq to objects you only need to deal with delegates, which are much less finicky.
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
Func<Type, bool> predicate = t => t.GetInterfaces().Contains(typeof(T));
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
return t => predicate(t) &&
t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`');
}
return predicate;
}
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!
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 IQueryables 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 Invoked, 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.