Error combining 'if' statements that null-checks and Pattern Matches

前端 未结 2 951
太阳男子
太阳男子 2021-01-11 12:50

The following works as expected:

dynamic foo = GetFoo();

if (foo != null)
{
    if (foo is Foo i)
    {
        Console.WriteLine(i.Bar);
    }
}

2条回答
  •  北海茫月
    2021-01-11 13:22

    Ok, I was thinking for some time about this issue, and it looks that compiler behavior is pretty damn correct and it's not so hard to reproduce it even without dynamic values.

    Some strange code will be required, nevertheless.

    To start with we will overload && operator for our Foo type. It's not possible to overload short circuit logical operators directly, so we will overload true, false and & separately.

    public static bool operator true(Foo x) => true;
    public static bool operator false(Foo x) => true;
    public static Foo operator &(Foo foo, Foo val) => new Foo();
    

    Initially we had an expression foo != null && foo is Foo i in if block, now we want && from it to bound to our overload. For this reason we will overload != operator and == as well as they should be paired always.

    public static Foo operator !=(Foo val, Foo val2) => new Foo();  
    public static Foo operator ==(Foo val, Foo val2) => new Foo();
    

    For now foo != null evaluates to Foo and foo is Foo evaluates to bool, but our && overload has signature (Foo, Foo) — still a mismatch, will add one more overload for implicit conversion from bool.

    public static implicit operator Foo(bool val) => new Foo();
    

    Here is the code for Foo type we've got so far

    class Foo
    {
        public static bool operator true(Foo x) => true;
        public static bool operator false(Foo x) => true;
        public static Foo operator &(Foo foo, Foo val) => new Foo();
    
        public static implicit operator Foo(bool val) => new Foo();
    
        public static Foo operator !=(Foo val, Foo val2) => new Foo();
        public static Foo operator ==(Foo val, Foo val2) => new Foo();
    }
    

    And voila! We have the same error for this piece.

     static void Main(string[] args)
     {
         Foo foo = GetFoo();
    
         if (foo != null && foo is Foo i)
         {
             // Use of unassigned local variable i
             // Local variable 'i' might not be initialized before accessing 
             Console.WriteLine(i);
         }
     }
    
     static Foo GetFoo() => new Foo();
    

    And indeed, if we for example use foo is string i instead of foo is Foo i, i won't be initialized at runtime, but we will be inside if block.

    Initial issue is rather equivalent, because of dynamic values involved. foo != null is dynamic, as far as foo is dynamic, so it means && should be bound at runtime, and we have no guarantees that i will be initialized.

    Looks like Matthew quoted the same thing from github issue, but I personally wasn't able to grasp it from the beginning.

提交回复
热议问题