|Deep C# - Dynamic C#|
|Written by Mike James|
|Thursday, 16 January 2020|
Page 4 of 5
The other end of the spectrum from or static typing is dynamic typing. In true dynamic typing a variable really can change its type at runtime.
The best way of thinking about dynamic type is as a sort of formal way to use a general object type which which allows you access to the methods and properties of the actual data type in use without the need to cast.
For example, suppose we have a class:
If we now create an instance using an object reference type:
then trying to access any of the methods or properties of the object will fail for obvious reasons – an object type doesn’t have the methods and properties of a MyClass type.
However, if you use a cast to MyClass then you can access all of the properties and methods as if MyObject was of type MyClass that is:
In this sense using object and cast has long been the C# programmer’s way of implementing dynamic typing. In this sense dynamic typing is nothing new to the language.
However you must have had the thought
“why do I need to cast the object to the correct type – either the method call works or doesn’t work at run-time”.
Apart from making it easier to discover the programmer’s intention the cast does absolutely nothing to protect you from an error at compile time – any problems only become apparent at runtime.
With the new dynamic type you can indeed “drop the cast”.
The same code in C# can be written using the dynamic type introduced in version 4.0:
The dynamic type only resolves to a method or property at runtime.
Interestingly you can mix dynamic and anonymous as in:
and the compiler correctly works out that i should be an int – suggesting that it isn’t completely blind to the type stored in MyObject. Notice that as dynamic is a valid static type name it is perfectly possible that an anonymous type will resolve to dynamic.
You can swap from dynamic to fully static simply by making appropriate assignments. For example:
first creates a dynamic variable, an int, which is then converted to a strongly typed int. You can also force a conversion using a cast but, as always, if it can’t be done the result is a runtime exception.
Notice that dynamic really is dynamic in the sense that the determination of its type at runtime isn't a one off. A dynamic type can change its type as many times as necessary. For example:
When the int 1 is assigned to it i becomes an int, and i+1 is an integer expression which evaluates to 2. Assigning the string "mike" to i changes its runtime type to string and now i+1 concatenates the string "1" which is implicitly cast from an int to give "mike1".
Notice that there is nothing new going on here as every thing works just as it would if the variable i was first declared as an int and then declared as a string - of course you can't change the type of a static type at compile time.
The guiding principle that has been used in implementing the dynamic type is that what happens should correspond to what happens if the dynamic type was known at compile rather than runtime.
So to work out how a dynamic type behaves simply imagine that you know its type at compile time and what happens in this case should be what happens to the dynamic type.
Late or early?
Whenever you change something in a language, no matter how small or innocent the change is, the ripples spread out and reach parts of the language that you might never have guessed at.
For example, with dynamic typing late binding is the rule even if the method in use isn’t virtual. Consider the following class with two overloaded versions of the same method:
If we now call the method but with a random type, i.e. a the type of the object is selected randomly, something that was impossible to do before the introduction of dynamic, as in:
then which MyMethod is actually called is determined at run time according to the type of i which is discovered using reflection. If i is a double then MyMethod(double f) is called and if it i is an int then MyMethod(int i) is called.
This should be the behaviour you expect from your understanding of the way that dynamic types work but notice that this means that the late binding is being used in a situation where you might have expected the usual early binding. That is, it fits into the principle that what should happen should be the same as if the type of the dynamic variable was known at compile time.
|Last Updated ( Thursday, 16 January 2020 )|