C# Data Types – Difference Between var, dynamic, and object
In C#, var, dynamic, and object can all be used to declare variables, but they differ in type inference, type checking, method resolution, and runtime behavior.
The most important difference is when the compiler determines or checks the type.
1. What is var in C#?
The var keyword allows the compiler to automatically infer the variable's type from the assigned value at compile time.
Once the type is inferred, it cannot change.
Example
var age = 30; // int
var name = "John"; // string
var salary = 50000.50; // double
Console.WriteLine(age);
Console.WriteLine(name);
Console.WriteLine(salary);
Explanation:
-
var age = 30→ Compiler determines the type asint. -
var name = "John"→ Compiler determines the type asstring. -
var salary = 50000.50→ Compiler determines the type asdouble. -
Type checking happens at compile time.
-
Once inferred, the variable's type is fixed.
Can we change the type of a var variable?
var age = 30;
age = 40; // Valid
age = "Forty"; // Compile-time error
Why?
The compiler has already determined that age is an int. Therefore, assigning a string is not allowed.
Can we declare var without initialization?
var age; // Compile-time error
Reason: The compiler cannot determine the type without an initializer.
Correct:
var age = 30;
Key Points
-
Type Inference: Compiler determines the type automatically.
-
Type Checking: Compile time.
-
Type Safety: Strongly typed.
-
Initialization: Required when declaring a local variable using
var. -
Type Change: Not allowed after inference.
-
Performance: No inherent performance difference compared with an explicitly declared equivalent type.
-
Common Usage: LINQ queries, anonymous types, and local variables.
2. What is dynamic in C#?
The dynamic keyword allows operations on a variable to be resolved at runtime instead of compile time.
The compiler generally does not validate whether the requested methods or properties exist. These operations are checked when the program executes.
Example
dynamic value = 100;
Console.WriteLine(value); // 100
value = "Hello";
Console.WriteLine(value); // Hello
value = 25.50;
Console.WriteLine(value); // 25.5
Explanation:
-
Initially,
valuecontains an integer. -
Later, it contains a string.
-
Finally, it contains a double.
-
The compiler permits these assignments.
-
Operations involving
dynamicare resolved at runtime.
What happens if we call a method that does not exist?
dynamic value = "Hello";
Console.WriteLine(value.Length); // 5
value.TestMethod(); // Runtime error
The compiler allows TestMethod() because value is dynamic.
However, the method does not exist on string, so execution throws a RuntimeBinderException.
Key Points
-
Type Resolution: Operations are resolved at runtime.
-
Type Checking: Dynamic operations bypass normal compile-time member checking.
-
Type Safety: Less compile-time safety.
-
Initialization: Not required.
-
Type Change: Can reference values of different types.
-
Runtime Errors: Invalid method or property access can cause runtime exceptions.
-
Performance: Dynamic binding introduces runtime overhead.
-
Common Usage: COM interoperability, dynamic APIs, and scenarios where object structure is not known at compile time.
3. What is object in C#?
object is the base type of all C# types, representing System.Object.
It can hold values of any type because every C# type can be converted to object.
Unlike dynamic, object uses normal compile-time type checking.
Example
object value = 100;
Console.WriteLine(value); // 100
value = "Hello";
Console.WriteLine(value); // Hello
value = 25.50;
Console.WriteLine(value); // 25.5
Explanation:
-
objectcan hold an integer, string, or double. -
Assigning a value type such as
inttoobjectcauses boxing. -
Assigning a reference type such as
stringcopies its reference. -
The compiler treats the variable as
object. -
Accessing type-specific members requires casting or pattern matching.
Why do we need type casting with object?
object value = "Hello";
Console.WriteLine(value.Length); // Compile-time error
Why?
Although the actual object is a string, the variable's declared type is object.
The object type does not expose the Length property.
Correct approach:
object value = "Hello";
string text = (string)value;
Console.WriteLine(text.Length); // 5
Or:
object value = "Hello";
if (value is string text)
{
Console.WriteLine(text.Length);
}
Key Points
-
Base Type:
objectis the base type of all C# types. -
Type Checking: Compile time.
-
Type Safety: Strongly typed as
object. -
Initialization: Not required.
-
Type Change: Can hold values of different types.
-
Type Casting: Required to access type-specific members not exposed by
object. -
Boxing: Occurs when assigning a value type to
object. -
Common Usage: General-purpose APIs, heterogeneous collections, and interoperability.
4. Difference Between var, dynamic, and object
|
Feature |
|
|
|
|---|---|---|---|
|
Type determination |
Compile time |
Runtime binding for operations |
Declared as |
|
Type checking |
Compile time |
Runtime for dynamic operations |
Compile time |
|
Strongly typed |
Yes |
Dynamic binding |
Yes |
|
Initialization required |
Yes |
No |
No |
|
Can hold different types |
No, unless compatible with inferred type |
Yes |
Yes |
|
Type-specific members |
Direct access |
Direct syntax, runtime validation |
Casting usually required |
|
Boxing for value types |
Not inherently |
May occur |
Yes |
|
Runtime overhead |
No inherent overhead |
Dynamic binding overhead |
Casting/boxing may add overhead |
|
Common usage |
LINQ, local variables |
Dynamic interoperability |
General-purpose object storage |
5. Simple Example – All Three Together
// VAR
var a = "Hello";
Console.WriteLine(a.Length); // 5
// a = 100; // Compile-time error
// DYNAMIC
dynamic b = "Hello";
Console.WriteLine(b.Length); // 5
b = 100; // Valid
// Console.WriteLine(b.Length); // Runtime error
// OBJECT
object c = "Hello";
// Console.WriteLine(c.Length); // Compile-time error
Console.WriteLine(((string)c).Length); // 5
c = 100; // Valid
How type checking works
VAR
---
var x = "Hello";
|
v
Compiler infers string
|
v
Compile-time type checking
|
v
Execute
DYNAMIC
-------
dynamic x = "Hello";
|
v
Compiler defers dynamic operations
|
v
Execute
|
v
Runtime resolves methods/properties
|
v
Success or Runtime Exception
OBJECT
------
object x = "Hello";
|
v
Compiler treats x as object
|
v
Compile-time type checking
|
v
Cast to string for string-specific members
|
v
Execute
6. When Should We Use Each?
|
Scenario |
Recommended |
|---|---|
|
Variable type is clear from initialization |
|
|
LINQ queries with anonymous types |
|
|
Interacting with dynamically typed APIs |
|
|
COM interoperability |
|
|
Storing values of unrelated types |
|
|
Working with a general-purpose API accepting any type |
|
Real-world example using LINQ
var employees = dbContext.Employees
.Where(x => x.IsActive)
.Select(x => new
{
x.Id,
x.Name
})
.ToList();
Here, var is particularly useful because the query returns a list of anonymous objects whose type cannot be written directly using a normal C# type name.
7. Important Interview Follow-up Questions
Q1. Is var a data type?
No. var is a keyword that tells the compiler to infer the local variable's type.
Q2. Is dynamic the same as object?
No. Both can hold different types, but dynamic allows runtime-bound member access, while object uses compile-time member checking.
Q3. Does var affect performance?
No inherent overhead. The compiler resolves the type at compile time.
Q4. Does dynamic affect performance?
Yes, dynamic operations can introduce runtime binding overhead.
Q5. Can we use var as a method parameter?
No. var cannot be used as a normal method parameter type.
public void Test(var value) // Invalid
{
}
However, dynamic and object are allowed.
public void Test(dynamic value) { }
public void Test(object value) { }
Q6. Does dynamic support IntelliSense?
Static member suggestions are limited because the compiler does not know the runtime type of a dynamic value.
Quick Interview Revision
|
Keyword |
Remember |
|---|---|
|
|
Type inferred at compile time |
|
|
Operations resolved at runtime |
|
|
Base type of all C# types |
|
|
Cannot change its inferred type |
|
|
Invalid members can cause runtime errors |
|
|
Casting is usually required for type-specific members |
Interview Answer:
var is used for compile-time type inference, so the inferred type is fixed and checked by the compiler. dynamic defers member resolution to runtime, allowing flexible operations but introducing potential runtime exceptions. object is the base type of all C# types and supports storing different types, but type-specific operations generally require casting. For most normal development, prefer var or explicit types, and use dynamic only when runtime binding is genuinely required.