Coming from a non-statically typed language such as PHP or JavaScript, when you hear dynamic type, we think of being able to modify any object runtime. C# is mostly statically typed, but has great support for some dynamic behaviour.
Anonymous Type
Let’s see how we can declare anonymous objects with C# just like we would with dynamic languages.
Typically, when we want a simple dynamic object in a dynamic language, we would declare an anonymous object. This can be done in C# using the Anonymous type:
void Main()
{
dynamic myDynamicObject = new
{
Prop1 = "prop1",
Prop2 = 1
};
Console.WriteLine(myDynamicObject.Prop1);
Console.WriteLine(myDynamicObject.Prop2);
}
What’s going on here? Isn’t C# a statically typed language? Under the bonnet, this actually creates a class with an arbitrary unique name containing the properties that we defined. All the types remain static, there is nothing dynamic here.
So, what if we want to change the value of our Anonymous Object during runtime? Will it behave like an Anonymous type in a dynamic language? Let’s give it a try.
void Main()
{
dynamic myDynamicObject = new
{
Prop1 = "prop1",
Prop2 = 1
};
Console.WriteLine(myDynamicObject.Prop1);
Console.WriteLine(myDynamicObject.Prop2);
Thread.Sleep(1000); // so we can distinguish compilation error vs runtime error
myDynamicObject.Prop1 = "111";
}
If we try to run this, we would get the error:
Property or indexer '<>f__AnonymousType0<string,int>.Prop1' cannot be assigned to -- it is read only
Notice that this is a runtime error.
DLR overview
The Dynamic Language Runtime
was created with the idea of allowing support for dynamic languages within .NET
, this makes it possible for languages such as PHP
, Python
and Ruby
to run in the .NET Runtime
.
Meet the ExpandoObject
The ExpandoObject
is a Dynamic Type
that behaves exactly like how you would expect a dynamic object to behave.
Check the documentation of ExpandoObject Class along with the source code to find out more.
Let’s have a look at how we’d do the same task earlier. We want to create an Object anonymously and change it’s and maybe add properties during runtime.
void Main()
{
dynamic myDynamicObject = new ExpandoObject();
myDynamicObject.Prop1 = "prop1";
Console.WriteLine(myDynamicObject.Prop1);
myDynamicObject.Prop2 = 1;
Console.WriteLine(myDynamicObject.Prop2);
}
Pretty cool, eh? We can even attach Anonymous delegates as if it’s a Object.
void Main()
{
dynamic myDynamicObject = new ExpandoObject();
myDynamicObject.Prop1 = "prop1 is here";
myDynamicObject.Prop2 = 1;
myDynamicObject.Hyphenate = new Func<string, string>((s) => s.Trim().Replace(" ", " "));
myDynamicObject.HyphenateProp1 = new Func<string>(() => myDynamicObject.Prop1.Trim().Replace(" ", " ")); // this creates a closure allowing it to act like a method
Console.WriteLine(myDynamicObject.Prop1);
Console.WriteLine(myDynamicObject.Prop2);
Console.WriteLine(myDynamicObject.Hyphenate("a hyphenated sentence"));
Console.WriteLine(myDynamicObject.HyphenateProp1());
}
We are creating a closure for HyphenateProp1
, this just means that it is maintaining the state of the initial object that was passed to it in isolation throughout the object’s lifetime.
What’s it all for?
As you can imagine, introducing dynamic type in a statically typed language may seem a bit strange. Why would we purposely choose a type where the compiler can’t point out anything wrong until we hit our code during runtime? And even then, there may still be some unpredictable behaviour because of the dynamic types state being mutated to something we do not expect. We are also introducing issues with refactoring – we will no longer get the refactoring help from our beloved IDE.
Anoynmous
types are great for creating data structure that’s used internally within our application without having to write a private class
or struct
.
As for Dynamic
types, there are certain things that are just dynamic by nature, this could be XML, JSON, direct stream of text via TCP etc.