With the recent release of Visual Studio 2010, Microsoft has updated.NET and the C# language, both now at version 4. One of the new features of C# is the ability to handle dynamic types. But what exactly does that mean?
Essentially, if you're very careful, you can use C# in a manner similar to languages such as Python or even Smalltalk. Normally, without dynamic types, the compiler does all your type checking for you and won't compile the code if there are typing errors. For example, if you have something like this in your C# program:
Myobj.SomeFunction();
the C# compiler will make sure whatever class Myobj belongs to actually has a function called SomeFunction. If not, the compiler will issue a compiler error and refuse to build your program.
Normally compile-time type checking is a good thing, because it helps us programmers keep from writing sloppy code. But there are times when you might need to get around it.
Look closely at the following code. Notice the base class Car, and the three classes that follow it. Then notice the shop function, and how I use that function in Main.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace dynamictypes
{
class Car{
public virtual string tuneup() { return "fixed"; }
}
class Mustang : Car {
public override string tuneup() { return "good to go"; }
}
class Pinto : Car
{
public override string tuneup() { return "yee haw"; }
}
class Beetle
{
public string tuneup() { return "Fahrvergnugen"; }
}
class Program
{
static void shop(Car inst) {
Console.WriteLine(inst.tuneup());
}
static void Main(string[] args) {
Mustang stang = new Mustang();
Pinto thepinto = new Pinto();
Beetle bug = new Beetle();
shop(stang);
shop(thepinto);
shop(bug);
}
}
}
The function called shop takes a Car parameter, which means you can pass an instance of Car or an instance of any classderived from Car. In Main, I create two such instances—an instance of Mustang, and an instance of Pinto. Both are classes derived from Car, so the compiler will let me pass either instance to the shop function. (That whole process is called polymorphism.)
Through this means, the shop function can be assured that any object it receives will have the same structure—in particular, each object will have a tuneup function. The compiler enforces this rule for us, helping us avoid sloppy programming, making sure we don't pass in an object that doesn't have a tuneup function.
But now look at the class Beetle. It isn't derived from Car. And even though it has a tuneup function, we can't pass it to the shop function, because it isn't derived from Car. The compiler will issue an error for this line:
shop(bug);
Beetle isn't derived from car, so the compiler won't even compile the program, preventing us from running the program at all—even though you and I both know Beetle has a tuneup function.
Now the best solution in this case is tofix the problem by making Beetle derived from Car just like the other two classes.
But sometimes that's not an option. If you're writing a program that interacts with other libraries created by other people, and Beetle is in one of those libraries, and it's not derived from Car, and you have no control over the library's source code, and you know that the Beetle has all the necessary functions, then there's still hope. C# now supports dynamic types, as of version 4.0. Check out one little change to the shop function, and suddenly our program will work:
static void shop(dynamic inst) {
Console.WriteLine(inst.tuneup());
}
Instead of taking an instance of Car, the shop function takes a parameter whose type is dynamic. That tells the compiler to allow any object in, and wait until the program's actually running to check if the object has a tuneup method. Try it out yourself. In Visual Studio 2010 (including the free Express editions, as long as you're using 2010), create a new C# console application and paste the above code in but with the dynamic change to the shop function. You'll see it compiles and runs. When the compiler compiles the code for shop, it doesn't bother with making sure the type of object has a tuneup method. The program will verify at runtime that the object has a tuneup method when the tuneup method is actually called.
Here's the results with no errors:
This is a cool feature, but be careful with it. Code like this is just asking for mistakes, and if you use dynamic when it isn't necessary, you could end up with some serious headaches later on trying to track down any bugs that come in. The compile-time type checking is there for a reason, helping us make sure our code is designed well. So only use it when necessary.
And by the way, you might be wondering what happens if you pass in an object that doesn't have a tuneup method. Let's try it out and see what happens. Try commenting out the method in the Beetle class:
class Beetle
{
//public string tuneup() { return "Fahrvergnugen"; }
}
Then run the program and you'll see a runtime exception. But the program does still compile! Here's the error:
So if you're going to use dynamic types, then you'll want to put a try/catch block around your code and handle the exceptions gracefully so that your program doesn't crash.
Have fun!