In LINQ, select all values of property X where X != null
C#LinqC# Problem Overview
Is there a shorter way to write the following? (Something that would check for null without explicitly writing != null
)
from item in list
where item.MyProperty != null
select item.MyProperty
C# Solutions
Solution 1 - C#
You can use the OfType
operator. It ignores null values in the source sequence. Just use the same type as MyProperty
and it won't filter out anything else.
// given:
// public T MyProperty { get; }
var nonNullItems = list.Select(x => x.MyProperty).OfType<T>();
I would advise against this though. If you want to pick non-null values, what can be more explicit than saying you want "the MyProperties from the list that are not null"?
Solution 2 - C#
You could define your own extension method, but I wouldn't recommend that.
public static IEnumerable<TResult> SelectNonNull<T, TResult>(this IEnumerable<T> sequence,Func<T, TResult> projection)
{
return sequence.Select(projection).Where(e => e != null);
}
I don't like this one because it mixes two concerns. Projecting with Select
and filtering your null values are separate operations and should not be combined into one method.
I'd rather define an extension method that only checks if the item isn't null:
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T> sequence)
{
return sequence.Where(e => e != null);
}
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> sequence)
where T : struct
{
return sequence.Where(e => e != null).Select(e => e.Value);
}
This has only a single purpose, checking for null. For nullable value types it converts to the non nullable equivalent, since it's useless to preserve the nullable wrapper for values which cannot be null.
With this method, your code becomes:
list.Select(item => item.MyProperty).WhereNotNull()
Solution 3 - C#
I tend to create a static class containing basic functions for cases like these. They allow me write expressions like
var myValues myItems.Select(x => x.Value).Where(Predicates.IsNotNull);
And the collection of predicate functions:
public static class Predicates
{
public static bool IsNull<T>(T value) where T : class
{
return value == null;
}
public static bool IsNotNull<T>(T value) where T : class
{
return value != null;
}
public static bool IsNull<T>(T? nullableValue) where T : struct
{
return !nullableValue.HasValue;
}
public static bool IsNotNull<T>(T? nullableValue) where T : struct
{
return nullableValue.HasValue;
}
public static bool HasValue<T>(T? nullableValue) where T : struct
{
return nullableValue.HasValue;
}
public static bool HasNoValue<T>(T? nullableValue) where T : struct
{
return !nullableValue.HasValue;
}
}
Solution 4 - C#
There is no way to skip a check if it exists.
Solution 5 - C#
// if you need to check if all items' MyProperty doesn't have null
if (list.All(x => x.MyProperty != null))
// do something
// or if you need to check if at least one items' property has doesn't have null
if (list.Any(x => x.MyProperty != null))
// do something
But you always have to check for null
Solution 6 - C#
get one column in the distinct select and ignore null values:
var items = db.table.Where(p => p.id!=null).GroupBy(p => p.id)
.Select(grp => grp.First().id)
.ToList();
Solution 7 - C#
This is adapted from CodesInChaos's extension method. The name is shorter (NotNull
) and more importantly, restricts the type (T
) to reference types with where T : class
.
public static IEnumerable<T> NotNull<T>(this IEnumerable<T> source) where T : class
{
return source.Where(item => item != null);
}
Solution 8 - C#
I know i am a bit late to the party but I found a IMO very elegant sollution to this problem. I wrote an extension method to chain onto my LINQ queries:
public static IEnumerable<T> DiscardNullValues<T>(this IEnumerable<T?> nullable)
{
foreach (var item in nullable)
{
if (item is not null) yield return item;
}
}
Works like a charm.
Solution 9 - C#
This is a feature that have been proposed to the dotnet/runtime issue tracker.
See this comment that proposes a SelectNotNull
function :
https://github.com/dotnet/runtime/issues/30381#issuecomment-806396119