.NET Daily Quiz #041
Can you predict the output of this program? Do you know the rules determining the order in which these constructors are called?
The output is
Here's what's happening. When
is called, the constructed type Foo
The execution of a static constructor is triggered by the first of the following events to occur within an application domain (emphasis mine):
- An instance of the class type is created.
- Any of the static members of the class type are referenced.
Next we call and according to the C# spec (same section) a new static constructor execution is called because we have a new closed type:
A static constructor is a member that implements the actions required to initialize a closed class type.
We now have two closed types, each with their own static members. From here the execution is trivial to predict - each closed type acts on its own static members.
.NET Daily Quiz #042
See comments in code for question…
The dynamic type in C# is essentially compiler smoke and mirrors. When you compile this:
All the CLR sees is:
Covariance and contravariance on object is not allowed (because there is no implicit conversion from object to anything else), so the above code fails. There is an implicit conversion from string to object, so swapping the type arguments works:
The next piece of code has a lot more going on:
When compiled, the CLR sees something like this:
The upshot is that dynamic is not a feature of the CLR — it’s a fancy trick by the C# compiler to generate the appropriate runtime code (which itself will instantiate the compiler). The CLR has no knowledge that a dynamic object is being used.
This means that as far as the CLR knows, the runtime type of dynamic is just object (or as Eric Lippert says, ‘"dynamic" as a type is nothing more than "object" with a funny hat on’). So any covariance/contravariance operations with a dynamic constructed typed behave exactly as if you replaced dynamic with object.
.NET Daily Quiz #043
This one might be a bit of a brain-bender. Think carefully.
Is the call to method M bound statically or dynamically (ie, is the call site for this method call determined at compile time, or is it dynamically dispatched)? Can you describe the line of reasoning that leads to your conclusion?
Hint: This program compiles. This information is relevant.
The correct answer is a static dispatch, although the reasoning is quite subtle (if you want to answer without diving into reflector or ildasm.exe). Most of my reference comes from Chris Burrows’ excellent blog. Burrows is the guy who designed much of and implemented almost all of dynamic in C#.
First you need to understand the rules behind two features: overload resolution with dynamic and assignment conversions.
Overload resolution — any method call with a dynamic argument is dispatched dynamically. This is simple.
Assignment conversions — assignment conversions are a new type of conversion introduced into C# to support dynamic. Just as implicit conversions are a subset of explicit conversions, assignment conversions are a superset of implicit conversions and a subset of explicit conversions. So the conversion hierarchy says that all implicit conversions are assignment conversions and all assignment conversions are explicit conversions. See the image to the right.
Why this was done is out of the scope of this quiz — see this article.
The main point here is the set of rules for dynamic conversions (emphasis mine):
- There is an implicit conversion to dynamic from every type (modulo the weirdos, like pointer types). Basically, if it has an implicit conversion to object, it has an implicit conversion to dynamic too.
- There are no implicit conversions from dynamic to any type aside from itself and object.
- However (this is the clever part), there are implicit conversions from any dynamic expression (not type!) to any type.
- There are implicit conversions between types (in both directions) when they differ only by object and dynamic (as in the exception in rule 2).
Now to answer the quiz question. Our first argument is IEnumerable
From rule 1 above we know there must be an implicit conversion from type string to type dynamic. From rule 3 we know that the type dynamic is NOT implicitly convertible to type string. Because we’re dealing with types and not expressions then the call must be static — if we used expressions (eg, if we used naked dynamic and string objects) then this whole analysis would be deferred until run time — the static type analysis would never be performed because of the overload resolution rule given above.
.NET Daily Quiz #044
Continuing on with our exploration of dynamic. What is the result of this program, and why?
The application prints the first conversion but crashes attempting the second. But why?
This one is slightly tricky, even if you know dynamic well. It’s important to note that DynamicObject is just a convenience object that hides a lot of the complexity of creating dynamic types (the more difficult but more flexible way is to implement IDynamicMetaObjectProvider, which is not trivial).
As a result, DynamicObject has a weird and interesting way of defining call sites for what appear to be dynamic methods. If you call a method that exists statically on a DynamicObject then the static call site will be used — basically, if the underlying language (whether it be C# or something else) gets first dibs on resolving any method calls, and this includes conversions.
So what’s happening in my example code? When we call IEnumerable i1 = d; the C# compiler says, “do I have an implicit conversion from variable d of type DynamicConverter to IEnumerable?” The answer is no, so the compiler dispatches the call dynamically. No problem. Next, we call IEnumerable i2 = (IEnumerable)d; and the compiler asks itself if it can perform this conversion. The answer is “yes!” because in C# there is always an explicit conversion from any class type to any interface type. Because C# can handle this conversion, it is bound statically and fails at run time.
This is an important point to keep in mind if you’re using DynamicObject. If you try to do something like define and call a method named ToString then you should be aware that C# will bind this method statically at compile time — you will not get the dynamic behaviour you might expect!
.NET Daily Quiz #045
Why is my application crashing? I know for a fact that dynamicCollection implements get_Count!
Count is implemented explicitly on instances of Array.
When a method is bound at runtime due to dynamic arguments, the runtime type of the dynamic argument is used. In this case the runtime type is System.Array, while the compile-time type is ICollection. The statically bound call to ICollection.Count succeeds because System.Array explicitly implements the ICollection interface. The dynamically bound call fails because… well for the same reason — ICollection is explicitly implemented, so Count is not available through the System.Array type.