Я прочитал спецификацию языка С# для условных логических операторов || и &&, также известных как короткие замыкающие логические операторы. Мне показалось неясным, существуют ли они для нулевых булевых элементов, то есть типа операнда Nullable<bool> (также написано bool?), поэтому я попробовал его с нединамической типизацией:
bool a = true;
bool? b = null;
bool? xxxx = b || a; // compile-time error, || can't be applied to these types
Казалось, что он решил вопрос (я не мог четко понять спецификацию, но предполагая, что реализация компилятора Visual С# была правильной, теперь я знал).
Однако, я хотел попробовать с привязкой dynamic. Поэтому я попробовал это:
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);
}
}
Удивительный результат заключается в том, что это выполняется без исключения.
Ну, x и y не удивительны, их объявления приводят к восстановлению обоих свойств, а результирующие значения ожидаются, x - true и y - null.
Но оценка для xx of A || B приводит к отсутствию исключения времени привязки, и было прочитано только свойство A, а не B. Почему это происходит? Как вы можете сказать, мы могли бы изменить геттер B, чтобы вернуть сумасшедший объект, например "Hello world", и xx все равно оценили бы до true без проблем привязки...
Оценка A && B (для yy) также приводит к ошибке привязки-времени. И здесь оба свойства извлекаются, конечно. Почему это разрешено связующим ведром? Если возвращаемый объект из B изменен на "плохой" объект (например, string), произойдет исключение связывания.
Это правильное поведение? (Как вы можете сделать вывод, что из спецификации?)
Если вы попробуете B в качестве первого операнда, то как B || A, так и B && A выдают исключение связывания во время выполнения (B | A и B & A работают нормально, поскольку все нормально с операторами без короткого замыкания | и &).
(Пробовался с компилятором С# Visual Studio 2013 и версией .NET.NET 4.5.2.)