The vast majority of code written with C# is strongly typed. But there are scenarios where a strongly typed system doesn’t work, such as when dealing with some COM objects or working with dynamically typed languages. This chapter explores the support that C# provides for dynamically typed programming.
Dynamic provides a new way to declare variables. Consider the following code:
Employee george = new Employee("George", 15, 10M);
var jane = new Employee("Jane", 13, 9M);
dynamic astro = new Employee("Rastro", 7, 1M);
The first line declares that George is of type Employee. The second line uses var to declare that the type of jane will be whatever the type of the expression is, which is also Employee in this example.
The dynamic keyword is very different, in that it does not equate to a specific type. It means “I don’t know what type this thing is, so just keep a reference to it. We’ll figure out what it can do later.” Since all of these variables are references to instances of the Employee class, you can write the following:
Console.WriteLine(george.Name);
Console.WriteLine(jane.Name);
Console.WriteLine(astro.Name);
When you write george.Name or jane.Name, it means something very simple. Since you know that the type is Employee, you know that there is property named Name, and you merely call the getter of the Name property of the instance.1
When you write astro.Name, it means something very different; since you declared astro to be dynamic, all you know is that it is an instance of some object, but you don’t know what that object can do when you compile the code.
To evaluate astro.Name, you need to do the following:
All of this is done through the component of the .NET runtime known as the dynamic runtime. It is a lot more work than accessing a property where you know the underlying type, which is not surprisingly a fair bit slower than making a direct call.2
When dynamic is used, many compile-time failures become runtime failures. Consider the following code:
string value = "a,b,c,d,e";
string[] items = value.Split(','),
foreach (string item in items)
{
Console.WriteLine(item);
}
When it is rewritten to use dynamic, you can easily make mistakes.
dynamic value = "a,b,c,d,e";
string[] items = value.SplitItUp(','),
foreach (string item in items)
{
Console.WriteLine(item);
}
In this version, I have accidentally tried to call the SplitItUp() method instead of the Split() method. The compiler accepts my code and can’t tell me about my error until the code is executed.
Generic Arithmetic with dynamic
One of the areas where C# lacks support is generic arithmetic. There is no IArithmetic interface implemented by the built-in numeric types (int, short, long, et al.). This prevents the following code from working:
public static T Add<T>(T first, T second)
{
return first + second;
}
This lack of support is frustrating for those who want to create mathematical libraries; a matrix multiplication operation must be written twice, once for float and once for double, despite the code being identical. Can dynamic provide a way to get around this?
In fact, it can; the dynamic runtime provides support for determining whether a type supports operations (see DynamicObject.TryBinaryOperation() for more information), and using that support, you can write the following:
public static T Add<T>(T first, T second)
{
return (dynamic) first + (dynamic) second;
}
public static void Test()
{
Console.WriteLine(Add(5, 10));
Console.WriteLine(Add(5.134, 10));
Console.WriteLine(Add(10, 33.182274));
}
This generates the following:
15
15.134
43.182274
This is exactly what you would expect, and it can be used to write generic algorithms. Unfortunately, it suffers from two problems.
The slow performance likely excludes the use of this technique in many scenarios.3
The use of dynamic has performance disadvantages, but performance is not the only issue; because the compiler doesn’t know what the underlying type is, Visual Studio doesn’t support statement completion on types declared with dynamic.4
Because of these disadvantages, dynamic should be used only in the following situations:
1 If you care, it’s a method named get_Name. It’s still named that even if you don’t care.
2 A quick test of 10 million property accesses showed 12ms for direct access, 390ms for dynamic, and 2500ms using reflection.
3 There’s a nicer approach to do generic calculations; see www.codeproject.com/Articles/8531/Using-generics-for-calculations.
4 At least, it doesn’t currently. Doing so would require it to create objects of the target type and use dynamic to find out what properties and methods they expose. That’s similar to what UI controls do to show up in designers, so it seems feasible.
13.58.130.219