Linq strange behavior - c#

Statment:
(definitions != null && definitions.Where(key => key.asset_id != null &&
key.asset_id == item).FirstOrDefault() != null
Throws:
collection was modified enumeration operation may not execute
How to fix this?
if (definitions != null
&& definitions
.Where(key => key.asset_id != null && key.asset_id == item)
.FirstOrDefault() != null)
{
CurrentDuration = definitions
.Where(key => key.asset_id != null && key.asset_id == item)
.FirstOrDefault().duration;
}

The problem is that somewhere in your code the definitions collection is modified. Mostly it's because of collection modification in another thread, but it could have some other reasons. You should find out the piece of code which is modifying collection somewhere else. You can protect the definitions variable using a lock wherever you're using definitions.
if (definitions != null)
{
lock (definiitons)
{
var definition = definitions.FirstOrDefault(key => key.asset_id != null && key.asset_id == item);
if (definition != null)
CurrentDuration = definition.duration;
}
}
and put lock everywhere you're modifying the definitions or its references, for example:
lock (definitions)
{
definitions.Add(x);
}
or
lock (definitions)
{
definitions.Remove(x);
}
or even
var otherRef = definitions
lock (otherRef )
{
otherRef .Add(x);
}

I assume that "CurrentDuration" is a foreach loop variable counter.
The foreach statement is used to iterate through the collection to get the information that you want, but can not be used to add ,remove or change items from the source collection to avoid unpredictable side effects. If you need to add, remove or change items from the source collection, use a for loop.

Related

Complex if statement never gets executed

I have this long if statement that is checking for multiple things. It never seems to execute the code in the curly brackets though.
It is checking two objects.
"currentEngineObject" is the object as it exists in the database.
"engineList" is the object that is passed into this method.
So I am trying to check to make sure that the SizeId is not empty and also has a value for both objects.
If they both have values, but they are not the same value, I want to set the "SizeId" of engineList to the "SizeId" value that is in "currentEngineObject".
But even with test data, it never gets through the large if statement I have.
So I am wondering if there is a problem with my logic? Like should I be using "Or" instead of "And"?
Here is my if block:
if ((currentEngineObject.SizeId.HasValue && currentEngineObject.SizeId.Value != Guid.Empty)
&& (engineList.SizeId.HasValue && engineList.SizeId.Value != Guid.Empty)
&& (currentEngineObject.SizeId.Value != engineList.SizeId.Value))
{
engineList.SizeId = currentEngineObject.SizeId.Value;
}
Thanks!
Try this:
if ((currentEngineObject.SizeId.HasValue && currentEngineObject.SizeId.Value != Guid.Empty)
&& (engineList.SizeId.HasValue && engineList.SizeId.Value != Guid.Empty)
&& !currentEngineObject.SizeId.Equals( engineList.SizeId)) ////Use equals
{
engineList.SizeId = currentEngineObject.SizeId;
}

How can I use a lambda expression in a while loop condition?

while(list.next() != null && list.next().asInteger() != 6)
{
...
}
Is it possible to use an inline lambda function here to avoid calling list.next() twice? If next() actually removed the element from the list, this would be essential not just convenient.
YourType foo;
while ((foo = list.next()) != null && foo.asInteger() != 6)
{
}
You can use for instead of while:
for (var item = list.next(); item != null && item.asInteger() !=6; item = list.next()) {
...
}
You can assign variables in while loops. It would be easier to write it like so.
WhateverNextReturns nextListItem;
while ((nextListItem = list.next()) != null) && nextListItem.asInteger() != 6)
// Do some stuff
Or better yet...
WhateverNextReturns nextListItem;
while(true)
{
nextListItem = list.next();
if (nextListItem == null || nextListItem == 6)
break;
//Do some stuff
}
I think using a lambda would make this more complex than what it has to be.
Here's another example in this StackOverflow Answer of someone assigning a variable in a while expression
It is possible to do this with an inline lambda, but C# does not like it:
while (((Func<YourType, bool>)(n => n != null && n.asInteger() != 6))(list.next()))
{
...
}
is this list an IEnumerable object? You can always use
list.Where(t!=null && t=>t.asInteger()==6).ToList().ForEach(t=>{
//do anything you want with t here.
});
Tell me if I got the question wrong.

Variable Declaration inside an IF C#

take a look at the following code :
if( down == null || down.GetFace() != Face.None || down.GetFace() != Face.Partial )
{
// I called GetFace() two times
// How can i avoid to call it two times, and still putting inside that if
}
Thank you!
To be more maintainable and expressive first separate the null check as exceptional case
then get the result to a variable and check it.
if(down == null)
// Some exceptional case .. return or throw exception
var result = down.GetFace();
if(result == Face.None || result != Face.Parial)
// Do your code here
Refactor to a method:
private bool IsFaceNoneOrPartial(Down down)
{
var face = down.GetFace();
return face != Face.None || face != Face.Partial;
}
// Your code is now:
if( down == null || IsFaceNoneOrPartial(down))
{
}

more short code about if statement

i wanted to try the following code:
//all arrays are List<T> type.
if (m.terms[0] != null && m.terms[0].labels != null && m.terms[0].labels[0].title == "Part-of-speech")
{
result = true;
}
but it occured runtime error occasionly in following situation
i. m.terms == null
ii. m.terms != null, but m.terms[0] does not intialized.
iii. m.terms != null, and m.terms[0] has been exist but
m.terms[0].label does not initialized.
...
so i did modify it to like this:
if (m.terms[0] != null)
{
if (m.terms[0].labels != null)
{
if (m.terms[0].labels[0].title == "Part-of-speech") { result = true; }
}
}
is it the best way?
&& is a short circuiting operator, so the first way you wrote it and the second way will be functionally equivalent.
if (a && b && c)
{
// work
}
b will only be evaluated if a returns true. (Same goes for c).
In your code, checking m.terms[0].labels will not be a problem because you would have short-circuited out of the expression if m.terms[0] had been null.
To completely cover yourself, you'd want to possibly add checks for m and m.terms, however.
m != null && m.terms != null && m.terms.Count > 0 && m.terms[0] != null ...
As it evaluates from left to right, it will break on the first condition that doesn't pass and the rest will go unchecked.
int index = 0;
int labelIndex = 0;
string titleToCheck = "Part-of-speech";
if (m != null && m.terms != null && m.terms.Count > index)// or m.Length...
{
if (m.terms[index] != null && m.terms[index].labels != null &&
m.terms[index].labels.Count > labelIndex)
{
if (m.terms[index].labels[labelIndex].title == titleToCheck)
{
result = true;
}
}
}
This is all about readability. C# uses Short-circuit evaluation so in functionality there is no difference.
try this
if (m!=null && m.terms!= null && m.terms[0].labels!=null && m.terms[0].labels[0].title!=null && m.terms[0].labels[0].title == "Part-of-speech")
Yes, it would be better to split off each null check into a separate if statement.
The reason is that the second and third conditions require the first to not be null. If the first is null, then the second and third conditions will in turn throw errors because their parent is null yet is trying to be accessed.

Null check ObservableCollection before querying it

Is this code good enough:
if (MyCollection.Where(p => p.SomeID == idstring).Any())
{
selectedval = MyCollection.Where(p => p.SomeID == idstring).FirstOrDefault().MyField;
}
My doubt is about the fact that I make the same query twice: first for null check and then to actually get data.
Maybe there is a better way to do this type of things?
Yes.
var item = MyCollection.FirstOrDefault(p => p.SomeID == idstring);
if (item != null)
selectval = item.MyField;
This avoids double querying the collection, which will certainly make a difference in big collections or if your collection performs a DB query.
There is. You can use the FirstOrDefault method which takes a predicate and returns null if the item is not found.
var result = MyCollection.FirstOrDefault(p => p.SomeID == idstring);
if( result != null )
{
// item was found
}

Categories

Resources