These are the answers for the C# brainteasers. I've included the questions again just for clarity.
What is displayed, and why?
Answer: Derived.Foo(object)
is printed - when choosing
an overload, if there are any compatible methods declared in a derived class,
all signatures declared in the base class are ignored - even if they're overridden
in the same derived class!
What will be displayed, why, and how confident are you?
Answer: On my box, Bar
is printed and then Foo
. This is
because Foo
has a static constructor, which cannot be run until the exact point at which the
class first has to be initialized. Bar
doesn't have a static constructor though, so the CLR
is allowed to initialize it earlier.
However, there's nothing to guarantee that Bar
will be printed at all. No static fields
have been referenced, so in theory the CLR doesn't have to initialize it at all in our example.
This is all due to the beforefieldinit flag.
Computers are meant to be good at arithmetic, aren't they? Why does this print "False"?
Answer: All the values here are stored as binary floating point. While 1.0 can be stored exactly, 1.000001 is actually stored as 1.0000009999999999177333620536956004798412322998046875, and 0.000001 is actually stored as 0.000000999999999999999954748111825886258685613938723690807819366455078125. The difference between them isn't exactly 1.0, and in fact the difference can't be stored exactly either. Learn more about binary floating point
Here's some code using the anonymous method feature of C# 2. What does it do?
Answer: Ah, the joys of captured variables.
There's only one i
variable here, and its value changes on each iteration of the loop. The anonymous methods
capture the variable itself rather than its value at the point of creation - so the result is 10 printed ten times!
Should this code compile? Does it? What does it mean?
Answer: This shouldn't compile, but it does under the MS compilers for both C# 2 and 3
(and probably 1 as well - I haven't checked). It shouldn't compile because only the literal 0 should be implicitly
convertible to the default value of any enum. Here the decimal is 0.0. Just a little compiler bug. The result is
to print Bar
as that's the 0 value of the Foo
.
More along the same lines...
Answer: Eek - it gets worse! This won't compile under the MS C# 2 compiler, but will compile with the MS C# 3 compiler. It's a known bug due to some optimisation being done too early, collecting constants of 0 and thinking that any known 0 constant should be convertible to the 0 value of any enum. It's with us now, and unlikely to ever be fixed as it could break some code which is technically illegal but working perfectly well. It's possible that the spec will change instead, of course.
I first saw this on Ayende's blog (in a rather more obscure form, admittedly). Once again, work out what will be printed, and why.
Answer: params T[]
is printed. Now why would the compiler
choose to create an array when it doesn't have to? Well... there are two stages to this. Firstly,
when trying to find overloads which are legitimate candidates to be called, type inference works out
that T
should be System.String
. Nothing scary so far.
Then overloading
tries to work out which method is "better". If it's a choice between string x
and
params string[] x
the former will always win - but at this point it's effectively
a choice between object x
and params string[] x
. (The fact that
one is actually a generic method is only relevant in a tie-break situation.)
For the purposes of working out "better conversions" the expanded form of the method with
the params
parameter is then used. This means that by the time actual conversions
are considered, the choices are object x
or string x
- so clearly the latter
wins.
Back to the main page.