I am utilizing nullable reference types in the C# nullable context.
I am taking a List<string>
, then transforming it to a new List<string?>
with a Select
like so. I then filter out the null
s with a Where
, but the underlying type is still List<string?>
.
var strings = strings.
.Select(s => method.ThatReturnsNullableString(s))
.Where(s => s is not null)
.ToList();
When I try to use this as a List<string>
, I get a CS8619 compiler warning. An easy solution is to use the ! null-forgiving operator and the warning goes away, but I try to use this as sparingly as possible.
Another solution is to use .Cast<string>
, but I would assume this adds runtime overhead for no reason.
Have I not sufficiently proven to the compiler that the collection is of type string
, or is there something I'm missing?
CodePudding user response:
.Where(s => s is not null)
will suppress the null-only items and will keep items of type string?
, so the result will be of type List<string?>
.
Use .OfType<string>()
, it will skip null values and casts string?
to string, It's the equivalent to .Where(s => s is not null).Cast<string>()
.
strings = strings
.Select(s => method.ThatReturnsNullableString(s))
.OfType<string>()
.ToList(); // List<string>
CodePudding user response:
You could write an extension like, working example here
public static class EnumerableExtensions
{
public static IEnumerable<T> SkipNull<T, Y>(
this IEnumerable<Y> source,
Func<Y, T?> target)
{
foreach(var item in source)
{
var result = target(item);
if (result is not null)
{
yield return result;
}
}
}
}
You could use it like this,
public class Program
{
public static void Main()
{
var oddStrings = Enumerable
.Range(1, 100)
.SkipNull(Convert);
}
public static string? Convert(int value)
{
if(value % 2 == 0)
{
return null;
}
return value.ToString();
}
}
but, I would probably use OfType<string>
, or if enumerating the sequence twice was a problem, write a standard function to process and filter the sequence in one pass. Unless of course, I was repeating this pattern.