Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dynamic or Not Dynamic

0.00/5 (No votes)
25 Apr 2010 1  
Discussion of dynamic keyword

Introduction

.NET 4 introduces a set of new features, and among them there’s a dynamic keyword. We'll discuss usage of this keyword in this article.

What is Dynamic Keyword?

We can read in MSDN:

The type is a static type, but an object of type dynamic bypasses static type checking.

So, dynamic can be used in 2 cases:

  1. For COM interop:
    excelApp.Cells[1, 1].Value = "Name";
    Excel.Range range2010 = excelApp.Cells[1, 1];

    This is convenient and easy to understand.

  2. In the code: parameters in function, local variables, etc.

I want to show you the reasons why the second case should be used extra carefully, or not used at all.

Why Dynamic is Evil?

By using dynamic in methods, you:

  • Make the classes (or even libraries) more coupled (loose coupling is a fundamental principle of OO design, you can read about it, e.g. in MSDN Magazine)
  • Write the code that will be possible hard to understand and change (IntelliSense will not work with it, and even Resharper will not help you). Without the author of this code, it will be almost impossible to understand.
  • Create potential source of bugs that are very hard to find and fix.

Example

Let’s see an example:

Programmer A has created a class library called FooLibrary:

FooLibrary

Programmer B has written code that works with library FooLibrary:

using FooLibrary;

namespace FooDemo {
    class Program {
        static void Main(string[] args) {
            AbstractFooFactory fooFactory = new FooFactory();
            AbstractFoo foo = fooFactory.ProduceFoo();

            ProcessFoo(foo);
        }

        private static void ProcessFoo(dynamic foo) {
            foo.Bar();
        }
    }
}

Everything was working very well, as the programmer B knows that the factory always produces instances of ComplexFoo, or its descendant VeryComplexFoo. Both have method Bar().

N days passed.

The company where programmers A and B work ordered a library ExternalFoo. Freelancer C made this:

FooLibrary with ExternalFoos

After that, programmer A has been asked to add a feature to FooLibrary.

When adding a feature, he saw that the method Bar() has no usages except of ComplexFoo and its descendant. The programmer A marked this method as protected internal and renamed it to NewBar().

The code built okay and was uploaded to the production server.

One day was spent by the company to recover from the circumstances of the error:

Unhandled Exception: 
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 
'FooLibrary.VeryComplexFoo' does not contain a definition for 'Bar'

Programmer A has been dismissed from the company. He has found the problem and whacked programmer B in the face.

Programmer B has been told to fix the bug urgently. To do this, he has marked the method NewBar() as public and changed the call:

private static void ProcessFoo(dynamic foo) {
            foo.NewBar();
        }

After this, the code which used the library ExternalFoos (created by freelancer), failed.

Programmer B has been dismissed from the company too.

Programmer C has examined the problem and found a good solution:

FooLibrary refactoring

using FooLibrary;

namespace FooDemo {
    class Program {
        static void Main(string[] args) {
            AbstractFooFactory fooFactory = new FooFactory();
            AbstractFoo foo = fooFactory.ProduceFoo();

            if (foo is ComplexFoo) {
                ProcessFoo(foo as ComplexFoo);
            } else {
                DoSomethingElse();
            }
        }

        private static void DoSomethingElse() {}

        private static void ProcessFoo(ComplexFoo foo) {
            foo.NewBar();
        }
    }
}

Now, if anybody refactors the code of FooLibrary and NewBar() method, it’s clear where this method is used. Also, after renaming this method, a solution with ExternalFoos will not build at all, and this means that the library ExternalFoos has not been refactored.

This example is very simple and straightforward. In the real world, there would be tons of code using dynamic in methods. Just try to imagine that you refactor this code, this is a horror.

I really don’t understand why Microsoft has allowed using dynamic as a parameter. Do you?

Another Negative Aspects

Here’s the code with dynamic method:

using FooLibrary;

namespace FooDemo {
    class Program {
        static void Main(string[] args) {
            AbstractFooFactory fooFactory = new FooFactory();
            AbstractFoo foo = fooFactory.ProduceFoo();

            ProcessFoo(foo);
        }

        private static void ProcessFoo(dynamic foo) {
            foo.Bar();
        }
    }
}

And here’s the generated code:

internal class Program {
    // Methods
    private static void Main(string[] args) {
        ProcessFoo(new FooFactory().ProduceFoo());
    }

    private static void ProcessFoo([Dynamic] object foo) {
        if (<ProcessFoo>o__SiteContainer0.<>p__Site1 == null) {
            <ProcessFoo>o__SiteContainer0.<>p__Site1 = 
            	CallSite<Action<CallSite, object>>.Create
            	(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, 
            	"Bar", null, typeof(Program), new CSharpArgumentInfo[] 
            	{ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
        }
        <ProcessFoo>o__SiteContainer0.<>p__Site1.Target.Invoke
	(<ProcessFoo>o__SiteContainer0.<>p__Site1, foo);
    }

    // Nested Types
    [CompilerGenerated]
    private static class <ProcessFoo>o__SiteContainer0 {
        // Fields
        public static CallSite<Action<CallSite, object>> <>p__Site1;
    }
}

Let’s compare the performance, here’s the code we’ll run:

static void Main(string[] args) {
    AbstractFooFactory fooFactory = new FooFactory();
    AbstractFoo foo = fooFactory.ProduceFoo();

    DateTime dateStart = DateTime.Now;
    for (int i = 0; i < 200000000; i++) {
        ProcessFoo(foo);
    }
    Console.WriteLine(DateTime.Now - dateStart);
}

private static void ProcessDynamicFoo(dynamic foo) {
    foo.NewBar();
}

private static void ProcessFoo(AbstractFoo foo) {
    ComplexFoo cmplxFoo = foo as ComplexFoo;
    if (cmplxFoo == null) {
        throw new InvalidOperationException();
    }
    cmplxFoo.NewBar();
}

If we use ProcessFoo, the result will be 2.5 seconds.

If we use ProcessDynamicFoo, the result will be 6 seconds.

It’s not time-critical here but dynamic is more than twice slow.

Points of Interest / Conclusion

  • dynamic is cool, when it’s used for COM interop; it gives readable and simple code.
  • In other cases, dynamic is evil and should be avoided; using dynamic, you make modules more coupled.

History

  • March 2010 - Initial revision

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here