Replies: 4 comments 5 replies
-
That is definitely not true. Indeed, parens exist precisely to affect order of operations and to change things like precedence. This is very intentional exactly so you can get the different semantics here (each of which are useful in different circumstances). |
Beta Was this translation helpful? Give feedback.
-
This is expected, the null-conditional operator is right-associative and short-circuits the remainder of the expression. Without the parenthesis the attempt to access member |
Beta Was this translation helpful? Give feedback.
-
The Shouldly assertion library has also struggled with this, where people write For the null-safe enumerable use case specifically, foreach (var e in c?.TheList ?? [])
{ |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Just came across something odd when debugging an error
P?.A.B differs from (P?.A).B
This is very unexpected, wacky, and breaks simple extension methods used in many places. Parens aren't supposed to matter with simple order of operations!
All this is tucked away in a note on page 174 in the spec
https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_june_2022.pdf
Simple use case is below
Extension methods are supposed to be able to take null as the "this" parameter. Which allows folks to write useful extensions such as:
public static IEnumerable<T> NullSafeEnumerable<T>(this IEnumerable<T> e) { if (e == null) return new T[0]; return e; }
and invoke them like
static void TestB(IList<int> l=null) { var cnt = 0; foreach (var e in l.NullSafeEnumerable()) { ++cnt; } Console.WriteLine($"{nameof(TestA)}=>{cnt}"); }
In this additional case of the null conditional member access, we have
class Container { public IList<int> TheList; } static void TestD(Container c=null) { var cnt = 0; foreach (var e in c?.TheList.NullSafeEnumerable()) { ++cnt; } Console.WriteLine($"{nameof(TestB)}=>{cnt}"); }
which fails, but the following with parens succeeds
static void TestC(Container c = null) { var cnt = 0; foreach (var e in (c?.TheList).NullSafeEnumerable()) { ++cnt; } Console.WriteLine($"{nameof(TestB)}=>{cnt}"); }
We have the pattern shown in TestD all over our app. No idea how many others are caught up in this unexpected scenario!
Beta Was this translation helpful? Give feedback.
All reactions