Once I asked myself a question that stopped me for a second: "Why don't we just make everything dynamic? Then we never have to worry about types at all."
I knew var, object, and dynamic were different, I used var constantly and avoided dynamic out of some vague instinct...but I couldn't actually explain why in a way that would convince me.
They Look Similar. They Are Not the Same Thing.
All three let you write code without explicitly naming a concrete type on the left-hand side, which is exactly why they get confused:
var a = "hello";
object b = "hello";
dynamic c = "hello";All three compile. All three run. All three currently hold a string. But they behave completely differently the moment you do anything interesting with them, because each one represents a different stage at which C# figures out the type.
var: the type is decided at compile time, by the compiler, based on what's on the right-hand side.
object: the type is genuinely object at compile time, anything more specific is hidden until you cast it back.
dynamic: type checking is deferred to runtime entirely. The compiler steps back and just trusts you.
var
This is the one people misunderstand most. var is not "no type." It's not JavaScript's var. The compiler looks at the right-hand side, figures out the concrete type, and locks it in permanently at compile time.
var name = "Alice"; // compiler infers string
var count = 5; // compiler infers int
var product = GetProduct(); // compiler infers whatever GetProduct() returns
name = 42; // ERROR — name is a string, always was, always will beThis matters for performance too: since the type is fully known at compile time, there's zero runtime overhead.
object: Everything's Base Type, With a Boxing Tax
object is the ancestor of every type in C#, every class, every struct, everything. So you can store anything in an object variable. The catch is that once it's in there, the compiler only knows about the object members (ToString(), Equals(), GetHashCode(), GetType()), nothing else.
object o = "hello";
int length = o.Length; // ERROR — object has no Length propertyEven though the runtime value is clearly a string, the compiler refuses to let you call .Length on it, because as far as compile time type checking is concerned, o is just an object. To get the string back, you need an explicit cast:
object o = "hello";
string s = (string)o;
int length = s.Length; // fine nowThe Boxing Problem
When you put a value type into an object, C# has to "box" it, wrap the value type in a heap-allocated object so it can be referred to by reference.
int number = 42;
object boxed = number; // BOXING: number gets copied onto the heap
int unboxed = (int)boxed; // UNBOXING: copied back onto the stack
Join the conversation! Your thoughts help the community grow.