Przeczytałem specyfikację języka C # dotyczącą warunkowych operatorów logicznych ||
i &&
, znanych również jako zwierające operatory logiczne. Wydawało mi się niejasne, czy istniały one dla wartości logicznych dopuszczających wartość null, tj. Typu operandu Nullable<bool>
(również napisanego bool?
), więc wypróbowałem to z typowaniem niedynamicznym:
bool a = true;
bool? b = null;
bool? xxxx = b || a; // compile-time error, || can't be applied to these types
To wydawało się rozstrzygać kwestię (nie mogłem jasno zrozumieć specyfikacji, ale zakładając, że implementacja kompilatora Visual C # była poprawna, teraz wiedziałem).
Jednak chciałem też spróbować z dynamic
wiązaniem. Więc zamiast tego spróbowałem:
static class Program
{
static dynamic A
{
get
{
Console.WriteLine("'A' evaluated");
return true;
}
}
static dynamic B
{
get
{
Console.WriteLine("'B' evaluated");
return null;
}
}
static void Main()
{
dynamic x = A | B;
Console.WriteLine((object)x);
dynamic y = A & B;
Console.WriteLine((object)y);
dynamic xx = A || B;
Console.WriteLine((object)xx);
dynamic yy = A && B;
Console.WriteLine((object)yy);
}
}
Zaskakującym wynikiem jest to, że działa to bez wyjątku.
Cóż, x
i y
nie jest to zaskakujące, ich deklaracje prowadzą do pobrania obu właściwości, a wynikowe wartości są zgodne z oczekiwaniami, x
jest true
i y
jest null
.
Ale ewaluacja xx
z A || B
ołowiu do wiązania bez wyjątku czasu, a tylko nieruchomość A
została przeczytana, nie B
. Dlaczego to się dzieje? Jak widać, moglibyśmy zmienić B
metodę pobierającą, aby zwracała szalony obiekt, taki jak "Hello world"
i xx
nadal oceniałby true
bez problemów z wiązaniem ...
Ocenianie A && B
(dla yy
) również nie prowadzi do błędu w czasie wiązania. I tutaj oczywiście pobierane są obie właściwości. Dlaczego jest to dozwolone przez spinacz czasu wykonywania? Jeśli zwracany obiekt z B
zostanie zmieniony na „zły” obiekt (taki jak a string
), występuje wyjątek wiązania.
Czy to prawidłowe zachowanie? (Jak możesz to wywnioskować ze specyfikacji?)
Jeśli spróbujesz B
jako pierwszy operand, oba B || A
i B && A
daj wyjątek spinacza czasu wykonywania ( B | A
i B & A
działa dobrze, ponieważ wszystko jest normalne z operatorami nie powodującymi zwarcia |
i &
).
(Wypróbowano z kompilatorem C # programu Visual Studio 2013 i wersją środowiska wykonawczego .NET 4.5.2).
Nullable<Boolean>
zaangażowania, tylko wartości logiczne w pudełku są traktowane jakodynamic
- Twój test zbool?
jest nieistotny. (Oczywiście nie jest to pełna odpowiedź, tylko zalążek jednego.)