Skip to main content
Use real headers; fix spelling and grammar and code-quotes
Source Link
Toby Speight
  • 88.7k
  • 14
  • 104
  • 327

Learn more about Nullability

Learn more about nullability

Of what I can see so far from your further elaboration and comments/replies everything comes with pro'spros and con'scons, but there isare a few misconceptions especially with LinqLinq and .net/c#.Net/C# versions.

Going from here I'll solely address this as a .net 6.Net 6 scenario. soSo to clear the weeds a bit and layoutlay out some background:

The whereWhere method does nothing to the elements it is processing and returns the same type coming out as it did going in.

Even if you did filter to only items that are not null, the type system has nothing to forward...since, since the whereWhere method doesn't todo type changes.

The ! at the end still probably isn't satisfying the compiler,compiler; there most definitely should be a warning saying so that "it" is not convinced that you've actually made your code null safe. General advice about the ! operator,: just try not to use it and learn about what nullability is, and learn coding patterns to clean it up. You'll far more likely end up using it far less than you think.

Linq is optimized but not Performant

Linq is optimized but not performant

There is plenty of documentation and benchmarks out there about if you want to write the most performant code....you: you don't use LinqLinq. LinqLinq is a handy syntax to query objects in an expressive manner that usually should be fairly efficient. So I can't say it is worth the argument to get picky about chaining on another LinqLinq method after another,another; if anything itsit's common enough to see LinqLinq chains of 4-8 methods chained alongtogether.

Which to point out, theThe Select, Cast, and OfType methods isare meant for type changing type of each element from an enumerable. The same aboutis true of creating another enumerable and a Lambda,lambda: both are created once. theThe Select wrapper is just a super simple cheap class, and the lambda is stored and reused for all elements. FAR better than a method that takes an expression per element, yuck.

Compiler can't forward nullability thru a Linq chain

Compiler can't forward nullability through a Linq chain

Going with this as the example:

The compiler can't help you here, nor can the type system make this simpler. In fact what the compiler discovers about an element in the Where method is essentially thrown away when it processprocesses the Select method. whatWhat you can do is make all the type information about nullability accessible to both parts of the transformation, i.e. check and switch to not nullnon-null. To do this we employ, like fromas in other comments, a delayed enumerable foreachforeach. Rather than make our own enumerable class we use yield to instruct the compiler to treat the method as a delayed enumerable that doesn't cause extra loops of processing of each element.

Learn more about Nullability

Of what I can see so far from your further elaboration and comments/replies everything comes with pro's and con's, but there is a few misconceptions especially with Linq and .net/c# versions.

Going from here I'll solely address this as .net 6 scenario. so to clear the weeds a bit and layout some background

The where method does nothing to the elements it is processing and returns the same type coming out as it did going in

Even if you did filter to only items that are not null the type system has nothing to forward...since the where method doesn't to type changes.

The ! at the end still probably isn't satisfying the compiler, there most definitely should be a warning saying so that "it" is not convinced that you've actually made your code null safe. General advice about the ! operator, just try not to use it and learn about what nullability is, and learn coding patterns to clean it up. You'll far more likely end up using it far less than you think.

Linq is optimized but not Performant

There is plenty of documentation and benchmarks out there about if you want to write the most performant code....you don't use Linq. Linq is a handy syntax to query objects in an expressive manner that usually should be fairly efficient. So I can't say it worth the argument to get picky about chaining on another Linq method after another, if anything its common enough to see Linq chains 4-8 methods chained along.

Which to point out, the Select, Cast, and OfType methods is meant for type changing of each element from an enumerable. The same about creating another enumerable and a Lambda, both are created once. the Select wrapper is just a super simple cheap class, and the lambda is stored and reused for all elements. FAR better than a method that takes an expression per element, yuck.

Compiler can't forward nullability thru a Linq chain

Going with this as the example

The compiler can't help you here, nor can the type system make this simpler. In fact what the compiler discovers about an element in the Where method is essentially thrown away when it process the Select method. what you can do is make all the type information about nullability accessible to both parts of the transformation, i.e. check and switch to not null. To do this we employ, like from other comments, a delayed enumerable foreach. Rather than make our own enumerable class we use yield to instruct the compiler to treat the method as a delayed enumerable that doesn't cause extra loops of processing of each element.

Learn more about nullability

Of what I can see so far from your further elaboration and comments/replies everything comes with pros and cons, but there are a few misconceptions especially with Linq and .Net/C# versions.

Going from here I'll solely address this as a .Net 6 scenario. So to clear the weeds a bit and lay out some background:

The Where method does nothing to the elements it is processing and returns the same type coming out as it did going in.

Even if you filter to only items that are not null, the type system has nothing to forward, since the Where method doesn't do type changes.

The ! at the end still probably isn't satisfying the compiler; there most definitely should be a warning saying so that "it" is not convinced that you've actually made your code null safe. General advice about the ! operator: just try not to use it and learn about what nullability is, and learn coding patterns to clean it up. You'll far more likely end up using it far less than you think.

Linq is optimized but not performant

There is plenty of documentation and benchmarks out there about if you want to write the most performant code: you don't use Linq. Linq is a handy syntax to query objects in an expressive manner that usually should be fairly efficient. So I can't say it is worth the argument to get picky about chaining on another Linq method after another; if anything it's common enough to see Linq chains of 4-8 methods chained together.

The Select, Cast, and OfType methods are meant for changing type of each element from an enumerable. The same is true of creating another enumerable and a lambda: both are created once. The Select wrapper is just a super simple cheap class, and the lambda is stored and reused for all elements. FAR better than a method that takes an expression per element, yuck.

Compiler can't forward nullability through a Linq chain

Going with this as the example:

The compiler can't help you here, nor can the type system make this simpler. In fact what the compiler discovers about an element in the Where method is essentially thrown away when it processes the Select method. What you can do is make all the type information about nullability accessible to both parts of the transformation, i.e. check and switch to non-null. To do this we employ, as in other comments, a delayed enumerable foreach. Rather than make our own enumerable class we use yield to instruct the compiler to treat the method as a delayed enumerable that doesn't cause extra loops of processing of each element.

Source Link

Learn more about Nullability

Of what I can see so far from your further elaboration and comments/replies everything comes with pro's and con's, but there is a few misconceptions especially with Linq and .net/c# versions.

Going from here I'll solely address this as .net 6 scenario. so to clear the weeds a bit and layout some background

source.Where(item => item is not null)!

The where method does nothing to the elements it is processing and returns the same type coming out as it did going in

public IEnumerable<T> Where<T>(Predicate<T> condition){}

Even if you did filter to only items that are not null the type system has nothing to forward...since the where method doesn't to type changes.

Back to

source.Where(item => item is not null)!

The ! at the end still probably isn't satisfying the compiler, there most definitely should be a warning saying so that "it" is not convinced that you've actually made your code null safe. General advice about the ! operator, just try not to use it and learn about what nullability is, and learn coding patterns to clean it up. You'll far more likely end up using it far less than you think.

Linq is optimized but not Performant

There is plenty of documentation and benchmarks out there about if you want to write the most performant code....you don't use Linq. Linq is a handy syntax to query objects in an expressive manner that usually should be fairly efficient. So I can't say it worth the argument to get picky about chaining on another Linq method after another, if anything its common enough to see Linq chains 4-8 methods chained along.

.Select(e => e!)

Which to point out, the Select, Cast, and OfType methods is meant for type changing of each element from an enumerable. The same about creating another enumerable and a Lambda, both are created once. the Select wrapper is just a super simple cheap class, and the lambda is stored and reused for all elements. FAR better than a method that takes an expression per element, yuck.

Compiler can't forward nullability thru a Linq chain

Going with this as the example

public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source)
{
    return source.Where(item => item is not null).Select(item => item!);
}

The compiler can't help you here, nor can the type system make this simpler. In fact what the compiler discovers about an element in the Where method is essentially thrown away when it process the Select method. what you can do is make all the type information about nullability accessible to both parts of the transformation, i.e. check and switch to not null. To do this we employ, like from other comments, a delayed enumerable foreach. Rather than make our own enumerable class we use yield to instruct the compiler to treat the method as a delayed enumerable that doesn't cause extra loops of processing of each element.

public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source)
{
    foreach(var item in source)//item might be null
    {
        if(item is T notNullItem)//non exception throwing conversion with success check
        {
            yield return notNullItem;
        }
    }
}