Assignment in lambda expression - c#

I want to define some lambda expression that represent updates of properties of instances of a class.
I try to write that as below:
Expression<Action<User>> update = user => user.Name = "Joe Foo";
But I have a compilation error:
Error CS0832
An expression tree may not contain an assignment operator.
How to represent this update with a lambda.
EDIT
My goal is for a business service to send updates to a generic repository. This repository could analyze the expression of the lambdas to build query to send to the database engine.
An example of a business service could be:
public void DoStuff(String userId, ...)
{
// Business logic here
// ...
// Persist updates determined above
this.repository.Update(
// First parameter is the filter of entities to updates
x => x.Id == userId,
// Next parameters are updates to apply
x => x.FirstName = "John",
x => x.LastName = "Foo",
...);
}

I want to define some lambda expression that represent updates of properties of instances of a class.
You can't always get what you want.
We designed expression-tree lambdas to represent non-mutating operations, so using =, +=, ++ and so on in an expression-tree lambda is illegal.
How to represent this update with a lambda?
Delegate lambdas have no such restriction; you can say
Action<User> update = user => user.Name = "Joe Foo";
Can you say more about why you need this? There might be a better way to achieve your goal. You may be asking an XY question. That is a question where you have a problem, you have a bad solution, and now you are asking a question about the bad solution instead of about the problem. What's the problem you're trying to solve?

As others have said, C# does not allow assignment expressions in expression trees.
An alternative approach would be to use a new expression. This would allow to express the update with a single lambda:
repository.Update(
x => x.Id == userId, // Where clause
x => new User{ // Update expression
Modified = DateTime.Now,
ModifiedBy = "John",
Amount = x.Amount + 10
}
);
where x represents the old state of the entity in the update expression.
void Update(Expression<Func<T, bool>> filter, Expression<Func<T, T>> update)
If you don't need to reference the old value, you can use this simplified signature (according to your comment):
void Update(Expression<Func<T, bool>> filter, Expression<Func<T>> update)

It is hard to guess how you want to use your Expression.
If you want to dive deep into reflections, maybe this snippet will help:
var user = new User();
var paramExpr = Expression.Parameter(typeof(User), "user");
var propertyExpression = Expression.Property(paramExpr, "Name");
Expression.Lambda<Action<User>>(
Expression.Assign(
propertyExpression,
Expression.Constant("Joe Foo")
),
new List<ParameterExpression>() { paramExpr }
).Compile()(user);
Console.WriteLine(user.Name); //Joe Foo
In there you:
1) Define the ParameterExpression - your input;
2) Set up how to get to the property of the class that you are interested (.Name)
3) Finally, define the expression (and compile-call it) to do stuff wqith a test user variable

Related

How could I generate a c# .NET core function that can mimic the Include().ThenInclude.(Where) behaviour?

I'm trying to create a generic blazor component that and has a config object.
So far I've been able to successfully mimic .Where(), .Include().ThenInclude() separately, but now I need to add condition to the include.
My config file has the following structure
class Config
{
public List<string> includes {get;set;}
public List<Expression<Func<T,bool>>> conditions {get;set;}
}
database structure
For the example lets assume the following structure.
Dataset (1)<--(n) DatasetItem
DatasetItem (1)-->(1) Image
DatasetItem (1)-->(1) Label
Image (1)<--(n) Labels
Label(1)<--(n) Tags
where an image can be a part of more than one dataset and it's tags might or might not be included in the same dataset. Imagine an picture of a city park with dogs, people, and cars. Someone would want a dataset of vehicles and consider only the cars and ignore the labels about animals and people.
A Label include the coordinates and one or more TagNames (vehicle, car, red, fourWheeler, etc)
what works
And I can give conditions and includes this way:
var config = new Config<DatasetItem>()
{
includes = new() {"Image", "Image.Labels", "Image.Labels.Tags"}
conditions = new() {di => di.datasetId == 1, di => di.Label.width > 100}
}
the problems and limitations of this approach
For this to work I use the .Include(str) overload, but I don't like that approach since it is prone to fail.
The other problem with this approach is a limitation on the conditions.
For example, I can not add a condition to get only the Tags that belong to a specific category.
It seems that is not possible to add a condition that would give me this filter. Best I got was with the use of All or Any, but those do not give the desire result.
config.conditions.Add(
di => di.Images.Any(i => Labels.Any(l => l.Tags.Any(t => t.Name == "vehicle"))
)
what I'm looking for
Whith regular use of Include, obtaining the desire result would be like this.
DatasetItems.Include(di => di.Images)
.ThenInclude(i => i.Labels)
.ThenInclude(l => l.Tags.Where(t => t.Name == "vehicle"))
So, is there any way to achieve this?
I thing the solution would require to use Expression Trees, Reflection, and Recursive functions using MakeGenericMethod, but I havent found a way to achive this.
the ideal solution would be to find a structure like the one for conditions
List<Expression<Func<T,something>>> that lets me add the condition in this way
includes.add(di => di.Images.Labels.Tags.Where(t => t.Name == "vehicle"))
a failed attempt
I'm including a failed attempt I took to solve this, just in case this helps to narrow down the intention and for if someone can use it for solving the problem. This attempt is far from ideal.
property was a dot-separated string, like "Image.Labels.Tags" and filter was suppoused to be the Where expression.
This function does not compile.
public static IQueryable<T> FilteredInclude<T>(this IQueryable<T> query, string property, Func<dynamic, bool> filter) where T : class
{
var type = typeof(T);
var properties = property.Split('.');
var propertyInfo = type.GetProperty(properties[0]);
var parameter = Expression.Parameter(type, "x");
var propertyExpression = Expression.Property(parameter, propertyInfo);
var lambda = Expression.Lambda(propertyExpression, parameter);
var filteredQuery = query.Where(x => filter(propertyInfo.GetValue(x)));
if (properties.Length == 1)
{
var methodInfo = typeof(QueryableExtensions).GetMethod(nameof(Include));
methodInfo = methodInfo.MakeGenericMethod(type, propertyInfo.PropertyType);
var result = methodInfo.Invoke(null, new object[] { filteredQuery, lambda });
return (IQueryable<T>)result;
}
else
{
var nextProperty = string.Join(".", properties.Skip(1));
var result = filteredQuery.FilteredInclude(nextProperty, filter);
var thenIncludeMethod = typeof(Microsoft.EntityFrameworkCore.Query.Internal.IncludeExpression)
.GetMethod("ThenInclude")
.MakeGenericMethod(propertyInfo.PropertyType);
var resultWithThenInclude = thenIncludeMethod.Invoke(result, new object[] { lambda });
return (IQueryable<T>)resultWithThenInclude;
}
}

C# Expression to use Guid bookmark

I have a requirement to work through several tables that need to be synchronized/backed up. All of these tables' classes implement ITrackModifiedDate:
interface ITrackModifiedDate
{
DateTime ModifiedDate { get; set; }
}
I need to work through these in batches, which means I need to bookmark where I last got up to. So I can sort by ModifiedDate, and just keep track of my last ModifiedDate. But there's a wrinkle in the plan: it can easily happen that multiple records have the identical ModifiedDate. That means I need a secondary identifier, and the only thing I can generically rely on being there is the key field, which is invariably a Guid.
I got some help in the Expression stuff from here, but when I tried tinkering to add in the "greater than" clause, things broke.
async Task<ICollection<T>> GetModifiedRecords<T>(DateTime modifiedSince, Guid lastId) where T : class, ITrackModifiedDate
{
var parameterExp = Expression.Parameter(typeof(T), "x");
var propertyExp = Expression.Property(parameterExp, keyField);
var target = Expression.Constant(lastId);
var greaterThanMethod = Expression.GreaterThan(propertyExp, target);
var lambda = Expression.Lambda<Func<T, bool>>(greaterThanMethod, parameterExp);
var query = db.Set<T>()
.Where(t => t.ModifiedDate > modifiedSince ||
t.ModifiedDate == modifiedSince && lambda.Invoke(t));
var orderByExp = Expression.Lambda(propertyExp, parameterExp);
var thenByMethodGeneric = typeof(Queryable)
.GetMethods()
.Single(mi => mi.Name == "ThenBy" && mi.GetParameters().Length == 2);
var thenByMethod = thenByMethodGeneric.MakeGenericMethod(typeof(T), propertyExp.Type);
// first order by date, then id
query = query.OrderBy(t => t.ModifiedDate)
.AsQueryable();
query = (IQueryable<T>)thenByMethod.Invoke(null, new object[] { query, orderByExp });
return await query.ToListAsync();
}
Attempting to run this query results in:
System.InvalidOperationException: The binary operator GreaterThan is not defined for the types 'System.Guid' and 'System.Guid'.
Oh dear. It seems Guids, like humans, don't like being compared with each other. Either that, or I'm using the wrong comparison expression.
The obvious solution that jumps to mind is to convert the Guid to a string for comparison purposes, but (a) that seems a little inefficient, and (b) I don't know how to write an Expression that converts a Guid to a string.
Is converting to a string the right way to go? If so, what Expression will do the job? If not, what's the correct approach?
The general approach is to replace the unsupported Guid operators with Guid.CompareTo(Guid) calls, e.g. instead of
guidA > guidB
use
guidA.CompareTo(guidB) > 0
In your case, replace
var greaterThanMethod = Expression.GreaterThan(propertyExp, target);
with
var compareTo = Expression.Call(propertyExp, "CompareTo", Type.EmptyTypes, target);
var greaterThanMethod = Expression.GreaterThan(compareTo, Expression.Constant(0));
This works for most of the query providers (LINQ to Objects, LINQ To Entities (EF6)). Unfortunately doesn't work with EF Core 2.x which requires a different approach. If that's the case, register the custom GuidFunctions class as explained in the linked answer, and use this instead:
var greaterThanMethod = Expression.Call(
typeof(GuidFunctions), "IsGreaterThan", Type.EmptyTypes,
propertyExp, target);

What is the "=>" sign in LINQ queries?

It's amazing how little information there is on this. I found tons of tutorials explaining LINQ, but they don't explain this particular operator:
var Results = UserFavoritesContext.UserFavorites.Select(color => color.FavoriteColor);
"x => x.y"
Can someone please explain how this works? I get the general syntax and am able to use it to make queries, but it's like doing something without knowing what you're doing.
Suppose you have a list of people, and you want to iterate over them. You would write something like:
foreach(var person in people)
{
//do something to person
}
Note how you yourself chose the name person. It could've been any word, but you basically said "process every single item of the list as my person variable".
Now look at this LINQ query:
filteredPeopleList = people.Where(person => person.Name == "John");
Again, you basically chose person as a placeholder name for every object in the original list (one at a time). The above Linq query is equivalent to
foreach(var person in people)
{
if(person.Name == "John")
{
filteredPeopleList.Add(person);
}
}
To me, x => x.y is basically saying "for every variable we process (let's call it x), please perform the following operation on it (x.y, get the y property)"
I hope that explains it.
Edit
As a commenter who now deleted his comment mentioned, this isn't exclusively used in LINQ. A lambda expression doesn't have to iterate over an IEnumerable, it can be used to process a single item.
However, LINQ is by far the most common place to encounter lambdas, and I find their use very similar to the foreach loop, which is why I picked this example.
The => operator is used in lambda expressions.
The best way to think of this is a type of syntax for writing a function, where the left side of the operator is the parameters for the function and the right side is the body of the function e.g. this is a valid use of a lambda expression where its being used like a function:
Func<int, int> incrementFunction = i => i + 1;
int incrementedNumber = incrementFunction(1);
The name i in this case is an arbitrary variable name e.g. just like you would name a functions input parameter. Notice I didnt need to declare the input parameters type because the compiler will infer it. Also notice I dont need to include the "return" keyword or enclose the function body in a code block. It doesn't necessarily need any parameters either e.g.
Action myAction = () => Console.Write("something");
myAction();
When you use it in a linq expression, think of it as though the lambda function is being called on every element in the collection (which I believe is exactly what happens with linq to objects).
It's the syntax of a Lambda expression. If it helps you to remember... in a nutshell, the argument to pass (the parameter) is on the left of the => and the method(s) that use it are on the right hand side of it.
I hope this short summary explains it enough :)
That is a lambda expression, and it can be used as a selector from an object
You can conditionally select (or another operation orderby, count, etc) when the expression is true. For example:
Say you had a list of people and their details: ID, Name, City and Profession.
You could select a single person by using lambda to search for their specific ID:
public Person GetByID(int id)
{
Person selectedPerson = people.SingleOrDefault(person => person.ID == id);
return selectedPerson;
}
Same could be applied for a select on a city, this would be:
public List<Person> GetByCity(string city)
{
List<Person> selectedPeople = people.where(person => person.City == city);
return selectedPeople;
}
The lamda expression is where you place your operation variable, so in these cases the condition upon which you select the data. You can use it as a orderby variable much in the same way, in the next example I use two lamdas to perform two seperate functions
public List<Person> GetByCity(string city)
{
List<Person> selectedPeople = people.where(person => person.city == city)
.OrderByDescending(person => person.Name);
return selectedpeople;
}
I hope this helps at all
x => x.y is Lambda Expression introduced with C# 3.0. The general syntax is
parameter => executioncode
The Lambda Expression has 3 parts:
x on left hand side is the parameter.This can be a variable,delegate or an anonymous function.
=> read as "goes to", which acts as separator
x.y is an Expression to be evaluated.
For example, the lambda expression x => x * x specifies a parameter that’s named x and returns the value of x squared (source: MSDN).
Hope this would help you.
They're called Lamda expression:
https://msdn.microsoft.com/en-us/library/bb397687.aspx
var Results = UserFavoritesContext.UserFavorites.Select(color => color.FavoriteColor);
is similar to:
List<UserFavorite> Results = new List<UserFavorite>();
foreach(var item in UserFavorites)
{
Results.Add(item.FavoriteColor);
}
This is not specific to Linq.
It is the way you write a lambda expression.
The arrow => is the delimiter between your lambda parameters and its body.

How to create C# LambdaExpression that returns anonymous type for SelectMany resultSelector

I'm building a dynamic query that can have n of Where method calls and n of SelectMany calls dependent upon user input. For example I may have:
var qZ = entityContext.TableA
.SelectMany(a=>a.TableB, (a,t)=>new{a,t} )
.Where(a=>a.t.FieldID==21)
.Where(a=> EntityFunctions.Left(a.t.Value,1)=="p")
.SelectMany(a=>a.a.TableC, (a,t)=>new{a,t} )
.Where(a=>a.t.FieldID==22)
.Where(a=> a.a.t.Value=="Peter" && a.t.Value=="Pan")
.Where(a=> a.a.a.TypeID==3)
.Select(a=> new{ a.a.a.ItemID }
).Distinct();
In the method I'm writing, I use helper methods that return an IQueryable as seen in the return line below.
return query.Provider.CreateQuery(
Expression.Call(typeof(Queryable),
"Where",
new Type[] {query.ElementType},
query.Expression, predicateLambda)
);
I'm able to create LambdaExpressions for all of the various query attribute-value pairs required, but I am unable to create one for the resultSelector of Queryable.SelectMany.
How can we create (a,t) => new{a=a, t=t} in an expression tree? Or How do we accomplish the same result as the .SelectMany above using Expression.Call like below?
Expression.Call(typeof(Queryable),
"SelectMany",
????????,
????????
);
I've tried using the SelectMany overload that doesn't require the resultSelector which works to some degree, however, I don't know how to reference the properties of t in subsequent method calls.
I've found this lambda expression ((a,t) => new{a=a, t=t}) associated with SelectMany all over the web, but I can't find any example of how to convert it to an expression tree.
UPDATE:
Let's reframe the question. I can pass the lambda like this
var q = entityContext.TableA.AsQueryable();
var q1 = Queryable.SelectMany(q, a => a.TableB, (a, t) => new { a = a, t = t });
var q2 = Queryable.Where(q1,a=>a.t.FieldID==22);
That works, however, since I don't know ahead of time how many SelectMany need to be called and since each call changes to anonymous type of the IQueriable, is there a way to cast (and re-cast) the anonymous type to a single variable? This way I can loop through and apply whatever method necessary to the variable and then enumerate to get the results once the query is built. Something like:
var q = entityContext.TableA..AsQueryable();
q = Queryable.SelectMany(q, a => a.TableB, (a, t) => new { a = a, t = t });
q = Queryable.Where(q,a=>a.t.FieldID==22);
(BTW: This doesn't work)
The way that I ended up resolving this required a paradigm shift. The first query above was based upon the fact that I learned to write queries by joining all the tables I needed together to give me access to filter on and select fields in those tables.
SelectMany() creates joins and the box around my thinking at the time required that if I need to filter on a specific column in a table, I had to join that table to my query. This in turn changed the type of my IQueryable resulting in my not being able to predict the Type of the IQueryable at design time.
Answer:
Step 1: Set the type of IQueryable to the output type it needs to return. In the case above, the result was always IQueryable.
Step 2: Utilize Expressions to dynamically create the WHERE predicate, including any and all tables necessary to create the proper filter. This always returns Expression> and all of the other variables we easily accounted for. And rememeber, in EF it isn't necessary to join table outside of Where() if they are only needed in Where().

Lambda expression syntax

Is it mandatory that lambda expression need to use when LINQ will be used, or are lambda expressions optional?
In lambda expressions, the sign => is always used. What does it mean?
customers.Where(c => c.City == "London");
Here c => is used but why?
What kind of meaning of using c =>. Please discuss in detail because I don't know lambda.
No, you don't have to use a lambda expression. For example, your Where example could be written as:
private static bool IsLondon(Customer customer)
{
return customer.City == "London";
}
...
var londoners = customers.Where(IsLondon);
That's assuming LINQ to Objects, of course. For LINQ to SQL etc, you'd need to build an expression tree.
As to why "=>" is always used in a lambda expression, that's simply because that's the way the operator is written - it's like asking why "+" is used for addition.
A lambda expression of "c => ..." is effectively giving the lambda expression a parameter called c... in this case generic type inference provides the type of c. The body provides either an action to perform or some calculation to return a value based on c.
A full-blown description of lambda expressions is beyond the scope of this answer. As a blatant plug for my book, however, they're covered in detail in chapter 9 of C# in Depth.
The lambda expression
c => c.City == "London"
is shorthand for something like
bool IsCustomerInLondon(Customer c)
{
return (c.City == "London");
}
It's just a very concise way of writing a simple function that returns a value. It's called an "anonymous function" because it's never assigned a name or a formal definition (the parameter types and the return type are inferred from the context).
(Actually, it's not just shorthand; lambda expressions are related to some other constructs called closures, which are very cool and powerful tools.)
Think about lambdas as anonymous of functions.
I'll try to explain it with following code.
public bool IsLondon(Customer customer)
{
return customer.City == "London";
}
Now we strip down function name and get rid of braces:
public bool Customer customer
return customer.City == "London";
We don't need return type, because compiler is able to deduce type from expression:
customer.City == "London";
In the same manner compiler knows about input type, so we don't need to specify it.
So basically, what we left with is
customer
return customer.City == "London";
And lambda syntax in c# is basically:
(parameter list) => "expression"
You can also write "multi-line" expressions, but then you have to surround your code with curly braces. Also you will need to use "return" statement, like you usually do.
Jon already answered,
but I'd like to add this.
In the example you have given, imagine Linq looping over all customers,
and c is simply a reference to each item in the enumerable:
var result = new List<Customer>();
foreach(var c in customers)
{
if (c.City == "London")
result.Add(c);
}
return result;
It's a variable like any other, it does not have to be a single named one,
but it's just a convention of some sort.
you do not need to use lambda expressions on Lİnq to sql or Entities; here is an alternative way of your code;
you code :
customers.Where(c => c.City == "London");
the other way;
var query = from cs in customers
where cs.City == "London"
select cs;
this is the another way. it is up to you.
Lambda and linq are quite separate. You can use one without using the other (there are parts of linq that depend on lambda expressions, but we want to keep it simple :-) )
A lambda expression is an anonymous
function that can contain expressions
and statements, and can be used to
create delegates or expression tree
types.
This was from MSDN. (http://msdn.microsoft.com/en-us/library/bb397687.aspx )
To make it short (it's much more complex) you can use a lambda expression to make a local function. what you put before the => (in your example the c) will be the parameter of the function. The return type is "discovered" by the C# compiler.
c => c.City == "London" is nearly equivalent to:
delegate (TheObjectTypeOfC c) {
return c.City == London
};
(the difference is that some lambda expression are delegates and also expressions, but please ignore this, you won't need it for some time)
If/when the compiler isn't able to infer the types of the parameters, you can force them: (MyObject p) => p.SomeProperty != null. Here you are telling the compiler that p is a parameter.
While here I showed you what are called "expression lambdas", you can even do "statement lambdas":
p => {
for (int i = 0; i < 10; i++) {
if (p.SomeProperty == 0) {
return true;
}
}
return false;
}
(I won't tell you what are the "behind the scenes" differences between expression lambdas and statement lambdas. If you want to know them, read the msdn page I pointed before)
No it is not necessary at all.
We have two ways to write LINQ queries.
One is query method and other is builder method. You only need to put lambda expression in case of builder method.
For example, if we want to find all those students from some Students object that have more marks than 70.
but we can do this thing in LINQ with following syntax
var data = from p in stdList
where p.marks > 70
select p;
or
var data = stdList.Where(p=>p.marks > 70);
later approach is builder method, in Where function, we are passing lambda expressions.
Lambda expressions are just short cuts of doing things you can always use LINQ queries but if you want to avoid whole query syntax for just applying a simple condition you can just use LINQ builder methods (which asks for lambda expressions) in lambda expressions, you always define some alias and then perform your operation.
As far as => operator is concerned, It works just like assignment operator.
For example:
(p) => p.Gender == “F”
It means “All persons p, such that person’s Gender is F”
In some literature this is called “predicate”. Another literature terminology is “Projection”
(p) => p.Gender ? “F” : “Female”
“Each person p becomes string “Female” if Gender is “F””
This is projection, it uses ternary operator.
Although i explained with very basic examples but i hope this would help you . . . :)

Categories