2017-11-11 37 views
21

Z jakiegoś powodu M1() powoduje błąd kompilatora, natomiast M2(), który robi to samo, nie powoduje błędu. Każdy pomysł, dlaczego?C# 7 Błąd kompilatora - Dopasowywanie wzorca

Używanie false == powinno być takie samo jak korzystanie z operatora nie, !.

Zastosowanie nieprzydzielonej zmiennej lokalnej 'i'

class Program { 
    static void Main(string[] args) { 
     int x = 8; 

     M1(x); 
     M2(x); 
    } // Main() 

    public static void M1(Object obj) { 
     if (false == (obj is int i)) // Causes ERROR on WriteLine 
      return; 

     System.Console.WriteLine(i); // Use of unassigned local variable 'i' 
    } 

    public static void M2(Object obj) { 
     if (!(obj is int i)) // OKAY 
      return; 

     System.Console.WriteLine(i); 
    } 
} // class Program 
+0

Wygląda na to, że jestem poza zakresem dla M1 - znalezisko krawędzi? –

+0

@ Aominè Widzę to w VS 15.2 (VS-> help-> about) ... Czego używasz? –

+2

@PatrickArtner Oczywiście nie. Jeśli 'i' byłby poza zakresem, błąd nie powiedziałby" nieprzypisanej zmiennej lokalnej ". Ten błąd można uzyskać tylko w przypadku zmiennych znajdujących się w zakresie. – hvd

Odpowiedz

0

dobry znaleźć, tutaj jest to, co myślę. zauważ, że jest to z pewnością coś, co można naprawić, ale próbuję znaleźć uzasadnienie. zauważ, że nie jest to dokładna odpowiedź. tylko mówię!

to nie tylko , który powoduje ten problem, ale także == true powoduje, że staje się bezużyteczny w obu gałęziach, więc poszedłem naprzód i napisałem to.

var x = obj is int i; 
if(x) Console.WriteLine(i); 

pojawia się ten sam błąd. jak widać, jeśli x jest prawdziwe, to należy zainicjować i, prawda? chyba że zaczniesz zarabiać z wartością x! tutaj x nie jest stały, dlatego nie możemy zagwarantować, że x zawsze pozostaje prawdziwe przed wykonaniem instrukcji if.

jak zawsze kompilator może obliczać stałe wartości i wyrażenia w czasie kompilacji. Nie jestem pewien, co się tutaj dzieje, ale to, co myślę jest

if((obj is int i) == false)

tutaj == operator stawia lukę między wyniku dopasowywania wzorców i oceny if, stąd ten błąd. Nie wiem, dlaczego operator ! działa dobrze, może zoptymalizowali tę część, ale zapomnieli ją zoptymalizować? ;)

Myślę, że odnosi się to do fazy analizy semantycznej kompilatora, jej zadaniem jest sprawdzanie znaczenia twojego kodu i określanie sposobu jego wykonania, jeśli coś jest nie tak, jeśli istnieje możliwość niezdefiniowanego zachowania lub jest coś całkowicie nic nie znaczącego, to się nie powiedzie i dostaniesz błąd czasu kompilacji. Więcej informacji na temat Phases of Compiler Design

14

Problem dotyczy sposobu, w jaki kompilator obsługuje "zdecydowanie przypisany, gdy jest prawdziwy". ! odwraca to; == false nie. Tak dla kodu:

if (!(obj is int i)) 
     return; 

System.Console.WriteLine(i); 

Kompilator może wywnioskować, że jeśli obj is int i jest fałszywe, ! odwraca, że ​​w ten sposób return będzie wystąpić, jeśli nie jest to int. Dlatego i może mieć możliwość "wycieku" do kolejnego kodu bezpiecznie.

Jednak te same zasady nie mają zastosowania do == false. Podczas gdy semantycznie identyczny z ludzkim czytelnikiem kodu, kompilator traktuje ! i == false jako bardzo różne rzeczy. Więc dla:

if (false == (obj is int i)) 

kompilator miedze i jest zdania, że ​​nie może znać stan przyporządkowania i, stąd ten błąd.

Aby porozmawiać na ten temat, zobacz Incorrect "Use of unassigned local variable" for (x is T y) == false.

Morał z historii: należy unikać porównywania z false i używać ! podczas korzystania ze wzorów C#.

EDIT

Należy zauważyć, że == false nie jest szczególnym przypadkiem tutaj. Każde użycie == usuwa zdolność kompilatora do określenia "zdecydowanie przypisane, gdy jest prawdziwe". Na przykład, następujący kod kompiluje:

object x = 1; 
if (!(x is bool y)) 
    return 0; 

var z = y; 

Ale dodać == true i to już nie robi:

object x = 1; 
if (!(x is bool y == true)) 
    return 0; 

var z = y; // error: use of an unassigned variable 

EDIT2

Incidently, dla każdego, kto korzysta if (expression == false) ponieważ Kowalski if (!expression) trudne do odczytania, możesz być zainteresowany, aby wiedzieć, że the syntax, if !(expression) is being considered for C# 8.

+0

'!' Nadal jest operatorem, ma implementację podobną do '==' ma. dlaczego nie można zoptymalizować kompilatora '== false'? zauważ, że część "== false" jest stała. może być zoptymalizowany, ale niestety kompilator wysyła błąd przed wykonaniem tego. –

+2

@ M.kazemAkhgary, jest całkiem prawdopodobne, że można to ulepszyć w ten sposób. Jeśli uważasz, że jest to pasjonujące, proszę [podnieść problem w repozytorium języka C#] (https://github.com/dotnet/csharplang/issues), aby poprosić o to. –

+0

@DavidArno tam już jest problem: https://github.com/dotnet/csharplang/issues/801 – Evk