Dynamic typing in C#

As I wrote in the previous blog post about the Dynamic Language Runtime (DLR) some of the statically typed general purpose programming languages already available on the .NET platform will contain constructs which makes it easier for them to interoperate with the DLR and the languages upon it. In this article I will introduce you to the new features in C# 4.0, and the new dynamic type which brings dynamic typing to the language. I will try to explain what really happens under the hood.

The code I will be showing must be compiled using the .NET Framework 4.0 Beta 1. It can be downloaded here. Visual Studio 2010 Beta 1 can be downloaded at the same location.

Dynamic type

In C# 4.0 you are introduced to the new dynamic type. Some may wonder why somebody would like to add something that would break the type-safety of the language. But if you learn more you realize that a variable of type dynamic is statically typed to be dynamic at runtime. It will forever (in terms of scope) be dynamic and be able to hold any type of object.

dynamic x = "Hello, World!";
x = 2;  //Valid because it is of type "dynamic".


The current type of the object held by the dynamic variable is unknown at compile-time and will always be resolved at runtime, hence if you make a call to a method the compiler would not complain if it turned out to not be a valid action.

dynamic foo = "foobar";
stringstr = foo.ToUpper();

foo.Bar(); //Not a member of String. Runtime exception.


As seen in the next example the dynamic type will automatically try to cast its object if you try to assign it to a variable typed other than dynamic.

dynamic foo = "foobar";
string a = foo;  //Will pass this.
int b = foo;  //Will fail at runtime.
 

As seen in these examples dynamic is a type that is handled at runtime.

There are no checks at compile-time which makes it an “unsafe” type to use when it comes to handling types.

It is best not to use it for other than interop with dynamic programming languages like IronPython. So it is not a type you would normally use in C#.

It is preferred that you stay with your old habit of static typing.

Note: Visual Studio will not provide any IntelliSense for dynamic variables because the type is uncertain before runtime. The same with member calls.

VS cannot be sure of the type before it is executed. If you are using Javascript in you will not find this so surprising.

Behind the scenes

Now to the most interesting part. What does the IL that is generated by the compiler look like? Lets dive into it.

We have this program:

dynamic A = 42;
Console.WriteLine(A);

This program actually does nothing that is useful. It only assigns the value 42 to

the variable A of type dynamic and then prints it out with a call to Console.WriteLine.

This is the disassembly in .NET Reflector:

object A = 42;
if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
    <Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(new CSharpInvokeMemberBinder(CSharpCallFlags.None, "WriteLine", typeof(Program), null, new CSharpArgumentInfo[] { new CSharpArgumentInfo(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null) }));
}
<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, typeof(Console), A);

As seen you actually assign 42 to a variable of type object. The variable will therefore be able to contain a reference to any kind of object, because every object inherits from the .NET base class Object.

What is not quite obvious is the calls done under that first line of code.

This code interacts with the DLR and makes it possible to resolve and do safe calls at runtime instead of compile-time, which is the usual way in C#.

The DLR is using CallSites to be able to resolve members at runtime.

CallSites

A CallSite is a type that performs lookups on members called dynamically at runtime. It can be a call to a member of a dynamic variable. In that case it is impossible to know at compile-time if it really exists. CallSites automatically checks if the action is valid.

In our disassembled code it first checks if the CallSite has been initialized, else it initializes it with a CallSite that functions as an member invoker.

It is set to work with the method we want to call, Console.WriteLine. Our argument is dynamic and we have to see if its value can be passed to any of its overloads. This is performed at the last line where the argument is passed into the DLR. If this is invalid the DLR would throw a runtime exception.

This is kind of silly here because Console.WriteLine takes object as an argument in one overload so this does not make any good use in this example.

In the assembly generated by the C# compiler you will find that CallSites live in a nested static class named something like <Main>o__SiteContainer0.

CallSites are simply static fields of the generic CallSite<T> class.

[CompilerGenerated]
private static class <Main>o__SiteContainer0
{
    // Fields
    public static CallSite<Action<CallSite, Type, object>> <>p__Site1;
}

Now where going to view one last sample. This time we call an object member.

We compile the code and then disassemble it for study.

dynamic A = "Test";
string r = A.ToUpper();

This is what .NET Reflector gives you:

object A = "Test";
if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
    <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, string>>.Create(new CSharpConvertBinder(typeof(string), CSharpConversionKind.ImplicitConversion, false));
}
if (<Main>o__SiteContainer0.<>p__Site2 == null)
{
    <Main>o__SiteContainer0.<>p__Site2 = CallSite<Func<CallSite, object, object>>.Create(new CSharpInvokeMemberBinder(CSharpCallFlags.None, "ToUpper", typeof(Program), null, new CSharpArgumentInfo[] { new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null) }));
}
string r = <Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, <Main>o__SiteContainer0.<>p__Site2.Target(<Main>o__SiteContainer0.<>p__Site2, A));

There are two CallSites in this code. The first one is a converter and the second is a member invoker. The action is performed on the last line of code. It involves the lookup and the call to the the member ToUpper. The result is converted to a string and stored in the string variable r.

If you want to check out these features you got to download Visual Studio 2010 Beta 1.

0 Responses to “Dynamic typing in C#”



  1. No Comments Yet

Leave a Reply





Robert Sundström

Tweets

  • Waiting for the VS 2010 Beta 2 to be released to public. Only a couple of hours left. But still not sure when. Is it local time? 3 weeks ago
  • Writing meaningless programs.. 3 weeks ago
  • I consider myself being a logical being, but my logic is flaud. 3 weeks ago
  • SvD: Facebook gör dig smart – men Twitter fördummar (http://bit.ly/14XGNr 2 months ago
  • 2 weeks have passed since I came to Karlskrona. I pretty much enjoy living here. College has started and so far little coursework. 2 months ago

Recent Comments

Steve on Windows 3.11 on a virtual…
catchmikey on Wakoopa
Hillary on First days in Delsbo
wilhol on PC or Mac?

Categories

Calendar

July 2009
M T W T F S S
« Jun   Aug »
 12345
6789101112
13141516171819
20212223242526
2728293031  

Blog Stats

  • 15,396 hits