Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Dynamic Programming in C# 4.0 – An Overview

3.86/5 (3 votes)
25 Feb 2010CPOL2 min read 1  
Introduction to dynamic programming in C# 4.0

One of the most interesting additions to C# 4.0, I think, is the dynamic addition. Just thinking about this makes me excited. I will jump right into a little theory, then some code.

The Theory of Dynamic

So what is this dynamic thingy? Dynamic in C# 4.0 refers to dynamic binding and dynamic binding is what happens at runtime and not at compile time. This involves binding a method, property, operator, member, etc. of an object at runtime. Yes, I know this sounds like polymorphism or like the var keyword or even like using the ultimate base class in C# – object. First and foremost, you have to let go of what you know and remember this important fact.

dynamic != var && dynamic != object

The keyword dynamic, casually speaking, tells the compiler that “Even though it cannot resolve the member statically, it should trust the programmer and not worry because it will/may be resolved at runtime.”

Code

Here is a sample on how you use the dynamic keyword:

C#
dynamic dyn = "My first time";
Console.WriteLine(dyn);

Now let’s look at some similarities and differences of var, object, and dynamic for a sec.

C#
var v = 1;     // here the compiler will figure out (at compile time)
       // the type for v which will be int.
Console.WriteLine(v.GetType().ToString());
//v.Compute();     // causes a compiler error
object o = 1;  // this is boxed from value type to an object with type being int32
Console.WriteLine(o.GetType().ToString());
//o.Compute();     //also gives a compiler error
dynamic d = 1;     //type here is int32
Console.WriteLine(d.GetType().ToString());
d.Compute();   // does not give compile time error but will throw a
       // runtime RuntimeBinderException

So How is this Binding Done?

Look at the following code:

C#
class Program
{
static void Main(string[] args)
{
dynamic dyn = "hello";
Function(dyn);     //The first call is slow because here the call site
       //must figure out the binding
Function(dyn);     //The second call is faster because all the binding lookup
       //was cached in the first call
Console.Read();
}

public static void Function(string s)
{
Console.WriteLine(s);
}

public static void Function(StringBuilder sb)
{
Console.WriteLine(sb.ToString());
}
}

Which version of Function is called? The one with the string argument.
The call to Function above on the dynamic type is resolved at runtime based on the runtime type information and not on the compile time’s type information. Also, the function with the most specific or closest matching parameter will be the one that is called. Pretty neat, huh? By the way, the way in which we used the dynamic keyword above is referred to as language binding.

A Bit More Advance Stuff

So let’s say you want to develop a class that is able to calculate some basic statistics and one of your key requirements is to make it so that the calls to the methods are case insensitive. Also, you want to be able to add new functionality at will. How can you do that?
In the System.Dynamic namespace, there is a class called DynamicObject that implements IDynamicMetaObjectProvider. If you want your classes to have the dynamic capability, then inheriting this class gives you those capabilities. By the way, inheriting DynamicObject or implementing IDynamicMetaObjectProvider is called custom binding.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;

namespace OliverCode.DynamicProgramming
{
 public class Statistics : DynamicObject
 {
 private readonly double[] _arrayOfValues;

 public Statistics(double[] arrVals)
 {
 _arrayOfValues = arrVals;
 }

 public override bool TryInvokeMember(InvokeMemberBinder binder, 
				object[] args, out object result)
 {
 bool isSuccess = true;

 switch (binder.Name.ToLower())
 {
 case "average":
 result = _arrayOfValues.Average();
 break;
 case "max":
 result = _arrayOfValues.Max();
 break;
 case "min":
 result = _arrayOfValues.Min();
 break;
 default:
 result = 0;
 isSuccess = false;
 break;
 }

 return isSuccess;
 }
 }

 class Program
 {
 static void Main(string[] args)
 {
 dynamic stats = new Statistics(new double[] 
			{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

 Console.WriteLine(stats.max()); 	//resolved at compile time
 Console.WriteLine(stats.Max());	//resolved at compile time
 Console.WriteLine(stats.Mean());	//resolved at compile time

 Console.Read();
 }
 }
}

Pay attention to TryInvokeMember method that is overridden. This means that my class can handle method calls. Actually there are a few methods that you can override:

C#
IEnumerable<string> GetDynamicMemberNames();
DynamicMetaObject GetMetaObject(Expression parameter);
bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result);
bool TryConvert(ConvertBinder binder, out object result);
bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result);
bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
bool TryDeleteMember(DeleteMemberBinder binder);
bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result);
bool TryGetMember(GetMemberBinder binder, out object result);
bool TryInvoke(InvokeBinder binder, object[] args, out object result);
bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result);
bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value);
bool TrySetMember(SetMemberBinder binder, object value);
bool TryUnaryOperation(UnaryOperationBinder binder, out object result);

I don’t have the details on all the methods but you get the gist.

So when does dynamic not work?

As far as I know, there are 3 cases in which dynamic doesn’t work:

  1. On interface members that are explicitly implemented
  2. With Extension methods
  3. Classes that subclass a base class, but hide the base classes members

So there is your introduction to dynamic programming. Happy coding and don’t forget to live.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)