0

I have recently found the following lines in a for loop are giving me an error. The error is from the stepEndTime, the last line of code shown below:

EnumerableRowCollection<DERP_Dataset.tblActualValueFloatRow> RowFirstStep = DERP_DataServiceDataSet.tblActualValueFloat.Where(t => t.PointSliceID == StepPointSliceId && t.ActualValue == stepnumbers[stepIndex] && t.UTCDateTime >= startDate).OrderBy(o => o.UTCDateTime);
EnumerableRowCollection<DERP_Dataset.tblActualValueFloatRow> RowNextStep = DERP_DataServiceDataSet.tblActualValueFloat.Where(t => t.PointSliceID == StepPointSliceId && t.ActualValue > stepnumbers[stepIndex] && t.UTCDateTime >= startDate).OrderBy(o => o.UTCDateTime);

DateTime StepStartTime = (RowFirstStep.First().HasErrors) ? DateTime.MaxValue : RowFirstStep.First().UTCDateTime;
string rowNextStepUTCDateTimeString = RowNextStep.First().UTCDateTime.ToString();
    DateTime StepEndTime = (RowNextStep.First().HasErrors) ? DateTime.MaxValue : RowNextStep.First().UTCDateTime;

Error:

A first chance exception of type 'System.InvalidOperationException' occurred in System.Core.dll
Message: {"Sequence contains no elements"}
Source: System.Core
StackTrace: at System.Ling.Enumerable.First[TSource](IEnumerable'1 source) 

Attempts to figure this out:

  • Link found here.
  • Using RowNextStep.First().isNull is not a Boolean, so can't use in the loop?
  • Tried putting in a dummy string variable, but got exact same error and exception, so didn't learn anything new when trying to debug.
  • I believe RowNextStep.First().HasErrors is evaluating to false each time, including when I encounter the error. Not certain 100%.

Any illumination on this matter would be greatly appreciated.

Edit

Modified the code with suggestions, and it produced a much more useful error.

DateTime StepEndTime = (RowNextStep.FirstOrDefault().HasErrors) ? DateTime.MaxValue : RowNextStep.First().UTCDateTime;

Error is definitely null. As I now get:

A first chance exception of type 'System.NullReferenceException' 

Is there any way to check for null besides !RowNextStep.First().Any? I will use it if I must, but I like to avoid negations if possible.

Community
  • 1
  • 1
hlyates
  • 1,279
  • 3
  • 22
  • 44
  • 1
    RowFirstStep has no elements!!!That why .First throws an exception.Use FirstOrDefault() and check for null also – George Vovos Sep 11 '14 at 17:19
  • @GeorgeVovos, how can I check for null? In my attempts, I tried using RowNextStep.First().isNull, but it didn't work. I think the original coders idea was that if there was an error or null, set it to DateTime.MaxValue. – hlyates Sep 11 '14 at 17:25
  • @hlyates : You can't check for Null. There is nothing in RowNextSteps to BE null! It's empty, so just check for Any() first. See my code answer below... – Rufus L Sep 11 '14 at 17:28
  • @hlyates : Also, with regards to @GeorgeVovos comment, if you use FirstOrDefault() instead of First(), you will get null if there are no elements. So you could do: `DateTime StepEndTime = (RowNextStep.FirstOrDefault() != null || RowNextStep.First.HasErrors) . . .` But I think Any() is more efficient. – Rufus L Sep 11 '14 at 17:32
  • @Rufus As I understand your answer below it is saying, IF null or errors -> DateTime.MaxValue OTHERWISE RowNextStep.First().UTCDateTime, yes? – hlyates Sep 11 '14 at 17:43
  • Thanks for all your useful and immediate comments everyone. I gave Rufus credit since he responded first and most often, but thanks to everyone. – hlyates Sep 11 '14 at 17:53

3 Answers3

2

It's the attempt to get an item from an empty object that is causing you problems.

When you call object.First() on an empty list, it will throw an exception. So you never call .First() unless you already know there are items or you are planning on handling the exception. So you need to do one of those two things (check for items or handle the exception) if you use .First().

When you call object.FirstOrDefault(), you will always get an object back. This object will either be the first item, or the default value of the type (which is usually null) if there are no items. The exception you're running into in your code when calling .FirstOrDefault() is due to the fact that you are also trying to access a property of the returned object (.HasErrors). This is causing the null reference exception (you can't access properties from a null object).

Note that you are also calling the extension methods on the data set multiple times in the condition and assignment, which is expensive.

Probably the most efficient way to handle this is to store the first (or null) item in a variable using .FirstOrDefault(). Then you can use this in your ternary conditions and assignment block.

For example:

var firstRowNextStep = RowNextStep.FirstOrDefault();

DateTime StepEndTime = (firstRowNextStep == null || firstRowNextStep.HasErrors)
    ? DateTime.MaxValue
    : firstRowNextStep.UTCDateTime;

Consider doing this for RowFirstStep as well (even though it isn't causing you any problems right now).

Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • Thanks for your reply. Anyway to check for null without negation? I am reading the Enumeration class in C# but thus far not finding anything we can use. – hlyates Sep 11 '14 at 17:33
  • @hlyates - Added the FirstOrDefault / check for null code. Not sure what you mean about negation? – Rufus L Sep 11 '14 at 17:36
  • 1
    This is not a very efficient solution.The query is executed 3 times when there is a record. – George Vovos Sep 11 '14 at 17:56
  • @George - Yeah, you're right - I was trying to solve the first problem at hand without adding too many more concepts to think about. But considering I said it was efficient, I'll update the sample. Thanks! – Rufus L Sep 11 '14 at 18:58
0

Change instances of RowFirstStep.First() to either

(RowFirstStep.FirstOrDefault() == null || RowFirstStep.FirstOrDefault().HasErrors())

or

(!RowFirstStep.Any()  || RowFirstStep.First().HasErrors())

As George said, .First() will throw an exception when called on an empty collection. .FirstOrDefault() will return null (in this case) when given an empty collection.

Community
  • 1
  • 1
timmy
  • 31
  • 9
  • Since the null is giving me the error, should I set it to RowFirstStep.FirstOrDefault() == null? That way it will return DateTime.MaxValue? Not sure I understand you check otherwise. – hlyates Sep 11 '14 at 17:37
  • Face slap to myself, RTFM, FirstOrDefault() will assign a default value if null. – hlyates Sep 11 '14 at 17:48
  • I updated my answer to fit that logic. It would give DateTime.MaxValue when the collection is empty or there's an error. – timmy Sep 11 '14 at 17:49
  • Right. Thanks a lot Parktimo. I tried to give rep, but apparently I don't have enough rep myself to do that. Appreciate your help! – hlyates Sep 11 '14 at 17:54
0

Don't call .First() or FirstOrFefault() more that 1 time.You only need to execute the query once.

var firstRecord = RowFirstStep.FirstOrDefault();
DateTime StepStartTime = DateTime.MaxValue;

if(firstRecord!=null && !firstRecord.HasErrors())
   StepStartTime =firstRecord.UTCDateTime;
George Vovos
  • 7,563
  • 2
  • 22
  • 45