So I have a code like this:
foreach (var optionValues in productOption.ProductOptionValues)
{
if (optionValues.ProductOptionValueID > 0)
{
unitOfWork.ProductContext.Entry(optionValues).State = EntityState.Modified;
}
else
{
unitOfWork.ProductContext.Entry(optionValues).State = EntityState.Added;
}
}
The code review for this was that I should look at using LINQ to do this.
Can someone please point me to a resource that can explain using LINQ to change the object properties?
You don't. Simple as that.
The code review for this was that I should look at using LINQ to do this and avoid the foreach.
Tell the code reviewer he is wrong. LinQ is for Querying data. You are updating data. Stay with your foreach loop, it's fine.
LINQ is for querying. You are modifying values, so foreach is perfectly fine here.
The best you could do is this:
var query =
from optionValues in productOption.ProductOptionValues
select new
{
entry = unitOfWork.ProductContext.Entry(optionValues),
value = optionValues.ProductOptionValueID > 0
? EntityState.Modified
: EntityState.Added
};
foreach (var x in query)
{
x.entry.State = x.value;
}
But I don't think that this really gives you much in terms of readability.
The only reasonable use of LINQ here (and it depends on the type of ProductOptionValues) is to filter the results using Where, which essentially replaces your if statement, but it's not better than your current code:
foreach (var option in productOption.ProductOptionValues.Where(x => x.ProductOptionValueID > 0)
unitOfWork.ProductContext.Entry(optionValues).State = EntityState.Modified;
foreach (var option in productOption.ProductOptionValues.Where(x => x.ProductOptionValueID <= 0)
unitOfWork.ProductContext.Entry(optionValues).State = EntityState.Added;
You should not use the LINQ ForEach extension. Let me explain why:
The LINQ foreach violates the functional programming principles that all the other sequence operators are based upon.
Clearly the sole purpose of a call to this method is to cause side effects. The purpose of an expression is to compute a value, not to cause a side effect.
The purpose of a statement is to cause a side effect. The call site of this thing would look an awful lot like an expression
The second reason is that using it adds zero representational value to your code. Doing this lets you rewrite this perfectly clear code:
foreach(Foo foo in foos){ statement involving foo; }
into this code:
foos.ForEach((Foo foo)=>{ statement involving foo; });
which uses almost exactly the same characters in slightly different order. And yet the second version is harder to understand, harder to debug, and introduces closure semantics, thereby potentially changing object lifetimes in subtle ways.
The above is in parts a summary of a blog Post from Eric Lippert. Read the full post here.
What is more the Extension has been removed by the BCL Team in Windows 8:
List.ForEach has been removed in Metro style apps. While the method seems simple it has a number of potential problems when the list gets mutated by the method passed to ForEach.
Instead it is recommended that you simply use a foreach loop.
Assuming productOption.ProductOptionValues is an IList<>() (if it isn't you might need to do a .ToList() before the .ForEach), it would be something like this:
productOption.ProductOptionValues.ForEach(x =>
unitOfWork.ProductContext.Entry(x).State = (
(x.ProductOptionValueID > 0) ? EntityState.Modified : EntityState.Added)
)
... but I don't think that's really an improvement. Quite the opposite, in fact.
Really, don't do this.
Tricky, just for the humor, it is possible in several ways, such as:
var sum = productOption.ProductOptionValues.Select(
optionValues => unitOfWork.ProductContext.Entry(optionValues).State = (optionValues.ProductOptionValueID > 0 ? EntityState.Modified : EntityState.Added).Sum();
Related
For most of the time I am using All(and returns true) instead of ForEach. Is it a good practice to use ALL instead of ForEach all the time(in case of IEnumerable), I understand All could be run on IEnumerable whereas foreach runs only on list
var wells = GlobalDataModel.WellList.Where(u => u.RefProjectName == project.OldProjectName);
if (wells.Any())
{
wells.All(u =>
{
u.RefProjectName = project.ProjectName;
return true;
});
}
var wellsList = GlobalDataModel.WellList.Where(u => u.RefProjectName == project.OldProjectName).ToList();
wellsList.ForEach(u => u.RefProjectName = project.ProjectName);
Nope, You're abusing the All method. Take a look at documentation
Determines whether all elements of a sequence satisfy a condition.
It should be used to determine all elements are true/false based on some condition, It is not meant to used to produce side effects.
List.ForEach is meant to be used for side effects. You may use it if you already have List<T> upfront. Calling ToList and creating new List just for the sake of List.ForEach is not worth. It adds another O(n) operation.
In short don't use All for side effects, List.ForEach is barely acceptable when you have list already. Recommended way is use loop of your choice, nothing can be better than that.
Ericlippert has something to say about ForEach, note that it is removed in ModernUI apps, may be removed in desktop version of .net too.
If you're checking whether all elements satisfy some condition, use All.
But, if you need to perform some operation on each element, don't use All or any other LINQ predicate (Where, Select, Any, etc.), as they are meant to be used in a purely functional way. You can iterate over the elements using a foreach .. in loop or if you prefer with the List<T>.ForEach method. However as you mention it is part of List<T> and makes your code slightly harder to change (e.g. from list to another enumerable).
See here for a discussion about the "right way" to use LINQ.
For example, you can write your code like this:
foreach (var u in GlobalDataModel.WellList
.Where(u => u.RefProjectName == project.OldProjectName))
{
u.RefProjectName = project.ProjectName;
}
It's more obvious that side effects are being done. Also, this will only iterate once over the sequence, skipping the elements that don't satisfy the condition.
I am using this solution to do a chained null check in my code
Cleaner way to do a null check in C#?
I was just wondering cant we make it like this.
bool returnValue = Helper.IsNull(nullPerson.contact.address.city);
Wouldn't that be even more cleaner ?
I tried writing such a generic function
public static bool IsNull<T>(this T rootObj)
{
var visitor = new IsNullExpressionVisitor();
//...
//...
}
but then I got stuck on how to make expression out of this rootObject.
One way to approach this (although still somewhat clunky) is to use a construct that's sometimes called a "Maybe" monad.
Using that, the code would become something like this (which you may or may not prefer!):
string city = nullPerson.With(x => x.address)
.With(x => x.city);
However, rejoice because C# is getting the "Safe Navigation" operator (?.) in the next version*.
With this new ?. operator, the code would look like this:
city = nullPerson?.address?.city;
(*Allegedly...)
After reading many questions trying to solve the same problem, I would go out on a limb and say that there is currently no way to create really elegant chained null check, where elegant would mean not adding indirection to each component of the chain.
Wrapping the chain in a lambda evaluation is perhaps the least terrible way to do it at the time, and it would only work in:
CheckNull<string>(() => nullPerson.contact.address.city);
T CheckNull<T>(Func<T> f) { try { return f(); } catch { return default(T); } }
I'd rather encourage you to try and follow the Law of Demeter that says that your object shouldn't know about the inner workings of the objects it is working with and ask them to return the value any way they want to instead of going down the class tree.
No there isn't. All the existing solutions I have seen are far more horrible than the problem. A lot of the clever solutions just make it difficult for other people to understand what the code is doing.
The situation is that you want to do something like this:
city = selectedPerson.Contact.Address.City;
What you can do is encapsulate the checks in a property
City SelectedCity
{
get
{
if (selectedPerson == null || selectedPerson.Contact == null || selectedPerson.Contact.Address == null)
return null;
return selectedPerson.Contact.Address.City;
}
}
After-all by the very nature of wanting to access this long chain of properties you do have a concept of a selected City. The code isn't elegant but at least it's hidden away in one place and anyone reading it can immediately grasp what a "SelectedCity" is.
Check my answer here
https://stackoverflow.com/a/34086283/4711853
you could simply write small extension method, which afford you to write chained lambda like this:
var val = instance.DefaultOrValue(x => x.SecondInstance) .DefaultOrValue(x => x.ThirdInstance) .DefaultOrValue(x => x.Value);
you may name this method shortier
I am trying to evolve my understanding of side effects and how they should be controlled and applied.
In the following List of flights, I want to set a property of each flight satisfying a conditions:
IEnumerable<FlightResults> fResults = getResultsFromProvider();
//Set all non-stop flights description
fResults.Where(flight => flight.NonStop)
.Select(flight => flight.Description = "Fly Direct!");
In this expression, I have a side effect on my list. From my limited knowledge I know for ex. "LINQ is used for queries only" and "There are only a few operations to lists and assigning or setting values is not one of them" and "lists should be immutable".
What is wrong with my LINQ statement above and how should it be changed?
Where can I get more information on the fundamental paradigms on the scenario I have described above?
You have two ways of achieving it the LINQ way:
explicit foreach loop
foreach(Flight f in fResults.Where(flight => flight.NonStop))
f.Description = "Fly Direct!";
with a ForEach operator, made for the side effects:
fResults.Where(flight => flight.NonStop)
.ForEach(flight => flight.Description = "Fly Direct!");
The first way is quite heavy for such a simple task, the second way should only be used with very short bodies.
Now, you might ask yourself why there isn't a ForEach operator in the LINQ stack. It's quite simple - LINQ is supposed to be a functional way of expressing query operations, which especially means that none of the operators are supposed to have side effects. The design team decided against adding a ForEach operator to the stack because the only usage is its side effect.
A usual implementation of the ForEach operator would be like this:
public static class EnumerableExtension
{
public static void ForEach<T> (this IEnumerable<T> source, Action<T> action)
{
if(source == null)
throw new ArgumentNullException("source");
foreach(T obj in source)
action(obj);
}
}
One problem with that approach is that it won't work at all. The query is lazy, which means that it won't execute the code in the Select until you actually read something from the query, and you never do that.
You could come around that by adding .ToList() at the end of the query, but the code is still using side effects and throwing away the actual result. You should use the result to do the update instead:
//Set all non-stop flights description
foreach (var flight in fResults.Where(flight => flight.NonStop)) {
flight.Description = "Fly Direct!";
}
Your LINQ code does not "directly" violate the guidelines you mention, because you are not modifying the list itself; you are just modifying some property on the contents of the list.
However, the main objection that drives these guidelines remains: you should not be modifying data with LINQ (also, you are abusing Select to perform your side effects).
Not modifying any data can be justified pretty easily. Consider this snippet:
fResults.Where(flight => flight.NonStop)
Do you see where this is modifying the flight properties? Neither will many maintenance programmers, since they will stop reading after the Where -- the code that follows is obviously free of side effects since this is a query, right?
[Nitpick: Certainly, seeing a query whose return value is not retained is a dead giveaway that the query does have side effects or that the code should have been removed; in any case, that "something is wrong". But it's so much easier to say that when there are only 2 lines of code to look at instead of pages upon pages.]
As a correct solution, I would recommend this:
foreach (var x in fResults.Where(flight => flight.NonStop))
{
x.Description = "Fly Direct!";
}
Pretty easy to both write and read.
There is nothing wrong with it perse, except that you need to iterate it somehow, like calling Count() on it.
From a 'style' perspective it is not good. One would not expect an iterator to mutate a list value/property.
IMO the following would be better:
foreach (var x in fResults.Where(flight => flight.NonStop))
{
x.Description = "Fly Direct!";
}
The intent is much clearer to the reader or maintainer of the code.
You should break that up into two blocks of code, one for the retrieval and one for setting the value:
var nonStopFlights = fResults.Where(f => f.NonStop);
foreach(var flight in nonStopFlights)
flight.Description = "Fly Direct!";
Or, if you really hate the look of foreach you could try:
var nonStopFlights = fResults.Where(f => f.NonStop).ToList();
// ForEach is a method on List that is acceptable to make modifications inside.
nonStopFlights.ForEach(f => f.Description = "Fly Direct!");
I like using foreach when I'm actually changing something. Something like
foreach (var flight in fResults.Where(f => f.NonStop))
{
flight.Description = "Fly Direct!";
}
and so does Eric Lippert in his article about why LINQ does not have a ForEach helper method.
But we can go a bit deeper here. I am philosophically opposed to providing such a method, for two reasons.
The first reason is that doing so violates the functional programming principles that all the other sequence operators are based upon. Clearly the sole purpose of a call to this method is to cause side effects.
I need a help with simpify this statement. How to change foreach to lambda
var r = mp.Call(c => c.GetDataset()); // returns IEnumerable of dataset
foreach (DatasetUserAppsUsage item in r)
{
datasetUserAppsUsage.Merge(item.AppsUsageSummary);
}
lambdas and loops are orthogonal. It is inappropriate to try to change them to brute-force one into the other. That code is fine. Leave it.
You can get .ForEach implementations, but it isn't going to make the code better (in fact, it will be harder to follow, i.e. worse), and it won't be more efficient (in fact, it will be marginally slower, i.e. worse).
You can do the following
r.ToList().ForEach(item => datasetUserAppsUsage.Merge(item.AppsUsageSummary);
Personally, I don't think I would merge this into a single lambda. You could do:
mp.Call(c => c.GetDataset()).ToList().ForEach(item => datasetUserAppsUsage.Merge(item.AppsUsageSummary));
However, I would avoid it, as it's purposefully causing side effects, which really violates the expectations of LINQ, and is not very clear in its intent.
I agree that lambdas purpose it different, but sometimes I use this trick:
mp.Call(c => c.GetDataset())
.All(a => { datasetUserAppsUsage.Merge(a.AppsUsageSummary); return true; });
The trick is to use All() and return true to avoid break.
And do not change the underlying collection when inside enumerator of course :)
I was hoping someone could explain to me what bad thing could happen in this code, which causes ReSharper to give an 'Access to modified closure' warning:
bool result = true;
foreach (string key in keys.TakeWhile(key => result))
{
result = result && ContainsKey(key);
}
return result;
Even if the code above seems safe, what bad things could happen in other 'modified closure' instances? I often see this warning as a result of using LINQ queries, and I tend to ignore it because I don't know what could go wrong. ReSharper tries to fix the problem by making a second variable that seems pointless to me, e.g. it changes the foreach line above to:
bool result1 = result;
foreach (string key in keys.TakeWhile(key => result1))
Update: on a side note, apparently that whole chunk of code can be converted to the following statement, which causes no modified closure warnings:
return keys.Aggregate(
true,
(current, key) => current && ContainsKey(key)
);
In that particular code nothing, take the following as an example:
int myVal = 2;
var results = myDatabase.Table.Where(record => record.Value == myVal);
myVal = 3;
foreach( var myResult in results )
{
// TODO: stuff
}
It looks like result will return all records where the Value is 2 because that's what myVal was set to when you declared the query. However, due to deferred execution it will actually be all records where the Value is 3 because the query isn't executed until you iterate over it.
In your example the value isn't being modified, but Resharper is warning you that it could be and that deferred execution could cause you problems.
When you modify the result variable, the closure (the use of the variable inside the lambda expression) will pick up the change.
This frequently comes as an unexpected surprise to programmers who don't fully understand closures, so Resharper has a warning for it.
By making a separate result1 variable which is only used in the lambda expression, it will ignore any subsequent changes to the original result variable.
In your code, you're relying on the closure picking up the changes to the original variable so that it will know when to stop.
By the way, the simplest way to write your function without LINQ is like this:
foreach (string key in keys) {
if (ContainsKey(key))
return true;
}
return false;
Using LINQ, you can simply call Any():
return keys.Any<string>(ContainsKey);
See
http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/
for an extensive discussion of this issue and what we might do in hypothetical future versions of C# to mitigate it.
I'm not sure if ReSharper will give the exact same warning for this, but the following illustrates a similar situation. The iterator for a loop is used in a LINQ clause, but the clause isn't actually evaluated until after the loop has finished, by which time the iterator variable has changed. The following is a contrived example that looks like it should print all odd numbers from 1 to 100, but actually prints all numbers from 1 to 99.
var notEven = Enumerable.Range(1,100);
foreach (int i in Enumerable.Range(1, 50))
{
notEven = notEven.Where(s => s != i * 2);
}
Console.WriteLine(notEven.Count());
Console.WriteLine(string.Join(", ", notEven.Select(s => s.ToString()).ToArray()));
This can be quite an easy mistake to make. I've heard people say that if you truly understand closures/functional programming/etc. you should never make this mistake. I've also seen professional developers who certainly do have a good grasp of those concepts make this exact mistake.
Well, the warning is because result could be changed before the closure is executed (variables are taken at execution, not defition). In your case, you are actually taking advantage of that fact. If you use the resharper reccomodation, it will actually break your code, as key => result1 always returns true.