16

Szybkie pytanie tutaj o zwarcie instrukcji w C#. Z if jak ten:Ocena zwarcia obwodu - czy jest to zagwarantowane? [C#]

if (MyObject.MyArray.Count == 0 || MyObject.MyArray[0].SomeValue == 0) 
{ 

//.... 
} 

To jest zagwarantowane, że ocena zostanie zatrzymane po „MyArray.Count” części, pod warunkiem, że część jest prawdziwa? W przeciwnym razie otrzymam wyjątek zerowy w drugiej części.

+1

W przypadku pytasz to pytanie, ponieważ * nie * dostać wyjątku null odniesienia z powyższego kodu, to prawdopodobnie albo dlatego 'MyArray' jest null lub' MyArray [0] 'zawiera null. Zobacz moją odpowiedź. –

Odpowiedz

34

Tak, jest to zagwarantowane.

C# Language Specification - 7.11 Conditional logical operators:

W && i || operatorzy nazywane są warunkowe operatorów logicznych. Są również nazywane operatorami logicznymi "zwierającymi".

Dlatego będą wspierać logiczne zwarcie definicji - można polegać na tym zachowaniu.

Teraz ważne jest, aby dokonać rozróżnienia pomiędzy warunkowego operatora i operator logiczne:

  • obsługują tylko operatorzy warunkowe zwarciem, operatory logiczne nie.
  • Operatory logiczne C# wyglądają podobnie jak ich odpowiedniki warunkowe, ale z jednym mniejszym znakiem, więc logiczne OR to |, a logiczne AND to &.
  • Operatory logiczne mogą być przeciążone, ale operatory warunkowe nie mogą (jest to trochę techniczne, ponieważ warunkowa ocena operatora obejmuje rozdzielczość przeciążania, a ta rozdzielczość przeciążania może rozwiązać niestandardowe przeciążenie operatora logicznego typu, aby można było obejść ten problem ograniczenie do pewnego stopnia).
+1

+1 za faktyczne cytowanie CLS. – Polynomial

5

Tak, jest to gwarantowane, ale nadal można uzyskać wyjątek odwołania zerowego, jeśli MyArray ma wartość zerową (lub oczywiście MyObject).

0

wolę używać operatora & &, bo wtedy przetestować pozytywne (moja tablica zawiera elementy), zamiast negatywu (mój błąd nie zawiera elementów):

if (MyObject.MyArray.Count > 0 && MyObject.MyArray[0].SomeValue == 0) 
{ 

//.... 
} 

ta jest również gwarancją zwarcie.

+0

Wynik tego kodu nie jest jednak taki sam jak jego. W jego, jeśli liczba wynosi 0, powoduje zwarcie i wchodzi do bloku. W Ciebie, to * tylko * wchodzi do bloku na wartość pierwszego elementu jest 0. –

2

Po prostu mała obserwacja.

Mówiłeś to:

przeciwnym razie dostanę wyjątku null w drugiej części. (akcenty moje)

To nieprawda. Jeśli zwarcie nie było zagwarantowane, w drugiej części można uzyskać numer IndexOutOfRangeException.

To nadal możliwe można dostać NullReferenceException, jeśli pierwszy element w obiekcie jest właściwie zerowa (lub jeśli któryś z innych obiektów w tej wypowiedzi są).

Jedynym całkowicie bezpieczne sprawdzenie byłoby to:

bool conditionHolds = 
    MyObject == null || 
    MyObject.MyArray == null || 
    MyObject.MyArray.Count == 0 || 
    MyObject.MyArray[0] == null || 
    MyObject.MyArray[0].SomeValue == 0; 

if (conditionHolds) 
{ 
    //.... 
} 
+1

Chyba ment: jeśli – riffnl

+0

@riffnl (conditionHolds!): No, właśnie, że mój przykład zgodny z kodem OP. (Wydaje się, że chce, aby kod coś zrobił w przypadku negatywnym). –

2

Tak,

za i operacje, jeśli którykolwiek z argumentu oceniane fałszywego następnie całkowitej ekspresji ocenianej na false to nie jest nie ma potrzeby oceny pozostałych wyrażeń, A w przypadku operacji OR, jeśli którykolwiek z operandów zostanie oceniony na true, pozostała ocena może zostać pominięta:

Tak więc za pomocą & & lub || operator, całe wyrażenie może być ocenione jako prawda lub fałsz, bez oceniania wszystkich podwyrażeń.

Ale rozważ także jego side effect. This article może być pomocne w zrozumieniu oceny zwarcia w głębokości z przykładami z prawdziwego świata.