I was looking at this code example in C# 7.0 and I was not sure about what was going on under the hood and the performance of this loop.
foreach (var c in text ?? throw new ArgumentNullException(nameof(text)))
{
...
}
My questions:
Does the conditional statement get hit once or multiple times (on
each iteration)?
The new syntax looks different, what are the benefits to doing it this way?
In terms of "how foreach works", conditional statement will only be calculated once.
You may want to read more about how foreach loops work in these questions:
How do foreach loops work in C#?
Does foreach evaluate the array at every iteration?
Thanks to Svek for explaining that it is a new C# 7.0 feature, which will be released after Visual Studio 2017 RC:
http://structuredsight.com/2016/09/01/c-7-additions-throw-expressions/
I think that "what are benefits" is a sort of opinion-based question.
In my opinion, it brings nothing good and is just ugly in terms or code readability.
I would recommend using a widely-used common good practice:
if (text == null) // or string.IsNullOrEmpty for strings
throw new ArgumentNullException(nameof(text));
foreach (var c in text)
{
// ...
}
Probably, we will see null-coalescing + throw exception usage in a couple years and it will become a new standard :)
You should understand foreach inner code for understanding this C# feature. A right part of expression in foreach statement must implement IEnumerable(<T>) interface, and whole loop is, internally, a simple while, something like this:
// here can be NullReferenceException
var en = text.GetEnumerator();
while(en.MoveNext())
{
var c = en.Current;
{
...
}
}
As you can see, there is a point in this code the NRE can occur, so you need to check the enumerable before entire loop or Enumerable extensions class, like this:
if (text.IsNullOrWhitespace())
{
throw new ArgumentNullException(nameof(text));
}
// while loop here or text.SomeLinqCodeHere()
There are some lines of code here which aren't really unnecessary, adding some entropy without real value. In case of simple foreach it really opinion-based decision about code standards, but the real purpose of this feature is chaining it with other new things in C#7, like ?. operator, like this:
int? length = customers?.Length ?? throw new ...;
Customer first = customers?[0] ?? throw new ...;
int? count = customers?[0]?.Orders?.Count() ?? throw new ...;
In such cases throwing the exception is similar to comment at the end of the line of code:
int? length = customers?.Length; // should not be null
Customer first = customers?[0]; // should not be null
int? count = customers?[0]?.Orders?.Count(); // should not be null
but it adds some strict contract-like rules for your code.
As for the performance for foreach loop with such expressions, as already said, it doesn't suffer as getting the enumerator occurs only once, and before the real loop.
Related
I have a rather ugly object (yeah, I need the Tuple there :) ):
var roomToIndex = new Dictionary<RoomNode, Tuple<Int32, Dictionary<GrowDirections, Int32>>>();
I initialize this Dictionary like this:
for (var i = 0; i < roomsAdjacent.Count(); i++) {
roomToIndex.Add(roomsAdjacent.ElementAt(i), new Tuple<Int32, Dictionary<GrowDirections, Int32>>(i, new Dictionary<GrowDirections, Int32>()));
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Top, 0);
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Right, 0);
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Bottom, 0);
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Left, 0);
}
Where roomsAdjacent is a List of RoomNodes and GrowDirections a [Flags] Enumerable.
After those initialization steps I increment the Integer values of the 'inner' Dictionaries and at last I want to get the GrowDirection and RoomNode with the biggest value.
I try to do that the following way (now):
///Use the Counts to determine optimal FillDirection
var rDC = roomToIndex
///Select the RoomNode and the GrowDirection (incl. Count) with the highest Count for each Room
.Select(r => new { RoomNode = r.Key, Dict = r.Value.Item2.OrderByDescending(dirCount => dirCount.Value).ToList()[0] })
///Order those RoomNodes and GrowDirections descending
///Take the first Element and used the Dict's Key (GrowthDirection)
.OrderByDescending(rGI => rGI.Dict.Value).ToList();
var rDC0 = rDC[0];
if (rDC0.Dict.Key == GrowDirections.Top || rDC0.Dict.Key == GrowDirections.Bottom)
fillDirection = GrowDirections.Top | GrowDirections.Bottom;
else
fillDirection = GrowDirections.Right | GrowDirections.Left;
foreach (var rTI in roomToIndex.Where(rTI => rTI.Key != rDC0.RoomNode))
roomCellCount[rTI.Value.Item1] = 0;
The rDC has a Type of { RoomNode, Dictionary } and I have no Problem there.
But when I debug and step to the next line:
var rDC0 = rDC[0];
The debugger skips the line, goes right to the 'if statement' and throws an error, telling me that I got a NullReferenceException??!!
When I look at the values in my 'rDC object' there is no null-Value.
What can it be? Thank you for any tip/help :)
Examining your code the type of rDC is List<KeyValuePair<RoomNode, something very complicated>. The important thing is not something very complicated but that KeyValuePair<TKey, TValue> is a value type (struct). This means that List<KeyValuePair<TKey, TValue>> cannot have elements that are null. This means that rDC0 cannot be null. This is basically also what you tell us.
But then, if you get a NullReferenceException as you describe, it must be rDC0.Dict that is null. However, the Dict property cannot be null because it has very clearly been initialized to a new Dictionary<GrowDirections, Int32> by your initialization code.
So the code you have provided in the question should not be able to exhibit the behavior your describe. Either your code is somewhat different or the behavior you get is not exactly as you describe. The debugger problem you mention could be either a result of debugging the release version or symbols being out of sync with the executable code.
I suggest that you try one or more of the following things to fix your problem:
Rebuild the solution to make sure the debugger shows the correct source code when you debug
Switch to a debug build to turn off optimizations that will make debugging confusing
Break your data and code into smaller parts to get rid of the complicated and hard to understand code you have
The last suggestion is what will solve (or has solved) your problem. Let me just give you a few pointers:
Instead of using Dictionary<GrowDiretions, Int32> you could perhaps create a type with four properties which hopefully would make it more clear what your code is doing:
class GrowCounts {
public Int32 TopCount { get; set; }
public Int32 RightCount { get; set; }
public Int32 BottomCount { get; set; }
public Int32 LeftCount { get; set; }
public GrowDirections MaxGrowDirection {
get { // Return GrowDirections.Top if TopCount has the highest count etc. }
}
}
Instead of using new Tuple<T1, T2> use Tuple.Create to let the compiler infer the types of the tuple.
Do you really need the Tuple where the first element is an index? Some of your code uses for loops with Count and ElementAt and accessing collections in that way requires an index. However, maybe you could convert these loops into foreach loops and in the process you would discover that the index is unneeded. If that was possible you could get rid of the Tuple.
Apparently (according to what you wrote) it has to do with the the complex Linq statement, which had a side-effect that is somehow leading to the null reference error, which putting it in its own function contained. You might be able to get more clues about what exactly caused that, by seeing what happens if you put a simpler Linq Select statement before the initialization. See Martin's more comprehensive later suggestion about how you could track down what's actually going on here.
I saw this loop in test code:
foreach ( StuffId Id in Result.GetIdList() )
{
if ( Id.Level == 3 )
{
Level3Id = Id.ToString();
}
if ( Id.Level == 5 )
{
Level5Id = Id.ToString();
}
}
Other tests imply that either there is only one Id for each level or when there are multiples for each level then the Id will be the same.
Being slightly obsessed with LINQ right now, I first refactored to this:
IEnumerable<StuffId> Ids = Result.GetIdList();
Level3Id = Ids.Where( x => x.Level == 3 ).First().Id.ToString();
Level5Id = Ids.Where( x => x.Level == 5 ).First().Id.ToString();
Then the code repetition bothered me so I refactored to this:
IEnumerable<StuffId> Ids = Result.GetIdList();
Func<int,string> IdFromLevel =
level => Ids.Where( x => x.Level == level ).First().Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);
A colleague wondered why I didn't use a method in place of the delegate. My reasoning is a method would be slightly more 'messy' because I'd have to additionally pass in the collection and that using a delegate is no big deal for a simple test (for which terse, readable and no branching are good qualities).
I had a look on SO, of course, and found this seemingly relevant question:
C#: Func<> instead of methods?
where the consensus seems to favour a method over a delegate. Does the same apply in my case?
It is a question of reuse. If you are using methods that might be reusable in other cases, you should define them seperately.
But if you have only short statements that additionally vary, you should stick with anonymous functions/lambda-expressions, these might result in a better runtime-behavior.
From SO:
There is no advantage in the code you posted. In your code, using the delegate just adds complexity as well as an extra runtime cost - so you're better off just calling the method directly.
However, delegates have many uses. "Passing around" to other methods is the primary usage, though storing a function and using it later is also very useful.
LINQ is built on top of this concept entirely. When you do:
var results = myCollection.Where(item => item == "Foo");
You're passing a delegate (defined as a lambda: item => item == "Foo") to the Where function in the LINQ libraries. This is what makes it work properly.
Not sure about pros and cons, but reading these articles might help you to take a better decision:
http://msdn.microsoft.com/en-in/library/bb549151.aspx
http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx
http://msdn.microsoft.com/en-in/library/98dc08ac.aspx
I would go with the first block:
foreach (StuffId Id in Result.GetIdList())
{
if (Id.Level == 3)
{
Level3Id = Id.ToString();
}
if (Id.Level == 5)
{
Level5Id = Id.ToString();
}
}
This does loop the collection only once. I see you don't worry about performance here, but for me its not a matter of performance or optimization. It's a matter of doing something logically correct way. Why do something twice if it could be in one step (provided readability is not hurt).
The added benefit is that you don't have the dilemma between Func<,> and method, and the related complexities. As far as number of characters or ease of typing goes, its almost the same, except you're writing it horizontally (in the second case) than vertically. You can even write the above in two lines inside the foreach block.
If you're bent on writing the two actions separately, I would make the choice based on whether the function has relevance outside the scope of current method in this case. It seems to me that its a trivial predicate which is relevant only for the two assignments. So I like:
var Ids = Result.GetIdList();
Func<int, string> IdFromLevel = level => Ids.Single(x => x.Level == level).Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);
Prefer Single here over First..
Reminiscent of the title of a bootleg live Rolling Stones recording of yesteryear, Resharper is sharper than I'll ever be; as I had it inspect my code, it told me this regarding closures:
1) "Loop:
foreach (var item in PlatypiIds)
{
var query = db.Table<Locations>().Where(l => l.PlatypusId == item).
Where(l=> l.SentTimeUTC >= EarliestToShow).
Where(l=> l.SentTimeUTC <= LatestToShow).
OrderBy(l => l.SentTimeUTC);
if (query != null)
{
foreach (var q in query)
{
listLocs.Add(q);
}
}
}
...can be converted into LINQ expression:
listLocs.AddRange(from item in PlatypiIds select db.Table<Locations>().Where(l => l.PlatypusId == item).Where(l => l.SentTimeUTC >= EarliestToShow).Where(l => l.SentTimeUTC <= LatestToShow).OrderBy(l => l.SentTimeUTC) into query
where query != null from q in query select q);"
...but then Resharper told me later regarding the "new and improved" code: "Access to foreach variable in closure. May have different behaviour when compiled with different versions of compiler"
So what are the possibilities of compiling with a different version of the compiler? I mean, I'm not going to go backwards, version-wise, from VS2012 to VS2010, for example...???
2) On these lines:
if (db != null)
db.Insert(new PlatypiRequested()
...of this code:
using (var db = new SQLiteConnection(SQLitePath))
{
db.CreateTable<PlatypiRequested>();
db.RunInTransaction(() =>
{
if (db != null)
db.Insert(new PlatypiRequested()
{
PlatypusId = PlatypusId,
PlatypusName = PlatypusName,
InvitationSentLocal = invitationSentLocal
});
});
}
...Resharper informs me, "Access to disposed closure"
What does that mean, and what should I do about it?
You have two different issues here, one LINQ vs foreach, and the other is a different case.
Regarding the ReSharper informing you of "Access to foreach variable in closure..." when the code is LINQified - I just never take my chances, and leave it as a foreach loop. In most cases it is also more readable and maintainable, and really, shortening the code isn't that much of a big deal.
Regarding the second case - you'll need to lose the using statement, since the db object will be disposed too soon. You should close and dispose it in the "old school fashion" INSIDE the RunInTransaction lambda expression, at the end of it.
There's a real difference which will show up in foreach loops, as well as in LINQ queries.
It has to do with the lifetime of the closure (scope) within which a variable is defined (in a foreach loop or in a LINQ expression). In some versions the variable is redefined in each iteration of the loop, and in other occasions its lifetime spans the whole execution of the loop, keeping the old value between iterations. And this can make a big difference in the results, depending on the code.
I can't explain it better than Eric Lippert (which worked for Microsoft for 16 years, developing compilers, including C# compiler):
http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
I have really seen code that behaves in a different way, depending on the traget framework (and thus on the C# version). This must be taken into account.
Most times R# is right, as in this occasion.
You could use the Linq ForEach to remove the open loop.
db.Table<Locations>().Where(l => l.PlatypusId == item).
Where(l=> l.SentTimeUTC >= EarliestToShow).
Where(l=> l.SentTimeUTC <= LatestToShow).
OrderBy(l => l.SentTimeUTC).ToList().
ForEach(q => listLocs.Add(q));
I would like to know:
What technic is that code?
Can you rewrite that code to make it more readable, because I do
not completely understand its meaning.
Paragraph para = CaretPosition.Paragraph;
var matchedRun = para.Inlines.FirstOrDefault(inline =>
{
Run run = inline as Run;
return (run != null && run.Text.EndsWith(inputText));
}) as Run;
if (matchedRun != null)
{
}
I'd say a more readable version would be:
var matchedRun = para.Inlines
.OfType<Run>()
.FirstOrDefault(r => r.Text.EndsWith(intputText));
OfType filters the input sequence on the given type (Run) and FirstOrDefault finds the first Run instance whose Text property ends with the given input (or null if none was found).
It's Linq. Do you know the "var" keyword? It's a type that the compiler knows but the programmer doesn't want to write.
The re-written code without using Linq is
Paragraph para = CaretPosition.Paragraph;
Run matchedRun = null;
foreach (var inl in para.Inlines)
{
Run run = inl as Run;
if( (run != null) && run.Text.EndsWith(inputText))
{
matchedRun = run;
break;
}
}
if (matchedRun != null)
{
}
Note that I converted "inline" to "inl". It's not a keyword in C# but Stackoverflow makes it look like one.
Also note that it's even LESS readable once you get accustomed to Linq!
This code appears to be related to the RichTextBox class in the .NET Framework.
The CaretPosition.Paragraph.Inlines is a collection of "Inlines" that make up the body of the paragraph.
The code is basically looking for any Inlines that are of type Run, and setting the value of matchedRun to that first instance if there are any. The FirstOrDefault method is simply a convenient way to look inside a collection of objects and retrieve the first element or a default value if the collection is empty.
As far as readability, if you are familiar with LINQ syntax, it isn't too bad to wade through that code, though I do personally find the example code provided by Lee to be a bit more readable - mostly because of the use of another LINQ expression: OfType
it's called "THE MIGHTY LINQ TECHNIQUE" :)
Jokes apart
it is Linq method to get the First element from the collection or return default value.
var matchedRun = para.Inlines.FirstOrDefault(inline =>{ Run run = inline as Run; return (run != null && run.Text.EndsWith(inputText));}) as Run;
=> is called the Lambda techique for shorthand delagate decalaration
so you can read it as
Find 1st object from the para.Inlines collection where that object EndsWith some user suplied value or retrun default value if no match found
if you don't want to use this technique which actually reduces lot of code so you can try below equibvalent code
Paragraph para = CaretPosition.Paragraph;
var matchedRun = null;
foreach (var inl in para.Inlines)
{ Run run = inl as Run;
if ((run != null) && run.Text.EndsWith(inputText))
{ matchedRun = run; break; }
}
Now you can decide which is better to write
Is there a better way to write this? I feel like I'm getting rusty with C# after doing a lot of JavaScript lately. Can this be improved?
foreach (var item in this.CartItems)
{
if (item.EffectivePrice != null)
{
this.CartItems[this.CartItems.IndexOf(item)].EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
}
Well, you could write it in LINQ query syntax with a from and a where, but I'm not sure it is a big change; I'd be more interested in knowing if the lookup is unnecessary:
this.CartItems[this.CartItems.IndexOf(item)].EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
to:
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
Other than that, I'm not sure it is worth the bother of changing it; I'd probably leave it as:
foreach (var item in this.CartItems) {
if (item.EffectivePrice != null) {
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
}
Straight up answer to your question (about how to implement your code in Linq):
this.CartItems.Where(item => item.EffectivePrice != null).ToList().ForEach
(
item =>
item.EffectivePrice = CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
);
There is no reason to have to explicitly specify the index of the item in the list (at least I haven't seen a reason). The .ToList() gives you a List<T> of object references for you to manage. You AsQueryable() to save a few CPU cycles.
It's a little strange, however, to overwrite a property with the results of the method call as subsequent method calls on that property may alter the value over and over again.
But, nonetheless, Linq's method is far more elegant. The drawback, that I can see, is the inability to edit-and-continue with any method that contains Linq.
I think you can do something like this:
foreach (var item in this.CartItems.Where(i => i.EffectivePrice != null))
{
item.EffectivePrice =
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice);
}
In addition to Marc's point, LINQ is more for functional(ish) stuff, and isn't so helpful at mutating existing data structures. Which is a good thing. So if you wanted to produce a new array of new objects, you'd go with something like:
var newItems = CartItems
.Select(i => CreateNewItemWithPrice(i, item.EffectivePrice ??
CurrencyHelper.GetLocalizedCurrency(item.EffectivePrice))
.ToList();
In general, that's a very nice approach, since mutating data can cause an awful lot of bugs.