var подразумевает, что применяется статическая проверка типов (раннее связывание). Динамический подразумевает, что применяется динамическая проверка типов (позднее связывание). С точки зрения кода, учитывайте следующее:
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();
}
}
Если вы скомпилируете это и проверите результаты с помощью ILSpy, вы обнаружите, что компилятор добавил некоторый код поздней привязки, который будет обрабатывать вызов Hello () из b, тогда как ранняя привязка была применена к a, a может вызвать Hello () напрямую.
например (разборка ILSpy)
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);
}
}
}
Лучшее, что вы можете сделать, чтобы обнаружить разницу, это написать себе небольшое консольное приложение, подобное этому, и протестировать его самостоятельно с помощью ILSpy.