I suggest you ...

Add "?." operator to C#

Add the "?." operator to C# and make it chainable like CoffeeScript so we don't have to write null reference checks for every nested property. An example would be:
myObject?.Items?.[0]?.DoSomething()

5,426 votes
Vote
Sign in
Check!
(thinking…)
Reset
or sign in with
  • facebook
  • google
    Password icon
    I agree to the terms of service
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    Jamshid Asadzadeh shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

    The “?.” operator is now implemented in the latest CTP of Visual Studio “14”.

    For links to details about this and other new C# language features, check out this CodePlex post:

    https://roslyn.codeplex.com/discussions/552378

    Please try out the feature, and see how it works for you!

    Thanks again for great input, and the many many votes!

    Mads Torgersen (MSFT)
    C# Language PM

    186 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      I agree to the terms of service
      Signed in as (Sign out)
      Submitting...
      • Pavel Minaev commented  ·   ·  Flag as inappropriate

        While we're at it, please also add a shorthand form of ?: where the null check is implied one branch is implicitly null. So that e.g. instead of:

        (e == null) ? null : f(e)

        we can write:

        e ?: f(e)

        So, basically, a generic "bind" for the nullable monad.

      • Sergey commented  ·   ·  Flag as inappropriate

        @Vladislav: к вопросу об адекватных примерах, где введение данного оператора дает обоснованный выигрыш.
        >>Vladislav: resource в этой точке гарантированно не null в силу предыдущего кода, он проходит до этого ещё несколько проверок.
        Видимо весь код выглядит так:

        if(resource == null) throw new ArgumentNullException(...);
        var freezable = resource as Freezable;
        if (freezable != null && !freezable.IsFrozen) throw new FrameworkException(...);

        Если применим сокращенный оператор "?.", то отражение данной прикладной области сокращается не на много:

        if(resource == null) throw new ArgumentNullException(...);
        if ((resource as Freezable)?.IsFrozen == false) throw new FrameworkException(...);

        Таким образом, сокращение до 136 символов против 174 - примерно 22% выигрыша, без учета параметров в конструкторах исключений, которые могут съесть половину выигрыша. И это все без документации.

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Anonymous: yes, it would be a better idea, but implementing non-nullable types in the present C# is much more complicated task (http://blog.coverity.com/2013/11/20/c-non-nullable-reference-types/). Safe navigation operator is not a substitute for it.

        But it's a relatively easy-to-implement feature, which would already contribute for code clarity and would quickly become idiomatic.

        Besides, the cases where ?.-operator is applicable are not the cases where non-nullable types are useful: this operator covers the case where _null value is perfectly valid_ and should be handled properly, not the cases where null value is invalid! In the latter case I would personally prefer the code to crash on NullReferenceException rather than swallow the error silently.

      • Sergey commented  ·   ·  Flag as inappropriate

        @Vladislav:
        >>Vladislav: the null constant is used instead.
        Ввод константы призван упрощать код, а не на оборот. Даже ввод свойства вместо поля, с JIT-инициализацией упростит код, и сделает его понятным и предсказуемым.

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Sergey: нет, не кошмарный. resource в этой точке гарантированно не null в силу предыдущего кода, он проходит до этого ещё несколько проверок.

        ---
        no, the code with Freezable is OK. resource at that point is guaranteed to be non-null because of the previous code (it's checked against other conditions before).

      • Sergey commented  ·   ·  Flag as inappropriate

        @Vladislav: Это:
        var freezable = resource as Freezable;
        if (freezable != null && !freezable.IsFrozen)
        throw new FrameworkException(...);

        - кошмарный код изначально. Если переменная resource уже null - участок ее проигнорирует. Зато он сгенерирует исключение, когда объект конкретный и имеет конкретное значение свойства. Если этот участок на входе метода, то в документации необходимо как минимум написать: "Исключение FrameworkException генерируется когда объект принадлежит семейству Freezable и является Frozen. В других случаях метод успешно исполняется даже с пустым ресурсом". Люди которые будут вызывать этот метод будут тратить время на понимание какой ресурс подставить. Им нужно будет задуматься, что возвращает свойство IsFrozen. И возможно им придется написать дополнительную кучу операторов if(...), чтобы корректно вызвать метод, не улетев в исключение, или четко понять нужно ли им в точке вызова гарантированно писать перехватчик, или у них гарантированный объект ресурса не Frozen.
        Конечно, если придерживаться такой архитектуры программирования - а на мой взгляд это извращение, - то оператор "?." необходим.
        У меня по этому поводу четкая позиция: не создавать себе и другим коллегам которые вызывают мой код дополнительных сложностей. Кроме того, когда прикладная область имеет такие закидоны, то размениваться на несколько символов - только мелочиться не в тему. А если прикладная область действительно требует таких загибов, то и оформлять ее следует по другому, например так:

        ////////// Внимание! Ресурс - что угодно, только не Frozen! /////////////
        var freezable = resource as Freezable;
        if (freezable != null && !freezable.IsFrozen)
        throw new FrameworkException(...);
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////

        Теперь уже не до короткого синтаксиса.

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Sergey: you can see "?." notation as a kind of Null-object pattern without having to create an artificial Null-object itself: the null constant is used instead.

      • Anonymous commented  ·   ·  Flag as inappropriate

        @John Saunders: actually, the logic _was_ ternary or near-ternary in both cases, so having one bool? condition instead of two bool conditions is the right thing.

      • Anonymous commented  ·   ·  Flag as inappropriate

        @John Saunders: well, in my case having no application and/or dispatcher is okay, so the logic is really ternary: if (need marshal and can marshal) -> marshal, if (not need marshal) don't marshal, if (special conditions) special processing. With the new syntax I am able to collapse the check into a one-liner.

        The Freezable case is even simpler: the logic is "if freezable, must be frozen".

        And yes, the developers must understand what they write. The point of the feature is to give a concise way to express what is usually expressed in a verbose way.

      • John Saunders commented  ·   ·  Flag as inappropriate

        @Vladislav: what should your code do if Application.Current is null, or if Application.Current.Dispatcher is null? I would hope you would throw an InvalidOperationException or something like that instead of just ignoring the fact that you had a null where you should not.

        This is one of my concerns about this functionality - newer developers will use it to obscure the sources of the nulls in their code. The problem will be seen a great distance away from where the problem began, making it much more difficult to find and fix the problems which caused nulls.

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Sergey: copy-and-paste from my code:

        var freezable = resource as Freezable;
        if (freezable != null && !freezable.IsFrozen)
        throw new FrameworkException(...);

        would be

        if ((resource as Freezable)?.IsFrozen == false)
        throw new FrameworkException(...);

        (one unnecessary variable less)

        Another example:

        Application app = Application.Current; // may still be null
        var d = (app == null) ? null : app.Dispatcher;
        if (d != null && !d.CheckAccess()) // need to marshal
        ...

        would be

        var check = Application.Current?.Dispatcher?.CheckAccess();
        if (check == true) ...

      • Anonymous commented  ·   ·  Flag as inappropriate

        @sergey as with all feature enhancements, they have a time and a place. If someone uses this everywhere they obviously fail to understand basic programming skills. There are absolutely places in my own code where this would be useful, but I would most definitely not use it everywhere

      • Johan Bengtsson commented  ·   ·  Flag as inappropriate

        This operator have some very good properties and at least my code would at some places improve with this.

        There are one benefit not mentioned very much in the previous comments: performance.
        Code like A?.B?.C would only need to call each property once, and if they are costly to call that would make an improvement over writing code first testing each level and then deciding on how to proceed.
        Using temporary variables would of course solve that too but that makes the code much longer and at least in my opinion makes it a lot less readable.

        The operator would also have a great benefit if any of the levels may have side effects, like properties or functions since calling it only once guarantes that it is the same value used for checking and proceeding (this also have a great benefit for volatile variables for the same reason).

        I think it should be possible to also write like this:
        A.B?.C.D

        meaning:

        var result=null;
        {
        var temp1=A.B;
        if (temp1!=null)
        {
        result=temp1.C.D;
        }
        }

        Throwing exceptions on failure is one thing, but it may no be a failure that one of those members are null. The above example will throw an exeption if A is null or if A.B is not null and A.B.C is.

        Littering the code with try..Catch blocks to handle normal situations is not very good, especially not for performance. The try Catch block doesn't make any performance impact if there are no exception thrown, but throwing exceptions are not cheap at all.
        In my opinion it also makes debugging harder, seeing a lot of irrelevant exceptions thrown in the trace or when I am forced to turn on breaking on an exception trown to tack down a problem wouldn't help with a try catch block thrown in to handle normal things.

      • Sergey commented  ·   ·  Flag as inappropriate

        It would be correct to write: myObject.Items.First().DoSomething();
        A fix properties so that they are always issued value or used JIT-initialization.

        If there are 100 references to the property which can sometimes give null, you have to write 100 times operator ".?". Simply well-designed architecture of one property, that it behaves predictably!
        The result will be obtained more predictable code. Namely sections of code 100 will be predictable.

        Further design "?". will be written after the brackets and uppercase before the next method or property name: [index].?Some or Method().?DoSome(). It is almost invisible.
        You can easily miss the moment when whole chunks of code executed in the "optional" - whether executed or whether not.

      • Sergey commented  ·   ·  Flag as inappropriate

        ================+===========================+===
        ================+===========================+===
        ==++++===+++==+++++====+++===+++===+++===++++===
        ==+===+=+===+===+=====+===+=+===+=+===+=+===+===
        ==+===+=+===+===+=====+===+=+===+=+===+=+===+===
        ==+===+==+++=====++====++++==+++===+++===+++++==
        ==========================+=====================
        ======================++++======================

      • Anonymous commented  ·   ·  Flag as inappropriate

        @Vladislav Great link, thanks for the update! Gonna send my votes somewhere else that's needed now...

      Feedback and Knowledge Base