Non-shortcircuting boolean operators and C# 7 Pattern matching

前端 未结 3 1695
遥遥无期
遥遥无期 2020-12-17 19:13

Im currently writing an C# application, targeting .NET 4.7 (C# 7). I am confused after I tried using the new way of declaring a variable utilizing the \"is\" keyword:

3条回答
  •  庸人自扰
    2020-12-17 19:57

    Am I missing something about the & operator?

    No, I don't think so. Your expectations seem correct to me. Consider this alternative example, which does compile without error:

    object variable = null;
    MyClass classInstance;
    
    if (true & ((classInstance = variable as MyClass) != null))
    {
        var a = classInstance;
    }
    
    var b = classInstance;
    

    (To me, it's more interesting to consider the assignment outside the if body, since that's where the short-circuiting would affect behavior.)

    With the explicit assignment, the compiler recognizes classInstance as definitely assigned, in the assignments of both a and b. It should be able to do the same thing with the new syntax.

    With logical and, short-circuiting or not shouldn't matter. Your first value is true, so the second half should always need to be evaluated to get the whole expression. As you've noted, the compiler does treat the & and && differently though, which is unexpected.

    A variation on this is this code:

    static void M3()
    {
        object variable = null;
    
        if (true | variable is MyClass classInstance)
        {
            var a = classInstance;
        }
    }
    

    The compiler correctly identifies classInstance as not definitely assigned when || is used, but has the same apparent misbehavior with | (i.e. also saying that classInstance is not definitely assigned), even though with the non-short-circuiting operator, the assignment must happen regardless.

    Again, the above works correctly with the assignment is explicit, rather than using the new syntax.

    If this were just about the definite assignment rules not being addressed with the new syntax, then I would expect && to be as broken as &. But it's not. The compiler handles that correctly. And indeed, in the feature documentation (I hesitate to say "specification", because there's no ECMA-ratified C# 7 specification yet), it reads:

    The type_pattern both tests that an expression is of a given type and casts it to that type if the test succeeds. This introduces a local variable of the given type named by the given identifier. That local variable is definitely assigned when the result of the pattern-matching operation is true. [emphasis mine]

    Since short-circuiting produces correct behavior without pattern matching, and since pattern matching produces correct behavior without short-circuiting (and definite-assignment is explicitly addressed in the feature description), I would say this is straight-up a compiler bug. There's probably some overlooked interaction between non-short-circuiting Boolean operators and the way the pattern-matched expression is evaluated that causes the definite assignment to get lost in the shuffle.

    You should consider reporting it to the authorities. I think these days, the Roslyn GitHub issue-tracking is where they track this sort of thing. It might help if you explain in your report how you found this and why that particular syntax is important in your scenario (since in the code you posted, the && operator works equivalently…the non-short-circuiting & doesn't seem to confer any advantage to the code).

提交回复
热议问题