This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

A subtle failure to pattern-match <c>null</c> in C#

Description

<img attachment="csharp-icon-clr.png" align="right">The article <a href="https://ayende.com/blog/202403-B/the-null-check-that-didnt-check-for-nulls" source="Ayende" author="Oren Eini">The null check that didn't check for nulls</a> points out an interesting and subtle difference in code-generation, depending on whether you use the <c>var</c> keyword. Using <c>var</c> in pattern-matching might lead to a pattern that <i>looks</i> like it checks for <c>null</c> but <i>doesn't</i>. You can see and play with a <a href="https://sharplab.io/#v2:D4AQDABCCMAsDcBYAUCmkAqBTAzgF2gAoAZAS3wB50A+CfAJxwEoUBvFCTiUgM0IZzdBAbQBuAQ3p0Aui2RcI7eQq4gA7HSTLOAXw6qN6AHQApAPakAdoQBEAGnt08jJlr2oP6CNnwAmEuR4VNBgtAJySgq8/M6C5BDCXjiy+pyRKpzqmqkQ7gpZxuZWtg52Ti5uKFWeId64eADMAZQ05cxsOdECQgmsOjJyCukZWThaCnkGUCGmFtb2juFuQA==" source="SharpLab.IO">live example</a> but I've replicated the examples below. This is the problematic example: <code>string Test1(List<string> strs) { if(strs is [var s]) { return s; } return string.Join(",", strs); }</code> It's basically saying that the pattern should match anything that's a collection with one element. Since the type is obvious from the method signature's parameter <c>strs</c>, we use <c>var</c> instead of <c>string</c>. That generates the following code. <code>internal static string
$>g__Test1|0_0(List<string> strs) { if (strs != null && strs.Count == 1) { return strs[0]; } return string.Join(",", strs); }</code> Note that it returns the first element <i>without checking it for <c>null</c></i>. If you change the <c>var</c> to <c>string</c>, which, as noted above, is redundant, then the generated code includes a null-check. <code>string Test2(List<string> strs) { if(strs is [string s]) { return s; } return string.Join(",", strs); }</code> This is the generated code for the example above. <code>internal static string
$>g__Test2|0_1(List<string> strs) { if (strs != null && strs.Count == 1) { string text = strs[0]; if (text != null) { return text; } } return string.Join(",", strs); }</code> If you instead use <c>{ }</c> to indicate that you want to match a non-null object, then you also get the null-check. <code>string Test3(List<string> strs) { if(strs is [{} s]) { return s; } return string.Join(",", strs); }</code> This is the generated code for the example above. It is the same as the second example that uses <c>string</c> for the matched parameter. <code>internal static string
$>g__Test3|0_2(List<string> strs) { if (strs != null && strs.Count == 1) { string text = strs[0]; if (text != null) { return text; } } return string.Join(",", strs); }</code>