What's the Point of the 'dynamic' Primitive Type?...

All the features of the .NET CLR (Common Language Runtime) must have some practical use… right? Then what’s the point in the dynamic primitive type?

C# is a type-safe programming language, meaning it makes sure that an instance of a type is only doing what it’s allowed to do at compile-time (as opposed to runtime). You get safety because the compiler can find out where you’re wrong before even running your code.

The dynamic type allows you to drop the compile-time safety net, allowing you to compile code that relies on types that are only available at runtime.

How would this be practical? Wouldn’t dynamic just make code unstable?

Using Reflection Sucks Sometimes…

Let’s look at an example where we load an assembly after we build and start the program - an assembly that we don’t know about until runtime. We’ll compare using System.Reflection to dynamic for running a method from within that assembly.

In a new project, I’ll make a class which I’m going to compile into a DLL that will be loaded dynamically (at runtime):

namespace Dynamic {
    public class LoadMeLater {
        public string InvokeMeLater() {
            return "You invoked me!";
        }
    }
}

In a separate project, I’ll use System.Reflection to load the DLL built from above:

namespace Dynamic.Tests {
    public class LoadUnsafeAssembly { 
        [Fact]
        public void LoadUnsafeAssembly() {
            Assembly unsafeAssembly = Assembly.LoadFile(@"C:\.....\Dynamic.dll");
        }
    }
}

I’m loading the Dynamic.dll assembly after I compile Dynamic.Tests. The Dynamic.Tests project doesn’t know anything about the Dynamic project it until the test above is running (hence, runtime).

Let’s execute the InvokeMeLater() method using System.Reflection:

[Fact]
public void InvokeAssemblyMethod() {
    string filePath = @"C:\.....\Dynamic.dll";
    Assembly unsafeAssembly = Assembly.LoadFile(filePath);
    Type unsafeType = unsafeAssembly.GetType("Dynamic.LoadMeLater");
    object unsafeTypeInstance = Activator.CreateInstance(unsafeType);

    var result = unsafeType.InvokeMember("InvokeMeLater", 
        BindingFlags.InvokeMethod |
        BindingFlags.Instance |
        BindingFlags.Public, 
        null, 
        unsafeTypeInstance, 
        null).ToString();

    _output.WriteLine(result);
}

This signature…

InvokeMember(string name,
    BindingFlags invokeAttr,
    Binder binder,
    object target,
    object[] args)

is not as clear as I’d like it to be.

Clean Things Up with dynamic

This is what the above test looks like using the dynamic keyword:

[Fact]
public void InvokeAssemblyMethodDynamic() {
    string filePath = @"C:\.....\Dynamic.dll";
    Assembly unsafeAssembly = Assembly.LoadFile(filePath);
    Type unsafeType = unsafeAssembly.GetType("Dynamic.LoadMeLater");
    dynamic unsafeTypeInstance = Activator.CreateInstance(unsafeType);
    
    var result = unsafeTypeInstance.InvokeMeLater();

    _output.WriteLine(result);
}

This looks a lot more understandable, to me, as far as the end goal of using this external assembly.

Summary

We walked through a practical example of using the dynamic primitive type. This hints at the ability for C# to interoperate with other dynamically-typed languages such as Python (IronPython) and Ruby (IronRuby). This is not the only practical use of dynamic, but I’ll sure keep it in my tool chest for the next time I find myself using a lot of reflection.

So, give it a try, sign up for my newsletter, and let me know if you have any questions or just want to connect!

Sample code here


References

Tweet
comments powered by Disqus