Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Dynamic Types and DynamicObject References in C#


:P
On this page:

I've been working a bit with C# custom dynamic types for several customers recently and I've seen some confusion in understanding how dynamic types are referenced. This discussion specifically centers around types that implement IDynamicMetaObjectProvider or subclass from DynamicObject as opposed to arbitrary type casts of standard .NET types. IDynamicMetaObjectProvider types  are treated special when they are cast to the dynamic type.

Assume for a second that I've created my own implementation of a custom dynamic type called DynamicFoo which is about as simple of a dynamic class that I can think of:

public class DynamicFoo : DynamicObject
{
    Dictionary<string, object> properties = new Dictionary<string, object>();

    public string Bar { get; set; }
    public DateTime Entered { get; set; }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = null;
        if (!properties.ContainsKey(binder.Name))
            return false;

        result = properties[binder.Name];
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        properties[binder.Name] = value;
        return true;
    }
}

This class has an internal dictionary member and I'm exposing this dictionary member through a dynamic by implementing DynamicObject. This implementation exposes the properties dictionary so the dictionary keys can be referenced like properties (foo.NewProperty = "Cool!"). I override TryGetMember() and TrySetMember() which are fired at runtime every time you access a 'property' on a dynamic instance of this DynamicFoo type.

Strong Typing and Dynamic Casting

I now can instantiate and use DynamicFoo in a couple of different ways:

Strong Typing

DynamicFoo fooExplicit = new DynamicFoo();
var fooVar = new DynamicFoo();

These two commands are essentially identical and use strong typing. The compiler generates identical code for both of them. The var statement is merely a compiler directive to infer the type of fooVar at compile time and so the type of fooExplicit is DynamicFoo, just like fooExplicit. This is very static - nothing dynamic about it - and it completely ignores the IDynamicMetaObjectProvider implementation of my class above as it's never used.

Using either of these I can access the native properties:

DynamicFoo fooExplicit = new DynamicFoo();


// static typing assignments
fooVar.Bar = "Barred!"; fooExplicit.Entered = DateTime.Now; // echo back static values Console.WriteLine(fooVar.Bar); Console.WriteLine(fooExplicit.Entered);

but I have no access whatsoever to the properties dictionary. Basically this creates a strongly typed instance of the type with access only to the strongly typed interface. You get no dynamic behavior at all. The IDynamicMetaObjectProvider features don't kick in until you cast the type to dynamic.

If I try to access a non-existing property on fooExplicit I get a compilation error that tells me that the property doesn't exist. Again, it's clearly and utterly non-dynamic.

Dynamic

dynamic fooDynamic = new DynamicFoo();

fooDynamic on the other hand is created as a dynamic type and it's a completely different beast. I can also create a dynamic by simply casting any type to dynamic like this:

DynamicFoo fooExplicit = new DynamicFoo();
dynamic fooDynamic = fooExplicit;

Note that dynamic typically doesn't require an explicit cast as the compiler automatically performs the cast so there's no need to use as dynamic.

Dynamic functionality works at runtime and allows for the dynamic wrapper to look up and call members dynamically. A dynamic type will look for members to access or call in two places:

  • Using the strongly typed members of the object
  • Using theIDynamicMetaObjectProvider Interface methods to access members

So rather than statically linking and calling a method or retrieving a property, the dynamic type looks up - at runtime  - where the value actually comes from. It's essentially late-binding which allows runtime determination what action to take when a member is accessed at runtime *if* the member you are accessing does not exist on the object. Class members are checked first before IDynamicMetaObjectProvider interface methods are kick in.

All of the following works with the dynamic type:

dynamic fooDynamic = new DynamicFoo();
// dynamic typing assignments
fooDynamic.NewProperty = "Something new!";
fooDynamic.LastAccess = DateTime.Now;

// dynamic assigning static properties
fooDynamic.Bar = "dynamic barred";
fooDynamic.Entered = DateTime.Now;

// echo back dynamic values
Console.WriteLine(fooDynamic.NewProperty);
Console.WriteLine(fooDynamic.LastAccess);
Console.WriteLine(fooDynamic.Bar);
Console.WriteLine(fooDynamic.Entered);

The dynamic type can access the native class properties (Bar and Entered) and create and read new ones (NewProperty,LastAccess) all using a single type instance which is pretty cool. As you can see it's pretty easy to create an extensible type this way that can dynamically add members at runtime dynamically.

The Alter Ego of IDynamicObject

The key point here is that all three statements - explicit, var and dynamic - declare a new DynamicFoo(), but the dynamic declaration results in completely different behavior than the first two simply because the type has been cast to dynamic.

Dynamic binding means that the type loses its typical strong typing, compile time features. You can see this easily in the Visual Studio code editor. As soon as you assign a value to a dynamic you lose Intellisense and you see

DynamicInDebugger

which means there's no Intellisense and no compiler type checking on any members you apply to this instance.

If you're new to the dynamic type it might seem really confusing that a single type can behave differently depending on how it is cast, but that's exactly what happens when you use a type that implements IDynamicMetaObjectProvider. Declare the type as its strong type name and you only get to access the native instance members of the type. Declare or cast it to dynamic and you get dynamic behavior which accesses native members plus it uses IDynamicMetaObjectProvider implementation to handle any missing member definitions by running custom code.

You can easily cast objects back and forth between dynamic and the original type:

dynamic fooDynamic = new DynamicFoo();
fooDynamic.NewProperty = "New Property Value";             
DynamicFoo foo = fooDynamic;
foo.Bar = "Barred";

Here the code starts out with a dynamic cast and a dynamic assignment. The code then casts back the value to the DynamicFoo. Notice that when casting from dynamic to DynamicFoo and back we typically do not have to specify the cast explicitly - the compiler can induce the type so I don't need to specify as dynamic or as DynamicFoo.

Moral of the Story

This easy interchange between dynamic and the underlying type is actually super useful, because it allows you to create extensible objects that can expose non-member data stores and expose them as an object interface. You can create an object that hosts a number of strongly typed properties and then cast the object to dynamic and add additional dynamic properties to the same type at runtime. You can easily switch back and forth between the strongly typed instance to access the well-known strongly typed properties and to dynamic for the dynamic properties added at runtime.

Keep in mind that dynamic object access has quite a bit of overhead and is definitely slower than strongly typed binding, so if you're accessing the strongly typed parts of your objects you definitely want to use a strongly typed reference. Reserve dynamic for the dynamic members to optimize your code.

The real beauty of dynamic is that with very little effort you can build expandable objects or objects that expose different data stores to an object interface. I'll have more on this in my next post when I create a customized and extensible Expando object based on DynamicObject.

Posted in CSharp  .NET  

The Voices of Reason


 

Nadav
February 01, 2012

# re: Dynamic Types and DynamicObject References in C#

Nice article.

Just a small remark,
You're using 'static properties' to refer to the properties defined on the class, maybe something 'strongly typed properties' would be better since static properties means something else...

Nadav

Steven Berkovitz
February 01, 2012

# re: Dynamic Types and DynamicObject References in C#

Have you had a chance to check out Clay (http://clay.codeplex.com/)? It has some neat features like being able to cast any dynamic object to an interface and then access properties with type-checking, etc.

Rick Strahl
February 01, 2012

# re: Dynamic Types and DynamicObject References in C#

@Nadav, thanks for the feedback. I was thinking about that last night and ended up not changing it at the last minute. Went through this morning and replaced most of the static references with strongly typed.

@John, you're totally right that shouldn't compile - my fat fingers. It was supposed to be the strongly typed foo.Bar property instead foo.Name. Fixed in the article.

I really should abstain from posting really late at night :-)

Rick Strahl
February 02, 2012

# re: Dynamic Types and DynamicObject References in C#

@Steven - Clay looks interesting. I have to investigate a little further. Not sure how useful it is to cast dynamic to an interface. That still means that you have to know up front what you're working with - if you know then you might as well be using a static type, no? I can't think of a use case where that would matter (unless you can also construct the interface on the fly).

Duncan Smart
February 03, 2012

# re: Dynamic Types and DynamicObject References in C#

> dynamic object access has quite a bit of overhead and is definitely slower

Only the first time you hit a dynamic member, at this point it compiles the call site so that subsequent accesses should be very fast. Hence Rob Conery's dynamic-based Massive "ORM" performs very well compared to Dapper, etc.

Rick Strahl
February 03, 2012

# re: Dynamic Types and DynamicObject References in C#

@Duncan - Performance is decent but still significantly slower than direct access. When I wrote up the DynamicDataReader post a while back I did a bunch of performance testing comparing direct data access using the Reader and the dynamic reader instance and even with warm up (initialization) removed from the call the performance difference was nearly than 2:1. There's definitely a tradeoff for using dynamic even if it does provide some really nice functionality and cleaner code.

Joy
July 07, 2014

# re: Dynamic Types and DynamicObject References in C#

Good stuff, just what I was looking for :D
Thanks!

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024