Introduction

In C#, a model usually refers to a strongly typed class that represents structured data (for example, a DTO, entity, or domain object). However, there are many scenarios where you may want to create objects without defining a formal model class:

This article explains the best technical approaches to creating objects without a model in C#, with examples, pros, cons, and guidance on when to use each approach.

1. Anonymous Types (Best for Local, Read-Only Data)

Overview

Anonymous types allow you to create an object without defining a class, directly inline in your code. The compiler generates a temporary type for you.

Example

var user = new
{
    Id = 1,
    Name = "Alice",
    IsActive = true
};

Console.WriteLine(user.Name);

Characteristics

Pros

Very concise and readable
Strongly typed (compile-time safety)
No class definition required

Cons

Cannot return from public methods easily
Cannot modify properties
Not suitable for complex logic or reuse

Best Use Cases

2. dynamic Objects (Best for Runtime Flexibility)

Overview

The dynamic keyword defers type checking to runtime, allowing you to add or change properties dynamically.

Example

dynamic user = new ExpandoObject();
user.Id = 1;
user.Name = "Bob";
user.IsActive = true;

Console.WriteLine(user.Name);

Required Namespace

using System.Dynamic;

Pros

Extremely flexible
Properties can be added/removed at runtime
Ideal for JSON or loosely typed data

Cons

No compile-time safety
Runtime errors possible
Slower performance than strongly typed objects

Best Use Cases

3. Dictionary<string, object> (Best for Data-Driven Scenarios)

Overview

Using a dictionary allows you to store key-value pairs where values can be of any type.

Example

var user = new Dictionary<string, object>
{
    { "Id", 1 },
    { "Name", "Charlie" },
    { "IsActive", true }
};

Console.WriteLine(user["Name"]);

Pros

Simple and explicit
Fully dynamic structure
Easy to serialize/deserialize

Cons

No IntelliSense support
Manual casting required
Error-prone for large datasets

Best Use Cases

4. Tuples (Best for Small, Structured Data)

Overview

Tuples provide a lightweight way to group multiple values without a model class.

Example

var user = (Id: 1, Name: "Diana", IsActive: true);

Console.WriteLine(user.Name);

Pros

Lightweight and fast
Named fields improve readability
Compile-time type safety

Cons

Not expressive for complex domains
Limited scalability
Not suitable for APIs or persistence

Best Use Cases

5. JSON-Based Objects (JsonElement / JObject)

Overview

When working with JSON-heavy systems, you can manipulate objects without defining models using JSON APIs.

Example (System.Text.Json)

using System.Text.Json;

string json = "{ \"Id\": 1, \"Name\": \"Eva\" }";
JsonElement user = JsonSerializer.Deserialize<JsonElement>(json);

Console.WriteLine(user.GetProperty("Name").GetString());

Pros

Ideal for schema-less data
No model maintenance
Common in microservices

Cons

Verbose access syntax
Runtime errors possible
Harder to refactor

Best Use Cases

Comparison Table

ApproachType SafetyFlexibilityPerformanceBest For
Anonymous TypeHighLowHighLINQ, local logic
dynamic / ExpandoObjectNoneVery HighMediumRuntime data
DictionaryLowHighMediumMetadata
TupleHighLowVery HighSmall data
JSON ObjectsLowHighLowExternal APIs

Best Practice Recommendation

Use Anonymous Types when:

Use Tuples when:

Use dynamic / ExpandoObject when:

Avoid dynamic approaches when:

Rule of Thumb: If the data structure is stable and reused, create a model class. If it is temporary or dynamic, choose one of the approaches above.

Conclusion

Creating objects without a model in C# is powerful when used correctly. Each technique has trade-offs between flexibility, safety, and maintainability. Choosing the right approach depends on scope, lifetime, and reliability requirements.

For production systems, prefer strongly typed models. For short-lived, dynamic, or exploratory code, the approaches above provide clean and efficient alternatives.