lashja
lashja

Reputation: 493

LINQ - "Index was outside the bounds of the array."

I am getting this error:

"Index was outside the bounds of the array."

By using this LINQ query

I want, if A.LogOutTime is returning null then display "Unknown".

var listItems = (from A in data orderby A.FirstName 
    select new {
        Action = "Logout", 
        UserName = A.FirstName + " " + A.SurName, 
        ID = A.Id, 
        AccessDate = (A.LogOutTime ?? "Unknown")
                       .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0], 
        AccessTimeFrame = (A.LogOutTime ?? "Unknown")
                           .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[1] 
                       + " " + (A.LogOutTime ?? "Unknown")
                           .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[2], 
        Comment = "Never delete this Archive" 
 }).Distinct();

How can I solve this?

Upvotes: 1

Views: 2868

Answers (2)

Gilad Green
Gilad Green

Reputation: 37299

The problem is that when the A.LogOutTime is null you place the string "Unknown" which you afterwards split by " " at go to some indexes of the returned IEnumerable. Those indexes do not exist so you get that error.

I suggest that you do something like the following:

  1. Use let so you do not repeat the split each time. Use the C# 6.0 ?. when splitting to avoid a NullReferenceException (in the case that the LogOutTime is null the sections will also still be null)
  2. When assigning to the property check if the LogOutTime is null and if so assign the "Unknown". If it isn't use the result of the split as needed
  3. Use ElementAtOrDefault(n) so you do not access an index that does not exist

So:

var listItems = (from A in data 
                 orderby A.FirstName
                 let sections = A.LogOutTime?.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)            
                 select new { 
                     Action = "Logout", 
                     UserName = A.FirstName + " " + A.SurName, 
                     ID = A.Id, 
                     AccessDate = A.LogOutTime == null ? "Unknown" : sections.ElementAtOrDefault(0), 
                     AccessTimeFrame = A.LogOutTime == null ? "Unknown" : (sections.ElementAtOrDefault(1) + " " + 
                                       sections.ElementAtOrDefault(2)), 
                     Comment = "Never delete this Archive" }
                ).Distinct();

Also by checking that LogOutTime is not null I assume it is a string. Instead save it as a DateTime and then you wont have the problems of splitting and accessing some index that does not exist. Use the different properties of DateTime or the ToString() overload where you specify a desired format. For more on the matter: Custom Date and Time Format Strings

Upvotes: 1

Jeffrey Patterson
Jeffrey Patterson

Reputation: 2562

Use the "let" keyword to split the parts of the log out time only once. Then check the length of the parts while calculating AccessTimeFrame.

var listItems = (from A in data
                    let logOutTimeParts = (A.LogOutTime ?? "Unknown").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                    orderby A.FirstName
                    select new
                    {
                        Action = "Logout",
                        UserName = A.FirstName + " " + A.SurName,
                        ID = A.Id,
                        AccessDate = logOutTimeParts[0],
                        AccessTimeFrame = logOutTimeParts.Length >= 3 ? logOutTimeParts[1] + " " + logOutTimeParts[2] : "",
                        Comment = "Never delete this Archive"
                    }
    ).Distinct();

Upvotes: 1

Related Questions