I read the C# Language Specification on the Conditional logical operators ||
and &&
, also known as the short-circuiting logical operators. To me it seemed unclear if these existed for nullable booleans, i.e. the operand type Nullable<bool>
(also written bool?
), so I tried it with non-dynamic typing:
bool a = true;
bool? b = null;
bool? xxxx = b || a; // compile-time error, || can't be applied to these types
That seemed to settle the question (I could not understand the specification clearly, but assuming the implementation of the Visual C# compiler was correct, now I knew).
However, I wanted to try with dynamic
binding as well. So I tried this instead:
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);
}
}
The surprising result is that this runs without exception.
Well, x
and y
are not surprising, their declarations lead to both properties being retrieved, and the resulting values are as expected, x
is true
and y
is null
.
But the evaluation for xx
of A || B
lead to no binding-time exception, and only the property A
was read, not B
. Why does this happen? As you can tell, we could change the B
getter to return a crazy object, like "Hello world"
, and xx
would still evaluate to true
without binding-problems...
Evaluating A && B
(for yy
) also leads to no binding-time error. And here both properties are retrieved, of course. Why is this allowed by the run-time binder? If the returned object from B
is changed to a "bad" object (like a string
), a binding exception does occur.
Is this correct behavior? (How can you infer that from the spec?)
If you try B
as first operand, both B || A
and B && A
give runtime binder exception (B | A
and B & A
work fine as everything is normal with non-short-circuiting operators |
and &
).
(Tried with C# compiler of Visual Studio 2013, and runtime version .NET 4.5.2.)
Nullable<Boolean>
involved at all, only boxed booleans treated asdynamic
-- your test withbool?
is irrelevant. (Of course, this is not a full answer, only the germ of one.) – Ashleyx.HasValue && x.Value || y.HasValue && y.Value
? You need to be explicit, one way or another, about how you want nulls handled. – VendittiA || B
makes a certain amount of sense, in that you don't want to evaluateB
unlessA
is false, which it's not. So you never know the type of the expression, really. TheA && B
version is more surprising - I'll see what I can find in the spec. – MallardA
isbool
and the value ofB
isnull
, then abool && bool?
operator might be involved. – Mallard&&
talks about resolving it as if it were&
instead, and specifically includes the case where both operands arebool?
- but then the next section it refers to doesn't handle the nullable case. I could add a sort of answer going into more detail on that, but it wouldn't fully explain it. – Mallard