Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I agree with you that the ?? operator is usually of limited use-- it's useful to provide a fall-back value if something is null, but isn't useful to prevent a Null Reference Exception in cases when you want to continue drilling down into properties or methods of a sometimes-null reference. </p> <p>IMHO, what's needed much more than ?? is a "null-dereference" operator which allows you to chain long property and/or method chains together, e.g. <code>a.b().c.d().e</code> without having to test each intermediate step for null-ness. The <a href="http://groovy.codehaus.org/" rel="nofollow noreferrer">Groovy</a> language has a <a href="http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator(?.)" rel="nofollow noreferrer">Safe Navigation operator</a> and it's very handy.</p> <p>Luckily, it seems that the C# team is aware of this feature gap. See this <a href="http://connect.microsoft.com/VisualStudio/feedback/details/432830" rel="nofollow noreferrer">connect.microsoft.com suggestion</a> for the C# team to add a null-dereference operator to the C# language. </p> <blockquote> <p>We get quite a number of requests for features similar to this one. The "?." version mentioned in the community discussion is closest to our hearts - it allows you to test for null at every "dot", and composes nicely with the existing ?? operator:</p> <p>a?.b?.c ?? d</p> <p>Meaning if any of a , a.b or a.b.c is null use d instead.</p> <p>We are considering this for a future release, but it won't be in C# 4.0.</p> <p>Thanks again,</p> <p>Mads Torgersen, C# Language PM</p> </blockquote> <p>If you also want this feature in C#, add your votes to the <a href="http://connect.microsoft.com/VisualStudio/feedback/details/432830" rel="nofollow noreferrer">suggestion</a> on the connect site! :-)</p> <p>One workaround I use to get around the lack of this feature is an extension method like what's described in <a href="http://blogs.infosupport.com/blogs/frankb/archive/2008/02/02/Using-C_2300_-3.0-Extension-methods-and-Lambda-expressions-to-avoid-nasty-Null-Checks.aspx" rel="nofollow noreferrer">this blog post</a>, to allow code like this: </p> <pre><code>string s = h.MetaData .NullSafe(meta =&gt; meta.GetExtendedName()) .NullSafe(s =&gt; s.Trim().ToLower()) </code></pre> <p>This code either returns <code>h.MetaData.GetExtendedName().Trim().ToLower()</code> or it returns null if h, h.MetaData, or h.MetaData.GetExtendedName() is null. I've also extended this to check for null or empty strings, or null or empty collections. Here's code I use to define these extension methods:</p> <pre><code>public static class NullSafeExtensions { /// &lt;summary&gt; /// Tests for null objects without re-computing values or assigning temporary variables. Similar to /// Groovy's "safe-dereference" operator .? which returns null if the object is null, and de-references /// if the object is not null. /// &lt;/summary&gt; /// &lt;typeparam name="TResult"&gt;resulting type of the expression&lt;/typeparam&gt; /// &lt;typeparam name="TCheck"&gt;type of object to check for null&lt;/typeparam&gt; /// &lt;param name="check"&gt;value to check for null&lt;/param&gt; /// &lt;param name="valueIfNotNull"&gt;delegate to compute if check is not null&lt;/param&gt; /// &lt;returns&gt;null if check is null, the delegate's results otherwise&lt;/returns&gt; public static TResult NullSafe&lt;TCheck, TResult&gt;(this TCheck check, Func&lt;TCheck, TResult&gt; valueIfNotNull) where TResult : class where TCheck : class { return check == null ? null : valueIfNotNull(check); } /// &lt;summary&gt; /// Tests for null/empty strings without re-computing values or assigning temporary variables /// &lt;/summary&gt; /// &lt;typeparam name="TResult"&gt;resulting type of the expression&lt;/typeparam&gt; /// &lt;param name="check"&gt;value to check for null&lt;/param&gt; /// &lt;param name="valueIfNotNullOrEmpty"&gt;delegate to compute non-null value&lt;/param&gt; /// &lt;returns&gt;null if check is null, the delegate's results otherwise&lt;/returns&gt; public static TResult CheckNullOrEmpty&lt;TResult&gt;(this string check, Func&lt;string, TResult&gt; valueIfNotNullOrEmpty) where TResult : class { return string.IsNullOrEmpty(check) ? null : valueIfNotNullOrEmpty(check); } /// &lt;summary&gt; /// Tests for null/empty collections without re-computing values or assigning temporary variables /// &lt;/summary&gt; /// &lt;typeparam name="TResult"&gt;resulting type of the expression&lt;/typeparam&gt; /// &lt;typeparam name="TCheck"&gt;type of collection or array to check&lt;/typeparam&gt; /// &lt;param name="check"&gt;value to check for null&lt;/param&gt; /// &lt;param name="valueIfNotNullOrEmpty"&gt;delegate to compute non-null value&lt;/param&gt; /// &lt;returns&gt;null if check is null, the delegate's results otherwise&lt;/returns&gt; public static TResult CheckNullOrEmpty&lt;TCheck, TResult&gt;(this TCheck check, Func&lt;TCheck, TResult&gt; valueIfNotNullOrEmpty) where TCheck : ICollection where TResult : class { return (check == null || check.Count == 0) ? null : valueIfNotNullOrEmpty(check); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload