Skip to content

Add WhereNotNull to help with nullability tracking #30381

@YairHalberstadt

Description

@YairHalberstadt

See dotnet/csharplang#8383

Currently the C# compiler can't track how the lambda in a Where method effects nullability.

For example

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

#nullable enable
public class C {
    public IEnumerable<string> WhereNotNull(IEnumerable<string?> strings)
    {
        return strings.Where(x => x != null);
    }
}

Warns with:

warning CS8619: Nullability of reference types in value of type 'IEnumerable<string?>' doesn't match target type 'IEnumerable'.

This could definitely be solved by improved compiler tooling, but doing so would be non-trivial.

A workaround would be to introduce a WhereNotNull method into CoreFX, so that consumers won't need to use the suppression operator themselves.

A further advantage would be that using WhereNotNull instead of Where would avoid allocating a lambda for an extremely common Linq method. This could be done either by caching the lambda as a Func<object, bool>, which avoids the need to update the rest of Linq to be aware of a new Linq method, or by creating a custom enumerator for WhereNotNull which avoids the overhead of a virtual function call, but requires updating the rest of Linq.

API Proposal

namespace System.Linq
{
    public static partial class Enumerable
    {
        public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source);
        public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T: struct;
    }
}

API Usage

I've deliberately not constrained the first API (i.e. omitted where T: class) so that unconstrained generic code can use this API as well. Of course, this won't work well with nullable value types, but that's a general problem of unconstrained generic code and nullability in general, so this isn't a new problem.

Risks

None.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions