Wednesday, 29 October 2008

New Toys! (C# 4.0)

Today I’ve had a chance to play with the VS 2010 CTP VirtualPC image. Specifically, I’ve been playing around with the major new feature for C# 4.0, the DLR integration that allows you to declare an object as dynamic and then perform late bound operations on it. (Please note that it was too much of a pain to get the highlighting working for the dynamic'; just imagine it nice and blue in these code listings.)

I started off very simple :

dynamic hello = "hello world";
Console.WriteLine(hello.ToString());

This worked fine. What happens if I misspell the ToString method?

dynamic hello = "hello world";
Console.WriteLine(hello.ToStrig());

Some sort of runtime error is expected, obviously. Here it is:

 image

Ok, so what is next? Well one thing that occurred to me when I saw the dynamic keyword is that it could be very useful when working with anonymous types. My problem with anonymous types has always been when you go to pass them to another method, you can’t do a whole lot with them when they come out the other side. Lets see if the dynamic keyword can make things nicer:

static void Main(string[] args)
{
    var testObj = new
    {
        Foo = (Action)(() => Console.WriteLine("foo!")),
        Bar = (Action)(() => Console.WriteLine("bar!"))
    };

    DoFooAndBar(testObj);
    Console.ReadLine();
}
static void DoFooAndBar(dynamic foobar)
{
    foobar.Foo();
    foobar.Bar();
}
Output: 
foo!
bar!

Ok well that works. I’m not sure what its good for though. In the past when I’ve wanted to do something like this with anonymous types, it was because I wanted dynamic behaviour. Surely now we have DLR integration, there will be a nicer way to achieve this without having to use anonymous types? I guess I will have to wait and see.

If you would like to read a bit more about dynamic, Chris Burrows has a decent post up. One point I found interesting is that he refers to dynamic as a type. Now the compiler certainly treats it as a type, but the CLR is certainly none the wiser:

static void Main(string[] args)
{
    List<dynamic> list = new List<dynamic>();
    Console.WriteLine(list.GetType());
    Console.ReadLine();
}
Output: 
System.Collections.Generic.List`1[System.Object]

Also, calling typeof(dynamic) won’t even compile:

image

So its a type, but not really. If you take a look at Chris’s post, he shows what the c# compiler generates when the dynamic type is used, and its quite clear that the resulting IL does not involve any “dynamic” type.

Another thing I tried was dynamic invocation of explicit interface implementation:

interface IFoo { void Foo(); }
class Foo : IFoo
{
    void IFoo.Foo() { Console.WriteLine("foo!"); }
}
static void Main(string[] args)
{
    dynamic foo = new Foo();
    foo.Foo();
    Console.ReadLine();
}

It doesn’t work. You get the same error as when I tried calling ToStrig() above. Static methods won’t work either:

class Foo
{
    static void DoFoo() { Console.WriteLine("foo!"); }
}
static void Main(string[] args)
{
    dynamic foo = new Foo();
    foo.DoFoo();
    Console.ReadLine();
}

Again, a RuntimeBinderException occurs. This behaviour is interesting. Here is an excerpt of the new features document (avaliable from the csharp futures site) discussing the C# runtime binder:

This is essentially a part of the C# compiler running as a runtime component to “finish the work” on dynamic operations that was deferred by the static compiler.

Its not JUST deferred. The binder is obviously not behaving precisely the same as the C# compiler. It doesn’t really surprise me that its not exactly the same. I’m sure someone will be able to give me a reasonable explanation.

The last thing I tried today was making a dynamic call within an expression tree:

static void Main(string[] args)
{
    dynamic hello = "hello world";
    Expression<Action> expTree = () => hello.ToString();
}

This fails to compile, while this is fine:

static void Main(string[] args)
{
    dynamic hello = "hello world";
    Action action = () => hello.ToString();
}

The new features document does not list this as one of the known limitations, so perhaps support for dynamic calls within expression trees is coming and just not yet implemented?

No comments:

Post a comment