What's the difference between dynamic (C# 4) and var?
I had read a ton of articles about that new keyword that is shipping with C# v4, but I couldn't make out the difference between a "dynamic" and "var".
This article made me think about it, but I still can't see any difference.
Is it that you can use "var" only as a local variable, but dynamic as both local and global?
Could you show some code without dynamic keyword and then show the same code with dynamic keyword?
var
is static typed - the compiler and runtime know the type - they just save you some typing... the following are 100% identical:
var s = "abc";
Console.WriteLine(s.Length);
and
string s = "abc";
Console.WriteLine(s.Length);
All that happened was that the compiler figured out that s
must be a string (from the initializer). In both cases, it knows (in the IL) that s.Length
means the (instance) string.Length
property.
dynamic
is a very different beast; it is most similar to object
, but with dynamic dispatch:
dynamic s = "abc";
Console.WriteLine(s.Length);
Here, s
is typed as dynamic. It doesn't know about string.Length
, because it doesn't know anything about s
at compile time. For example, the following would compile (but not run) too:
dynamic s = "abc";
Console.WriteLine(s.FlibbleBananaSnowball);
At runtime (only), it would check for the FlibbleBananaSnowball
property - fail to find it, and explode in a shower of sparks.
With dynamic
, properties / methods / operators / etc are resolved at runtime, based on the actual object. Very handy for talking to COM (which can have runtime-only properties), the DLR, or other dynamic systems, like javascript
.
Variables declared with var are implicitly but statically typed. Variables declared with dynamic are dynamically typed. This capability was added to the CLR in order to support dynamic languages like Ruby and Python.
I should add that this means that dynamic declarations are resolved at run-time, var declarations are resolved at compile-time.
I am going to explain difference between dynamic and var.
dynamic d1;
d1 = 1;
d1 = "http://mycodelogic.com";
This will work. compiler can re-create the type of dynamic variable.
first it create type as integer and after that compiler will recreate type as string
but in case of var
var v1; // Compiler will throw error because we have to initialized at the time of declaration
var v2 = 1; // Compiler will create v1 as **integer**
v2 = "Suneel Gupta"; // Compiler will throw error because, compiler will not recreate the type of variable
When using the ‘var’ keyword, the type is decided by the compiler at compile time, whereas when using the ‘dynamic’ keyword, the type is decided by the runtime.
‘var’ keyword, a strongly implicitly typed local variable for which the compiler is able to determine the type from the initialization expression - very useful when doing LINQ programming.
Compiler doesn't have any information about the dynamic type of variable. so compiler will not show any intelligence .
compiler has all information about the stored value of var type so compiler will show intelligence.
dynamic type can be passed as function argument and function also can return object type
But
var type can not be passed as function argument and function can not return object type. This type of variable can work in the scope where it defined.
var implies that static type checking (early binding) is applied. dynamic implies that dynamic type checking (late binding) is applied. In terms of the code, condsider the following:
class Junk
{
public void Hello()
{
Console.WriteLine("Hello");
}
}
class Program
{
static void Main(String[] args)
{
var a = new Junk();
dynamic b = new Junk();
a.Hello();
b.Hello();
}
}
If you compile this and inspect the results with ILSpy, you will find that the compiler has added some late binding code which will handle the call to Hello() from b, whereas becuase early binding was applied to a, a is able to call Hello() directly.
e.g. (ILSpy disassembly)
using System;
namespace ConsoleApplication1
{
internal class Junk
{
public void Hello()
{
Console.WriteLine("Hello");
}
}
}
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Runtime.CompilerServices;
namespace ConsoleApplication1
{
internal class Program
{
[CompilerGenerated]
private static class <Main>o__SiteContainer0
{
public static CallSite<Action<CallSite, object>> <>p__Site1;
}
private static void Main(string[] args)
{
Junk a = new Junk(); //NOTE: Compiler converted var to Junk
object b = new Junk(); //NOTE: Compiler converted dynamic to object
a.Hello(); //Already Junk so just call the method.
//NOTE: Runtime binding (late binding) implementation added by compiler.
if (Program.<Main>o__SiteContainer0.<>p__Site1 == null)
{
Program.<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Hello", null, typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
Program.<Main>o__SiteContainer0.<>p__Site1.Target(Program.<Main>o__SiteContainer0.<>p__Site1, b);
}
}
}
The best thing you can do to discover the difference is to write yourself a little console app like this one, and test it yourself with ILSpy.
One big difference - you can have a dynamic return type.
dynamic Foo(int x)
{
dynamic result;
if (x < 5)
result = x;
else
result = x.ToString();
return result;
}