CHAPTER 24

image

Dynamic Typing

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.

The dynamic Keyword

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:

  1. Determine whether astro has a member named Name.
  2. Determine whether the usage of astro.Name is valid in this context.
  3. Figure out that Name is a property and has a specific get method.
  4. Call the property getter.
  5. Determine how the return type of the property getter should be treated and whether any conversions are required.

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

Dynamic Failure

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 add operation is not typesafe; I can write code that tries to add two non-numeric types together.
  • It’s slow, taking approximately 50 times longer than performing the mathematical operations directly.

The slow performance likely excludes the use of this technique in many scenarios.3

Usage Guidelines

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:

  • When it provides the capability to do something that cannot be done otherwise in C#, such as calling code in Python
  • When it significantly simplifies the use of existing COM APIs

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.130.219