Okresowo zastanawiam się nad tym:
Zwarcie OR zawsze zwróci tę samą wartość, co operator OR nieobwarty?
Oczekuję, że OR zwarcia zawsze będzie oceniać szybciej. Czy więc operator OR nieobwarty obwód został uwzględniony w języku C # dla zachowania spójności?
Czego mi brakowało?
f()
powstaje wyjątek, rozważtrue || f()
itrue | f()
. Czy widzisz różnicę? Pierwsze wyrażenie oznaczatrue
, a ocena drugiego powoduje zgłoszenie wyjątku.Odpowiedzi:
Oba operandy były przeznaczone do różnych rzeczy, pochodzących z C, które nie miały typu boolowskiego. Wersja zwarciowa || działa tylko z wartościami logicznymi, natomiast wersja bez zwarcia | działa z typami całkowymi, wykonując bitowe lub. Po prostu zdarzyło się, że działało jako logiczna operacja bez zwarcia dla logicznych wartości logicznych, które są reprezentowane przez pojedynczy bit, czyli 0 lub 1.
http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical
źródło
|
operator zastosowany do dwóch wartości boolowskich jest skompilowany w tym samymor
operatorze w CIL, jak ma to miejsce w przypadku zastosowania do dwóch wartości całkowitych - w przeciwieństwie do tego,||
który jest kompilowany do CIL przy użyciubrtrue
warunkowego skok.|
(bitowy-lub) musi być odporny na zwarcie dla typów takich jakint
. Jest tak, ponieważ w prawie wszystkich przypadkach należy obliczyć obie strony|
wyrażenia, aby obliczyć poprawny wynik. Na przykład, co jest wynikiem7 | f(x)
?Jeśli
f(x)
nie zostanie to ocenione, nie możesz powiedzieć.Ponadto niespójne byłoby spowodowanie zwarcia tego operatora
bool
, gdy nie jest on zwartyint
. Nawiasem mówiąc, myślę, że nigdy nie używałem|
celowo porównań logicznych, ponieważ stwierdzenie, że jest|
operatorem logicznym , jest bardzo niewygodne .||
dotyczy to jednak logicznych porównań, w których ocena zwarcia działa dobrze.To samo dotyczy nawet C i C ++, gdzie pochodzenie tych operatorów jest.
źródło
Jest to poprawne, operator OR zwarciowy (||) zawsze zwraca tę samą wartość, co operator OR zwarciowy (|). (*)
Jeśli jednak pierwszy argument jest prawdziwy, operator zwarcia nie spowoduje oceny drugiego argumentu, podczas gdy operator bez zwarcia zawsze spowoduje ocenę obu argumentów. Może to mieć wpływ na wydajność, a czasem na skutki uboczne.
Istnieje więc jedno i drugie: jeśli zależy ci na wydajności, a ocena drugiego operandu nie wywołuje żadnych skutków ubocznych (lub jeśli nie przejmujesz się nimi), to za wszelką cenę użyj operatora zwarcia . Ale jeśli z jakiegoś powodu potrzebujesz efektów ubocznych drugiego operandu, powinieneś użyć operatora bez zwarcia.
Przykład, w którym należy użyć operatora przeciwzwarciowego:
(*) Z wyjątkiem niektórych naprawdę zboczonych scenariuszy, w których ocena pierwszego operandu na fałsz powoduje efekt uboczny drugiego operandu, który ma być oceniany jako prawda zamiast fałszu.
źródło
Byłyby 2 powody, aby używać wariantu innego niż zwarcie:
utrzymywanie efektów ubocznych (ale jest to łatwiejsze do kodowania za pomocą zmiennej tymczasowej)
udaremnić ataki czasowe , unikając rozwarcia w zwarciu (może to nawet poprawić wydajność środowiska wykonawczego, jeśli drugi operand jest zmienny, ale jest to mikrooptymalizacja, którą kompilator może i tak wykonać)
źródło
jeśli klauzula po prawej stronie operatora wywołuje efekt uboczny, a programista chciał, aby przed wystąpieniem wartości zwrotnej wystąpił efekt uboczny.
źródło