Home > Software design >  How to get C# null state to convert List<T?> to List<T>
How to get C# null state to convert List<T?> to List<T>

Time:10-05

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 nulls 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.

  • Related