Suppose I have
List<MyObject?> list = ...;
I want to turn it into List<MyObject>
, but I have not been able to drop the nullable reference.
Below is an MCVE. In my project I have nullable reference warnings turned to errors, so the commented out line below will not compile.
If I do .Where(e => e != null).Select(e => e!)
then it will be fine in the latest .NET Core 3.1.100, however I cannot extract this into an extension method.
I tried adding this extension method
public static IEnumerable<T> NotNull<T>(this IEnumerable<T> enumerable)
{
return enumerable.Where(e => e != null).Select(e => e!);
}
However it will not convert IEnumerable<MyObject?>
to IEnumerable<MyObject>
and I am unsure why. This leads me to an error like:
[CS8619] Nullability of reference types in value of type 'List' doesn't match target type 'List'.
Is there a way I can make the NotNull
function above work somehow?
After your Select linq query, filter null values with !string.IsNullOrEmpty ("string") or string.IsNullOrWhiteSpace ("string") in your Where query. Show activity on this post. Use Where Instead of Select (Linq).
If a source collection is null or contains an element whose value is null, and your query does not handle null values, a NullReferenceException will be thrown when you execute the query.
There are two methods provided by LINQ in C# which are used for filtering. They are as follows In this article, I am going to discuss the “Where” operator in detail. In the next article, I will discuss the OfType operator with some examples.
We need to use the where standard query operator in LINQ when we need to filter the data from a data source based on some condition (s) just like as we did in SQL using the where clause. So in simple words, we can say that it is used to filter the data from a data source based on some condition (s).
You have to update your extension method to the following
public static IEnumerable<T> NotNull<T>(this IEnumerable<T?> enumerable) where T : class
{
return enumerable.Where(e => e != null).Select(e => e!);
}
The point here is that you are converting the IEnumerable
of nullable references to not nullable ones, therefore you'll have to use IEnumerable<T?>
. where T : class
generic constraint is needed to help the compiler distinguish between nullable reference type and Nullable<T>
struct, as you can read here
Because of this issue between the concrete representations of nullable reference types and nullable value types, any use of
T?
must also require you to constrain theT
to be eitherclass
orstruct
.
After that the following lines will be compiled without any warnings
var list = new List<MyObject?>();
IEnumerable<MyObject> notNull = list.NotNull();
This question is overlaps a lot with Is there a convenient way to filter a sequence of C# 8.0 nullable references, retaining only non-nulls?
One answer posted there exhibited best performance and was extremely consise, with the relevant coding snippet repeated here for posterity:
public static class Extension {
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> o) where T:class
=> o.Where(x => x != null)!;
}
Notably; you don't need to Select
just to remove the ?
annotation, and I think it's a pretty reasonable place to place a nullability !
given that it's pretty clearly correct and likely centralized. If you really cared about GC perf you might consider caching the delegate in a static readonly field, though whether that's meaningfully faster is something you'd need to measure.
If you prefer a zero-tolerance approach to non-null claims via !
, then the other answer https://stackoverflow.com/a/59434717/42921 is likely as good as it gets.
You can use following extensions for Dotnet Core 3.1 both class and struct types.
[Pure]
public static IEnumerable<T> NotNull<T>(this IEnumerable<T?> enumerable) where T : class
{
return enumerable.Where(e => e != null).Select(e => e!);
}
[Pure]
public static IEnumerable<T> NotNull<T>(this IEnumerable<T?> enumerable) where T : struct
{
return enumerable.Where(e => e.HasValue).Select(e => e!.Value);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With