Search code examples
c#linqnull-conditional-operator

The proper use of using the `?.` while searching array with LINQ?


So I have this code:

foreach (var user in ServersHolder.Servers.Find(f => f.ID == 9999).Online.FindAll(g => g.LoginPhase == 3))
{
    await trySendPacket(9999, user.GUID.ToString(), OpCode.SentNotifyUserLeft, "", 2);
}

And I have seen where people use ?., I believe in case of a null return like below, but the below doesn't work in that case.

foreach (var user in ServersHolder.Servers?.Find(f => f.ID == 9999).Online?.FindAll(g => g.LoginPhase == 3))
{
    await trySendPacket(9999, user.GUID.ToString(), OpCode.SentNotifyUserLeft, "", 2);
}

Could somebody expain? Or is it best practice to do it this way:

if (ServersHolder.Servers.Exists(f => f.ID == 9999))
{
    foreach (var user in ServersHolder.Servers.Find(f => f.ID == 9999).Online.FindAll(g => g.LoginPhase == 3))
    {
        await trySendPacket(9999, user.GUID.ToString(), OpCode.SentNotifyUserLeft, "", 2);
    }
}

Solution

  • In the second code section, you perform the null checking for the ServersHolder.Servers.

    In the last code section, you validate there is any matching record in the ServersHolder.Servers.

    Both are performing different validation.

    To summarize the validation & data grabbing logic that you needed:

    1. Validate ServersHolder.Servers is not null.
    2. Validate existence of the record with ID = 9999 in ServersHolder.Servers.
    3. The Online property after the (2) cannot be null.
    4. Filter all the records in the Online property.

    As mentioned in the comment, you will get the Null Reference Exception (NRE) as you do not handle the null value in the foreach loop. You need to provide the default/empty list if the chain (with ?. null-checking operator) returns null.

    foreach (var user in ServersHolder.Servers
        ?.Find(f => f.ID == 9999)
        ?.Online
        ?.FindAll(g => g.LoginPhase == 3) ?? new List<OnlineModel>())
    {
        await trySendPacket(9999, user.GUID.ToString(), OpCode.SentNotifyUserLeft, "", 2);
    }