-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
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.