Skip to main content

C# Dynamic Type

Introduction

The dynamic type is a powerful feature introduced in C# 4.0 that enables flexible programming by bypassing compile-time type checking. Unlike statically typed variables in C#, operations on dynamic objects are resolved at runtime rather than compile time. This makes dynamic particularly useful when dealing with data from dynamic sources or interoperating with dynamic languages and COM objects.

In this tutorial, you'll learn:

  • What the dynamic type is and how it differs from other types
  • How to use dynamic variables in C#
  • When to use (and when to avoid) the dynamic type
  • Real-world applications of dynamic typing

Understanding the Dynamic Type

What is the Dynamic Type?

The dynamic type is a static type that tells the compiler to skip type checking during compilation. When you declare a variable as dynamic, the compiler treats it specially:

csharp
dynamic myVariable = 10; // myVariable is an integer at runtime

With dynamic variables, operations that normally would be checked at compile time are deferred until runtime:

csharp
dynamic myVariable = 10;
myVariable = myVariable + 5; // Valid: adds 5 to 10
myVariable = myVariable.ToUpper(); // Runtime error: integers don't have ToUpper()

Dynamic vs. var vs. object

Let's compare dynamic with var and object to understand the key differences:

csharp
// var - implicitly typed but statically resolved at compile time
var number = 10;
// number.NonExistentMethod(); // Compile-time error

// object - explicit boxing, requires casting for specific operations
object obj = 10;
// int result = obj + 5; // Compile-time error
int result = (int)obj + 5; // Valid with explicit casting

// dynamic - resolved at runtime
dynamic dyn = 10;
dyn = dyn + 5; // Valid, no casting needed
dyn = "Hello"; // Can change type at runtime
dyn = dyn.ToUpper(); // Valid, resolved at runtime

Basic Usage of Dynamic Type

Creating and Using Dynamic Variables

Here's a simple example of creating and using dynamic variables:

csharp
using System;

class Program
{
static void Main()
{
// Create a dynamic variable
dynamic dynamicValue = 100;

// Perform operations
Console.WriteLine($"Original value: {dynamicValue}");

// We can perform integer operations
dynamicValue += 50;
Console.WriteLine($"After addition: {dynamicValue}");

// We can change the type
dynamicValue = "Hello, Dynamic World!";
Console.WriteLine($"New string value: {dynamicValue}");

// We can call string methods
Console.WriteLine($"Uppercase: {dynamicValue.ToUpper()}");

// We can even assign it to an object of a custom class
dynamicValue = new Person { Name = "John", Age = 30 };
Console.WriteLine($"Person's name: {dynamicValue.Name}");
}
}

class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

Output:

Original value: 100
After addition: 150
New string value: Hello, Dynamic World!
Uppercase: HELLO, DYNAMIC WORLD!
Person's name: John

Handling Dynamic Type Errors

Since type checking is done at runtime with dynamic types, errors that would normally be caught at compile time aren't discovered until the program runs:

csharp
using System;

class Program
{
static void Main()
{
dynamic dyn = 100;

try
{
// This will cause a runtime error
Console.WriteLine(dyn.Substring(1, 3));
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex)
{
Console.WriteLine($"Runtime error: {ex.Message}");
}
}
}

Output:

Runtime error: 'int' does not contain a definition for 'Substring'

Advanced Dynamic Type Usage

Working with Dynamic Objects

C# provides the ExpandoObject class that lets you create objects with properties and methods added dynamically at runtime:

csharp
using System;
using System.Dynamic;

class Program
{
static void Main()
{
// Create a dynamic ExpandoObject
dynamic person = new ExpandoObject();

// Add properties dynamically
person.Name = "Alice";
person.Age = 28;

// Add a method dynamically
person.Greet = (Action)(() =>
Console.WriteLine($"Hello, my name is {person.Name} and I'm {person.Age} years old!")
);

// Use the dynamic object
Console.WriteLine($"Name: {person.Name}");
Console.WriteLine($"Age: {person.Age}");
person.Greet();

// Add new property at runtime
person.Occupation = "Software Developer";
Console.WriteLine($"Occupation: {person.Occupation}");
}
}

Output:

Name: Alice
Age: 28
Hello, my name is Alice and I'm 28 years old!
Occupation: Software Developer

Creating Custom Dynamic Objects

You can create your own dynamic objects by implementing the DynamicObject class:

csharp
using System;
using System.Dynamic;
using System.Collections.Generic;

class Program
{
static void Main()
{
dynamic dynamicDictionary = new DynamicDictionary();

// Set properties dynamically
dynamicDictionary.FirstName = "John";
dynamicDictionary.LastName = "Smith";
dynamicDictionary.Age = 42;

// Get properties
Console.WriteLine($"Full name: {dynamicDictionary.FirstName} {dynamicDictionary.LastName}");
Console.WriteLine($"Age: {dynamicDictionary.Age}");

// Try to access non-existent property
Console.WriteLine($"Email exists: {dynamicDictionary.HasProperty("Email")}");
}
}

// A dynamic dictionary that stores properties
public class DynamicDictionary : DynamicObject
{
// The inner dictionary
private Dictionary<string, object> _dictionary = new Dictionary<string, object>();

// Override TryGetMember to handle property access
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
return _dictionary.TryGetValue(name, out result);
}

// Override TrySetMember to handle property assignment
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dictionary[binder.Name] = value;
return true;
}

// Custom method to check if a property exists
public bool HasProperty(string name)
{
return _dictionary.ContainsKey(name);
}
}

Output:

Full name: John Smith
Age: 42
Email exists: False

Practical Applications

JSON Deserialization

The dynamic type is particularly useful when working with JSON data where the structure might not be known at compile time:

csharp
using System;
using System.Text.Json;

class Program
{
static void Main()
{
// JSON string with arbitrary structure
string jsonString = @"{
""name"": ""Product X"",
""price"": 29.99,
""specifications"": {
""weight"": ""1.5 kg"",
""dimensions"": ""10 x 20 x 5 cm""
},
""inStock"": true
}";

// Parse JSON to dynamic object
dynamic jsonData = JsonSerializer.Deserialize<System.Text.Json.JsonDocument>(jsonString)
.RootElement.JsonElementAsDynamic();

// Access properties dynamically
Console.WriteLine($"Product: {jsonData.name}");
Console.WriteLine($"Price: ${jsonData.price}");
Console.WriteLine($"Weight: {jsonData.specifications.weight}");
Console.WriteLine($"In Stock: {(jsonData.inStock ? "Yes" : "No")}");
}
}

// Extension to make JsonElement work better with dynamic
public static class JsonExtensions
{
public class DynamicJsonElement : DynamicObject
{
private readonly JsonElement _element;

public DynamicJsonElement(JsonElement element)
{
_element = element;
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_element.ValueKind == JsonValueKind.Object &&
_element.TryGetProperty(binder.Name, out JsonElement property))
{
result = property.JsonElementAsDynamic();
return true;
}

result = null;
return false;
}
}

public static dynamic JsonElementAsDynamic(this JsonElement element)
{
switch (element.ValueKind)
{
case JsonValueKind.String:
return element.GetString();
case JsonValueKind.Number:
if (element.TryGetInt32(out int intValue))
return intValue;
return element.GetDouble();
case JsonValueKind.True:
return true;
case JsonValueKind.False:
return false;
case JsonValueKind.Object:
return new DynamicJsonElement(element);
default:
return null;
}
}
}

Output:

Product: Product X
Price: $29.99
Weight: 1.5 kg
In Stock: Yes

COM Interoperability

One of the most practical uses of dynamic is for COM interoperability, such as when working with Microsoft Office applications:

csharp
using System;

class Program
{
static void ExcelExample()
{
// Create Excel application instance
Type excelType = Type.GetTypeFromProgID("Excel.Application");
dynamic excel = Activator.CreateInstance(excelType);

try
{
// Make Excel visible
excel.Visible = true;

// Add a new workbook
dynamic workbook = excel.Workbooks.Add();
dynamic worksheet = workbook.Worksheets[1];

// Add some data
worksheet.Cells[1, 1] = "Name";
worksheet.Cells[1, 2] = "Score";

worksheet.Cells[2, 1] = "Alice";
worksheet.Cells[2, 2] = 95;

worksheet.Cells[3, 1] = "Bob";
worksheet.Cells[3, 2] = 87;

// Format headers
dynamic headerRange = worksheet.Range["A1:B1"];
headerRange.Font.Bold = true;

Console.WriteLine("Excel document created. Press Enter to close.");
Console.ReadLine();
}
finally
{
// Clean up
excel.Quit();

// Release COM object
System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
}
}

static void Main()
{
// Note: This would require Microsoft Excel to be installed
Console.WriteLine("This example requires Microsoft Excel. Run it? (y/n)");
if (Console.ReadLine().ToLower() == "y")
{
try
{
ExcelExample();
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
}

Performance Considerations

While dynamic is powerful, it comes with performance overhead since type checking happens at runtime. Here's a comparison:

csharp
using System;
using System.Diagnostics;

class Program
{
static void Main()
{
const int iterations = 10000000;

// Test with regular int
Stopwatch sw1 = Stopwatch.StartNew();
int regularInt = 5;
for (int i = 0; i < iterations; i++)
{
regularInt += 1;
}
sw1.Stop();

// Test with dynamic
Stopwatch sw2 = Stopwatch.StartNew();
dynamic dynamicInt = 5;
for (int i = 0; i < iterations; i++)
{
dynamicInt += 1;
}
sw2.Stop();

Console.WriteLine($"Static type (int): {sw1.ElapsedMilliseconds} ms");
Console.WriteLine($"Dynamic type: {sw2.ElapsedMilliseconds} ms");
Console.WriteLine($"Dynamic is {(double)sw2.ElapsedMilliseconds / sw1.ElapsedMilliseconds:F1}x slower");
}
}

Output (results may vary):

Static type (int): 6 ms
Dynamic type: 402 ms
Dynamic is 67.0x slower

When to Use Dynamic Type

Good Use Cases

  • Working with COM interop (Office automation, legacy COM components)
  • Parsing JSON or XML with unknown structure at compile time
  • Interacting with dynamic languages like Python or JavaScript
  • Creating domain-specific languages within C#
  • Simplifying reflection-heavy code

When to Avoid

  • Performance-critical code
  • Code where compile-time type safety is important
  • Public APIs (prefer strongly-typed interfaces)
  • Large applications where maintainability is a concern
  • When other features like generics would be more appropriate

Summary

The dynamic type in C# provides flexibility by delaying type checking until runtime, allowing for more dynamic programming patterns in an otherwise statically typed language. We've explored:

  • How the dynamic type works and how it differs from var and object
  • Basic and advanced usage of dynamic variables
  • Creating custom dynamic objects
  • Practical applications in JSON handling and COM interoperability
  • Performance implications and best practices

While powerful, the dynamic type should be used judiciously, with an understanding of its performance implications and the trade-offs involved in bypassing C#'s compile-time type checking.

Additional Resources

Exercises

  1. Create a dynamic calculator that can perform operations on different types (integers, decimals, strings)
  2. Implement a custom DynamicObject that validates property values before assignment
  3. Create a simple data access layer using dynamic to handle database results
  4. Use dynamic to parse and manipulate different JSON structures
  5. Compare the performance of reflection-based property access versus dynamic-based access


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)