Back to Blog
C#

C# var vs dynamic: What's the Difference?

c# var vs dynamic: Understand the differences between C# var and dynamic, including type inference, runtime behavior, and when to use each for safer, more maintainable...

C#type inferencedynamic typingvar keywordcompile-time typeruntime binding
Illustration comparing C# var and dynamic type declarations, showing compile-time vs runtime type resolution.

c# var vs dynamic requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

When you write C# code, both var and dynamic let you avoid spelling out a type explicitly. That similarity leads many developers to treat them as interchangeable, but they solve completely different problems. var is a compile-time feature that infers the type from the initializer. dynamic defers type resolution to runtime, changing how the compiler treats the entire expression. Understanding the distinction is essential for writing code that is both safe and flexible.

What var and dynamic Actually Do

The var keyword tells the compiler to infer the variable's static type from the expression on the right side of the assignment. The inferred type is fixed at compile time, and the variable behaves exactly as if you had written the explicit type.

var count = 42; // count is int var name = "Ada"; // name is string var numbers = new List<int>(); // numbers is List<int>

dynamic, on the other hand, instructs the compiler to skip static type checking for that variable. The type is resolved at runtime using the Dynamic Language Runtime (DLR). Operations on a dynamic variable are bound when the code executes, not when it compiles.

dynamic value = GetValue(); // type unknown until runtime value.SomeMethod(); // resolved at runtime

This difference in timing has far-reaching consequences for type safety, performance, and how you handle errors.

Compile-Time Type vs Runtime Type

With var, the compiler knows the exact type of the variable. This gives you IntelliSense, compile-time error detection, and optimizations based on the concrete type. For example, the following code fails to compile because name is inferred as string:

var name = "Ada"; name++; // CS0021: Cannot apply operator '++' to operand of type 'string'

With dynamic, the compiler does not check whether an operation is valid. It emits code that performs the operation at runtime, throwing a RuntimeBinderException if the object does not support it.

dynamic name = "Ada"; name++; // Compiles, but throws RuntimeBinderException at runtime

This means dynamic shifts errors from compile time to runtime, which can make bugs harder to find. It also disables IntelliSense and other tooling that relies on static type information.

Performance and Overhead

var has zero runtime overhead. Because the compiler replaces var with the actual type, the generated IL is identical to using the explicit type. There is no boxing, no reflection, and no dynamic dispatch.

dynamic, however, introduces significant overhead. Every operation on a dynamic variable goes through the DLR, which performs runtime binding, caches call sites, and often falls back to reflection-like mechanisms. This can be orders of magnitude slower than a statically bound call, especially in loops or frequently executed paths.

Consider a simple method call:

static void CallWithVar() { var obj = new MyClass(); obj.DoSomething(); // direct call } static void CallWithDynamic() { dynamic obj = new MyClass(); obj.DoSomething(); // DLR dispatch }

The var version compiles to a standard virtual call. The dynamic version involves the DLR binder, which may cache the call site after the first invocation, but still incurs overhead for argument checking and type conversion. In tight loops, this difference becomes measurable.

When to Use var

var is the default choice for local variables in modern C#. It makes code more concise without sacrificing type safety. Use it when the type is obvious from the initializer, such as with new expressions, casts, or LINQ queries.

var options = new Dictionary<string, string>(); var query = products.Where(p => p.Price > 100); var result = (Result)something;

var is also necessary for anonymous types, which have no explicit name:

var person = new { Name = "Ada", Age = 36 };

Avoid var when it obscures the type and hurts readability, such as when the initializer is a method call with a non-obvious return type. In those cases, an explicit type is clearer.

When to Use dynamic

dynamic is a tool for specific interop scenarios. The most common use is working with COM APIs like Microsoft Office, where methods accept and return object and the real types are only known at runtime. Another is calling into dynamic languages such as IronPython or JavaScript via the DLR.

dynamic excel = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application")); excel.Visible = true; var workbook = excel.Workbooks.Add();

dynamic is also useful when you need to work with reflection-heavy code and want to avoid repetitive casting. For example, accessing a property by name on an object that does not implement a known interface:

dynamic settings = LoadSettings(); int timeout = settings.Timeout; // resolved at runtime

However, using dynamic in ordinary application code often signals a design problem. It bypasses the type system and makes the code harder to maintain, because there is no compile-time contract to rely on.

Common Pitfalls and Misconceptions

A frequent mistake is assuming var is the same as object or that it introduces dynamic behavior. It does not. var is strictly a compile-time feature; the variable has a concrete type from declaration onward.

Another misconception is that dynamic is just a more flexible var. In reality, dynamic changes the semantics of every operation involving the variable. For instance, method overload resolution happens at runtime, not compile time. This can lead to surprising behavior:

static void Print(int value) => Console.WriteLine($"int: {value}"); static void Print(string value) => Console.WriteLine($"string: {value}"); static void Main() { dynamic d = 42; Print(d); // calls Print(int) at runtime }

If d were declared as var, the compiler would select the overload based on the inferred type. With dynamic, the selection is deferred, which can cause a RuntimeBinderException if no matching overload exists.

Comparison: var vs dynamic

The following table summarizes the key differences:

Aspectvardynamic
Type resolutionCompile timeRuntime
Type safetyFull static type checkingNo compile-time checking
IntelliSense supportYesNo
Runtime overheadNoneSignificant (DLR)
Error detectionAt compile timeAt runtime
Use casesLocal variables, LINQ, anonymous typesCOM interop, dynamic languages, reflection

Choosing Between var and dynamic in Real Code

In practice, the decision is straightforward: use var by default and reserve dynamic for scenarios that genuinely require runtime binding. If you are writing new code that does not involve interop or dynamic languages, there is rarely a reason to use dynamic. It introduces risk and overhead without adding value.

When you do use dynamic, isolate it. Keep dynamic variables at the boundary of your system, such as in a wrapper method that converts the dynamic result to a statically typed object as soon as possible. This limits the impact of runtime binding on the rest of your codebase.

How dynamic Affects Extension Methods and Operators

One subtle technical detail is that dynamic does not participate in extension method resolution. If you call an extension method on a dynamic variable, the compiler will not find it, because extension methods are resolved at compile time. For example:

static class StringExtensions { public static bool IsEmpty(this string s) => string.IsNullOrEmpty(s); } static void Main() { dynamic text = "hello"; // text.IsEmpty(); // RuntimeBinderException: 'string' does not contain a definition for 'IsEmpty' }

Similarly, operators like + are bound at runtime, which can lead to different behavior than expected if the operand types are not known. Understanding these limitations helps you avoid subtle bugs when mixing dynamic with otherwise static code.

For most C# development, var is the right choice. It gives you the benefits of static typing with concise syntax. dynamic is a powerful escape hatch for specific interoperability problems, but it should be used sparingly and with full awareness of its runtime costs and loss of compile-time safety.

c# var vs dynamic: Practical Usage and Code Examples | RYUSLOG DEV