Skip to content

C#: Missed FirstOrDefault query. - #22497

Draft
michaelnebel wants to merge 9 commits into
github:mainfrom
michaelnebel:feat/csharp-missed-firstordefault-opprtunity
Draft

C#: Missed FirstOrDefault query.#22497
michaelnebel wants to merge 9 commits into
github:mainfrom
michaelnebel:feat/csharp-missed-firstordefault-opprtunity

Conversation

@michaelnebel

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

QHelp previews:

csharp/ql/src/Linq/MissedFirstOrDefaultOpportunity.qhelp

Missed opportunity to use FirstOrDefault

Programmers sometimes search a sequence by iterating over each element, testing it, and returning the first element that satisfies the test. If the loop completes without finding a match, the method then returns a default value such as null or default.

Recommendation

This pattern is directly available as the FirstOrDefault method in LINQ. Using the library method makes the search intent explicit and avoids manually spelling out the loop and fallback return.

Example

In this example the method searches a list of operations for the first operation with a matching identifier, returning null if no match is found.

using System;
using System.Collections.Generic;

class MissedFirstOrDefaultOpportunity
{
    public static Operation FindOperation(IEnumerable<Operation> operations, string operationId)
    {
        foreach (var operation in operations)
        {
            if (string.Equals(operation.OperationId, operationId, StringComparison.Ordinal))
                return operation;
        }

        return null;
    }
}

class Operation
{
    public string OperationId { get; set; }
}

The LINQ FirstOrDefault method can express this search more directly.

using System;
using System.Collections.Generic;
using System.Linq;

class MissedFirstOrDefaultOpportunityFix
{
    public static Operation FindOperation(IEnumerable<Operation> operations, string operationId)
    {
        return operations.FirstOrDefault(operation =>
            string.Equals(operation.OperationId, operationId, StringComparison.Ordinal));
    }
}

The following examples should not use FirstOrDefault, because they do more than return the matching element or because the fallback value is not the default value.

using System;
using System.Collections.Generic;

class MissedFirstOrDefaultOpportunityGood
{
    public static Operation FindOperationOrThrow(IEnumerable<Operation> operations, string operationId)
    {
        foreach (var operation in operations)
        {
            if (string.Equals(operation.OperationId, operationId, StringComparison.Ordinal))
                throw new InvalidOperationException("Unexpected operation.");
        }

        return null;
    }

    public static Operation FindReplacementOperation(IEnumerable<Operation> operations, string operationId)
    {
        foreach (var operation in operations)
        {
            if (string.Equals(operation.OperationId, operationId, StringComparison.Ordinal))
                return operation;
        }

        return new Operation();
    }

    public static string FindOperationId(IEnumerable<Operation> operations, string operationId)
    {
        foreach (var operation in operations)
        {
            if (string.Equals(operation.OperationId, operationId, StringComparison.Ordinal))
                return operation.OperationId;
        }

        return null;
    }
}

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants