dynamic Keyword in C#

The dynamic keyword in C# is used to delay type checking until runtime. Normally, C# is statically typed, which means the compiler checks whether methods, properties, and operations are valid before the program runs. With dynamic, the compiler skips many of those checks and lets the runtime decide whether the operation is valid.

This makes dynamic powerful in special situations, but also risky when used carelessly. It can make code flexible when dealing with dynamic data, COM objects, reflection-like scenarios, scripting, or loosely structured objects. At the same time, it can hide errors until runtime and reduce the safety that makes C# reliable.


What Is dynamic in C#?

dynamic is a type-like keyword that tells the compiler to defer member binding and type checking to runtime.

dynamic value = "Hello";
Console.WriteLine(value.Length);

This works because at runtime the value is a string, and strings have a Length property. The compiler does not verify that property at compile time in the same way it would for a statically typed string variable.

dynamic trades compile-time safety for runtime flexibility.

Basic Syntax of dynamic

dynamic variableName = value;

Example:

dynamic data = 100;
Console.WriteLine(data);

data = "Now I am text";
Console.WriteLine(data);

A dynamic variable can refer to values of different runtime types during execution. The compiler allows this because checks are delayed.

Runtime Binding

Runtime binding means that member access, method calls, and operations are resolved while the program is running. If the operation is valid for the actual runtime object, it works. If it is not valid, the program throws a runtime exception.

dynamic value = 10;
Console.WriteLine(value.Length); // Runtime error

This compiles, but it fails at runtime because an integer does not have a Length property.

dynamic vs var

dynamic and var are often confused, but they are completely different.

Featurevardynamic
Type decidedCompile timeRuntime
Type safetyStrong compile-time checkingRuntime checking
Can change apparent type?NoYes, depending on assigned value
Common useCleaner local declarationsDynamic runtime scenarios
var x = 10;
// x = "text"; // Compile-time error

dynamic y = 10;
y = "text"; // Allowed

dynamic vs object

Both dynamic and object can hold values of different types, but member access behaves differently.

object obj = "Hello";
// Console.WriteLine(obj.Length); // Compile-time error

dynamic dyn = "Hello";
Console.WriteLine(dyn.Length); // Runtime binding

With object, the compiler only knows the variable as object, so string-specific members are not available without casting. With dynamic, the runtime checks the actual value.

Use Cases of dynamic in C#

  • Interacting with dynamic data structures.
  • Working with COM objects.
  • Handling objects from dynamic languages.
  • Some reflection-like operations.
  • Processing loosely structured JSON when no strong model is used.
  • Building scripting or plugin-style systems.

These use cases are real, but they are not everyday beginner scenarios. Most normal C# application code should prefer explicit types, generics, interfaces, records, classes, or well-defined models.

dynamic with JSON-Like Data

Developers sometimes use dynamic when working with data whose shape is not known at compile time. This can be convenient, but it also means missing properties may only fail at runtime.

dynamic user = GetUserData();
Console.WriteLine(user.Name);

If Name does not exist at runtime, the program fails. A strongly typed model is safer when the data shape is known.

Runtime Errors with dynamic

The biggest risk of dynamic is that errors move from compile time to runtime. Code that looks valid to the compiler may fail when executed.

dynamic item = "Laptop";
item.CalculateTotal(); // Runtime error if method does not exist

This is why dynamic should be used only when its flexibility is genuinely needed.

Performance Consideration

Dynamic dispatch has extra runtime work compared with normal statically typed calls. For most small uses, this may not matter, but it should not be used casually in performance-sensitive loops or core application paths.

dynamic and the Runtime Binder

When a dynamic expression is executed, C# uses the runtime binder to decide what the operation actually means. The binder looks at the real runtime type of the value, the member name being accessed, the arguments being passed, and the available overloads. If it finds a valid operation, the code runs. If it cannot find one, the program throws a runtime binder exception.

This is why dynamic can feel similar to languages such as JavaScript or Python, but it still runs inside the C# and .NET type system. The object still has a real type. The difference is that the compiler does not prove the operation earlier. The decision is shifted from compile time to runtime.

dynamic number = 25;
Console.WriteLine(number.ToString());   // valid at runtime
Console.WriteLine(number.Length);       // runtime error

In this example, ToString() works because every object in .NET has that method. Length fails because an integer does not have a Length property. The compiler allows both lines, but the runtime accepts only the valid operation.

dynamic with Reflection-Like Scenarios

One practical reason developers use dynamic is to make reflection-like code easier to read. Reflection is powerful, but direct reflection code can become verbose because you have to manually search for properties, methods, and invoke them through metadata APIs. With dynamic, the syntax can become cleaner when the object shape is known by convention but not strongly represented in the current code.

That does not mean dynamic replaces reflection completely. Reflection gives more control and is better when you need to inspect types, loop through members, read attributes, or build generic tools. dynamic is more useful when you already expect a certain member to exist and you want simpler calling syntax.

ApproachBest UseMain Risk
dynamicCalling expected members on flexible objectsRuntime errors if the member is missing
ReflectionInspecting types and members programmaticallyVerbose code and slower member access
Strong typeNormal application logicLess flexible for unknown shapes

dynamic at Integration Boundaries

The safest place for dynamic is usually near an integration boundary. An integration boundary is the edge where your program talks to something less strongly typed, such as a JSON document, a script engine, an automation API, or an external system. In those places, the shape of the data may not be known fully at compile time.

A good design is to keep dynamic close to that boundary and convert the data into proper C# types as soon as possible. This keeps the flexible part small and protects the rest of the application from runtime binding problems.

dynamic externalUser = GetUserFromExternalSystem();

var user = new User
{
    Name = externalUser.name,
    Email = externalUser.email,
    IsActive = externalUser.active
};

After this conversion, the rest of the code can use the strongly typed User class. This is much safer than passing dynamic through service classes, controllers, repositories, and business logic. The farther dynamic travels, the harder the code becomes to test and maintain.

Safer Alternatives to dynamic

Before using dynamic, check whether a safer C# feature can solve the same problem. Many cases that look like they need dynamic can be handled with generics, interfaces, pattern matching, records, DTO classes, or dictionaries.

  • Use an interface when different classes share the same behavior.
  • Use generics when the type should stay flexible but still be checked by the compiler.
  • Use object with pattern matching when only a few known types are expected.
  • Use DTO classes when reading structured JSON or API responses.
  • Use a dictionary when keys and values are truly data-driven.
object input = "CSharp";

if (input is string text)
{
    Console.WriteLine(text.Length);
}

This version is safer than dynamic because the compiler understands that text is a string inside the if block. If you try to call a member that does not exist on string, the compiler catches it immediately.

Testing Code That Uses dynamic

Code that uses dynamic needs stronger tests because the compiler cannot catch every mistake. A typo in a property name, a changed external response, or an unexpected null value may only appear when that exact line executes. Unit tests are important here because they force those runtime paths to run before real users hit them.

At minimum, test the valid shape, missing members, wrong data types, and null values. If the dynamic value comes from an external API, also test a sample response that matches the real payload. This makes the flexible code safer without pretending it has the same compile-time guarantees as normal C#.

Use dynamic as a controlled adapter, not as a shortcut for weak design.

Practical Rules for Using dynamic

A practical rule is simple: if the type is known, do not use dynamic. If the type can be modeled with a class, interface, enum, or generic method, prefer that model. Use dynamic only when the shape of the object is genuinely not available to the compiler or when interoperability makes strong typing difficult.

Another important rule is to avoid storing dynamic values for long periods. Convert them quickly, validate them carefully, and keep them away from core business logic. This keeps the code flexible where needed but still allows most of the project to benefit from C# type safety, IntelliSense, refactoring support, and compile-time error checking.

Common Mistakes with dynamic in C#

  • Using dynamic instead of learning proper types.
  • Confusing dynamic with var.
  • Using dynamic values in core business logic without validation.
  • Expecting compile-time errors for invalid dynamic member access.
  • Overusing dynamic when interfaces or classes would be safer.
  • Ignoring runtime exceptions caused by missing members.
Is dynamic the same as var in C#?

No. var is compile-time type inference. dynamic delays type checking until runtime.

Is dynamic type-safe?

It is less type-safe than normal statically typed C# code because many checks happen at runtime instead of compile time.

Should beginners use dynamic?

Beginners should usually avoid dynamic until they understand static typing, object, var, generics, interfaces, and normal type conversion clearly.

Best Practices for dynamic in C#

  • Use dynamic only when runtime flexibility is required.
  • Prefer strong types when the data shape is known.
  • Validate dynamic data before using it deeply.
  • Keep dynamic usage close to integration boundaries.
  • Avoid dynamic in performance-critical loops.
  • Do not use dynamic as a shortcut to avoid proper design.
  • Document why dynamic is needed when the reason is not obvious.

The dynamic keyword in C# is useful for specific runtime scenarios, but it should be treated carefully. It gives flexibility by delaying type checks, but that flexibility comes with weaker compile-time safety, possible runtime errors, and reduced readability if overused.