Dynamic in .NET 4
General Misconception about Dynamic
C# is a statically typed and type safe language.
What this means is that all the expressions are resolved into instance of a Type and compiler performs checks for all the operations performed by the type before generating any code for that Type.
The benefit of a type safe programming language is that most errors are detected at compile time before it gets complicated to detect them at runtime. Moreover, it also helps compiler to generate optimized, fast and small code as the compiler can make more assumptions at compile time and emit the correct Intermediate Language (IL) and metadata.
The term dynamic is basically related to as Dynamic Language Runtime (DLR) and what most developers believe is that it is not good move for a statically typed language. Knowing the benefits of Static and Type safe language it also looks correct to avoid making C# dynamically typed.
So first things first, Dynamic has nothing to do with making the C# language dynamically typed or in other words Type unsafe.
What is Dynamic?
Dynamic is just another type defined within the CLR just like any other Framework Class Library (FCL) type.
Dynamic is a built-in CLR primitive type - They are the most basic types that are expected to be interoperable as other compilers are also expected to provide support for primitive type.
Dynamic is CLS compliant – Types are CLS compliant and non compliant. For example, “int” is CLS compliant and “uint” is not a CLS compliant type. This means that according to the CLS guidelines, it is necessary for each language targeting the CLR to provide support for the types that are CLS compliant as in case of “int” whereas it is not necessary for the language to provide any support for “uint”. Since dynamic is a CLS compliant type, it is to be supported by every language that targets the CLR.
To the CLR, dynamic is similar to Object type. However, the C# complier allows the operations on a dynamic type to be skipped during compile time and allows a dynamic dispatch at runtime.
To sum up, in the Dynamic world we have the following things happening:
- Types defined at runtime
- No compiler (usually)
- Late binding
- Interpreted (not always)
Where as in the Static world:
- Type can be implicit (var) or explicit
- Compiler safety
- Early binding
When to use Dynamic?
The simple answer to this question is, we have many situations in which it is not really clear on how to act until it is at runtime. It is not that C# does not support to work in these situations but the syntax becomes unusual and a little difficult to understand (C# achieves this by providing support for Reflection). To make it easier for developers writing code using reflection and communication with other components, the C# compiler offers support for dynamic type. Dynamic expressions or variables can be used to invoke members (fields, properties, methods, delegates and operators) on a Type.
Dynamic and Compiler
When some code invokes a member using a dynamic variable, the C# compiler generates special IL code called as payload. A payload is emitted by the compiler in the IL for the fields that are marked with the DynamicAttribute. This payload is responsible for determining the exact operation that needs to be performed on the field at runtime. At runtime, payload determines the exact operation that needs to be called on the actual type of an object that we marked dynamic in the code.
Lets look at a sample code:
class Program
{
static void Main(string[] args)
{
int age = 10;
dynamic number = 10;
Console.WriteLine(age.ToString());
Console.WriteLine(number.ToString());
}
}
// Output of the Program
10
10
Output for the code above is expected but internally a lot of things are happening. So how are things working here?
At Compile time – Variable “age” is statically typed to be an integer. So the compiler knows about the various operations that can be performed on the type Integer. Hence call to age.ToString() is compiled correctly.
What about variable “number”? The compiler knows the type of the variable is dynamic. So what happens is that compiler converts this type to System.Object type and applies a System.Runtime.CompilerServices.DynamicAttribute to the field in the type metadata. If we talk about the local variables of a type marked as dynamic, then those variables are not marked with this DynamicAttribute and they are simply marked of type Object.
It is possible to use dynamic for all reference types, value types, an interface, a delegate or a method. As described above, the compiler will simply mark that type of Type “Object” and apply a DynamicAttribute to it. For example :
dynamic number = 10;
is compiled as
[DynamicAttribute]
object number = 10;
So now you have an idea of how a dynamic type is compiled and what is its behavior, let’s go into further usage of dynamic.
Dynamic and Type Casting
As per the basic rules of typecasting in C#: “Compiler allows you to implicitly cast a type to its base type as such casts are considered safe. In all other cases compiler wants to explicitly cast the type to the desired typed and performs a type check for the same.”
Int i = 10;
Object e = i; // OK (boxing)
Int b = e; // Error, Explicit cast required at compile time (unboxing)
Int c = (Int) e; // OK, Explicitly cast specified (unboxing)
As mentioned above, dynamic type is converted into object type. But here the compiler will allow implicit cast of a dynamic variable.
dynamic i = 10; // (boxing)
Int a = i; // OK (unboxing)
The main idea behind the casting is to avoid runtime conversion errors. But what happens in the case with dynamic. So at runtime, the compiler will validate the cast at runtime to ensure the type safety is maintained. If the object type is not compatible with the cast then an InvalidCastException is thrown.
Dynamic and Reflection in .NET
CLR provides this feature known as Reflection which helps developers to query metadata about any assembly at runtime and perform operations as required. So if you have an assembly (commonly .dll), and you are not aware of any information about the assembly, then Reflection is the thing, that you can look forward to program with.
Proceeding with a simple example:
Here is the code that loads mscorlib.dll from the disk location, then looks for “System.Console” type in this assembly. Then it attempts to find a method named “WriteLine” overload with string parameter. After it finds one, it invokes the method passing “Hello”.
Version 1:
class Program
{
static void Main(string[] args)
{
//// Using Reflection invoke a method on a type
// Load the assembly from the location passed
var assembly = Assembly.LoadFrom(@"C:\Program Files\Reference Assemblies\
Microsoft\Framework\.NETFramework\v4.5\mscorlib.dll");
// Get a type defined in the loaded assembly
var getTypes = assembly.GetType("System.Console");
// Get a method in the Type named WriteLine
var methodName = getTypes.GetMethod("WriteLine",
new Type[] { typeof(string) });
// Invokes the method with parameter specified
methodName.Invoke(getTypes, new object[] { "Hello" });
// To generate a pause
Console.ReadLine();
}
}
The code below does the same thing as the code above:
Version 2:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(“Hello”);
}
}
The simple question is – “Which version of the code you want to write?”
The obvious answer – “Version 2”
The obvious reason – It is easy to read and fast to write and does the same thing.
That being said, it does have some performance overhead. Since the code using dynamic emits payload that requires the CLR to load a set of assemblies before it is able to generate the code at runtime. Just to point out, Microsoft.CSharp.dll contains the language rules and syntax for the dynamic which depends on other assemblies that includes – System.dll, System.Core.dll and System.Dynamic.dll. Due to this overhead, you should decide that you get sufficient benefit with the code syntax simplification before using dynamic.
Creating Dynamic Types
You can create your own Dynamic types. The CLR provides you with the class DynamicObject and interface IDynamicMetaObjectProvider.
Let’s look at the DynamicObject type and it’s usage to create a Dynamic type of our own.
Dynamic Object allows you to override all the method implementations that can be used to perform various operations on the members of a type. Here we have a simple Dictionary of string as keys and objects as values. With this you can store the values in the dictionary and then get them back. You need to a key value that will get you a Type (object) that is invoked at runtime.
public class DynamicType : DynamicObject
{
IDictionary<string, object> members = new Dictionary<string, object>();
public override bool TrySetMember(SetMemberBinder binder, object value)
{
members[binder.Name] = value;
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
if (members.ContainsKey(binder.Name))
{
result = members[binder.Name];
return true;
}
return false;
}
}
Every time you invoke a member using instance of this class, you invoke the method on the type which will store the member information in the dictionary.
Try running the following code:
dynamic a = new DynamicType();
a.Name = "CLR Dynamic"; // Invokes the TrySetMember
a.Likes = "using dynamic"; // Invokes the TrySetMember
Console.WriteLine(a.Name); // Invokes the TryGetMember
Console.WriteLine(a.Likes); // Invokes the TryGetMember
Every time you invoke a member using instance of this class, you invoke the method on the type which will store the member. As normally in case of a simple class where we have members that are defined already in code, here we can simply create members on a type dynamically and invoke them like a normal class. This feature can be used in a very powerful way when it makes sense to use this.
On a type that is not derived from DynamicObject, the CLR will perform all the dynamic operations using reflection and in other case, it uses the implementation defined as in the case above.
So now you should have an understanding of how dynamic works in .NET 4. There are many frameworks implemented using dynamic features.
For further understanding and usage here are a few references:
No new comments are allowed on this post.
Comments
No comments yet. Be the first!