Thursday, October 29, 2009

Scary Halloween-Style C# 4.0 Code

Check out the following code:

using System;
using System.Dynamic;

namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
dynamic d = new ExpandoObject();
d.Hola = "Howdy";
SaySomething(d);
}

void SaySomething(dynamic d)
{
Console.WriteLine(d.Hola);
}
}
}

What do you think this code should do? There's no static method to accept the incoming parameter, so compile error, right?

Wrong.

This compiles, but blows up at runtime with a RuntimeBinderException, not finding the instance method SaySomething.



While the above compiles just fine, the following does not:

using System;
using System.Dynamic;

namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
dynamic d = new ExpandoObject();
d.Hola = "Howdy";
SaySomething(d);
}
}
}

Rightly recognizing that SaySomething doesn't exist in the current context.

This is the scariest thing I've seen all week. And I was in Austin last weekend.

So why does it do this? This goes back to the way that overload resolution is achieved during compilation. Eric Lippert wrote about this problem in C# 3.0 earlier this year. Overload resolution steps (for C# 3.0) are as follows, in this order:

1. First, each overload is examined according to it's arguments.
2. Next the determination of whether or not the overload is accessible from the current static or instance context is made.
3. If the overload selected from step 1 is inaccessible, then a compile-time error is thrown.

Now, let's look at the situation I posed above. The major difference here is when this resolution occurs. The first example actually compiles, because the overload resolution is delayed until runtime. The order of operations, however, stays the same.

At runtime, these steps are performed in the following order:

1. First, each overload is examined according to it's arguments.
2. Next the determination of whether or not the overload is accessible from the current static or instance context is made.
3. If the overload selected from step 1 is inaccessible, then a run-time error is thrown.

In other words, the rules are exactly the same as they were in C# 3.0, but the consequences of this mistake while using dynamic are much more severe than they are when not using the dynamic type.

All this to say, the dynamic type is a nice addition to the C# toolbox, but it needs to be used with extreme care.

With great power comes great responsibility.

Monday, October 26, 2009

A Better Developer

We developers are constantly barraged with an overflow of activities and information we don't possibly have enough time for, and we're given very little guidance on what is and isn't worthwhile. This morning on my drive to work, I was reflecting on some of the things I'm involved with, questioning the usefulness of each. Some of these activities (other than the act of coding itself) include:
  • Using Twitter
  • Attending User Groups
  • Leading User Groups
  • Attending Conferences
  • Speaking at Conferences
  • Reading Books (of various kinds)
  • Writing Books
  • Participating in IRC
  • Contributing to Open-Source Projects
  • Taking Certification Tests
  • Contributing to Forums
  • Writing Blogs
  • Reading Blogs
  • LinkedIn
And that's just to name a few.

Which ones are and aren't worthwhile to you is wholly dependent on your personality, affinity, and general life direction.

There's a peer-pressure that comes with this (or any) industry to be noticed, but ultimately, the question we, as developers, should all be asking is "does this make me a better developer?" Answer that question, and you'll know what's worth giving your time to.

Wednesday, October 21, 2009

Adventures in Office Interop and C# 4.0

I had a chance earlier to play with the new features introduced to C# 4.0 for the support of Office Interop. There are a couple of notable features.

First, Type.Missing is no longer required to pass into COM calls. This means no more:

wbs.Open(@"somefile.xlsx", missing, missing, missing, 
missing, missing, missing,
missing, missing, missing,
missing, missing, missing,
missing, missing);

Instead you can opt for:

wbs.Open(@"somefile.xlsx");

Readability FTW!

Other changes include the ability to use the indexed methods ("get_Range" for example) using indexers. Now, instead of:

Range range = ws.get_Range("A1", "A1");

You can use:

Range range = ws.Range["A1"];

Combined with the optional parameters, this makes for another win for readability.

In some situations, this "inferred property" addition makes things even more readable. How many times when setting a value in Excel Interop have you done this:

range.set_Value(XlRangeValueDataType.xlRangeValueDefault, i);

Yeah, not too pretty. Try this on instead:

range.Value = i;

Uh-huh. Yep. Much, much more readable.

That is all.