I'm confused why this doesn't work and what an alternative might be. I suppose I could create a non-null version of MaybeNull
but this issue keeps recurring I'd have to make a lot of duplicate functions. The 'MaybeNull' extension is used in other places where the null is relevant, and like I say, there's a bunch of them with a similar setup.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
public class MyClass
{
private List<string> ParseList(List<string> source)
{
var result = new List<string>();
//problem is this line
result.AddRange(source.Select(x => x.MaybeNull()).Where(x => x != null));
return result;
}
}
public static class StringExtensions
{
public static string? MaybeNull(this string? input)
{
if (input == null) return null;
return input + "modified";
}
}
#nullable disable
So despite the where clause it's trying to add string?
items to the List<string>
result which obviously won't work. I can make it work if I do a foreach
private List<string> ParseList2(List<string> source)
{
var result = new List<string>();
foreach (var item in source)
{
var modifiedItem = item.MaybeNull();
if (modifiedItem != null) result.Add(modifiedItem);
}
return result;
}
Something like this looks like it would work for a list of Int
but not for string or other more complex types.
result.AddRange(source.Select(x => x.MaybeNull())
.Where(x => x != null)
.Select(x => x.Value));
Is there a way to achieve a similar result using a nice linq one liner?
EDIT: In response to comments, the actual code it isn't even a string (so string.IsNullOrEmpty isn't an option), it's a complex Class that gets modified in an extension which is designed to handle nulls. There are lots of extensions like this I'm now implementing nullable reference types on an established code base.
EDIT2: Part of the reason that this is bugging me is that ReSharper says "hey this foreach can be a linq statement! =D " and then it converts it into the invalid linq seen above -_-
This is because the compiler still sees the result from .Where() as a nullable T?
If you want to resolve this via LINQ, I'd recommend a custom extension method that tells the compiler your items aren't null. You'll need to use alternative LINQ syntax
var nullable = new List<string?>
{
"Hello",
null,
"World"
};
var notNull = nullable.WhereNotNull();
Console.WriteLine(string.Join(',', notNull));
internal static class IEnumerableExtensions
{
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> enumerable)
where T : class
{
return from e in enumerable
where e is not null
select e;
}
}
// Outputs: Hello,World