Serialization
Complete guide to serializing .NET objects to TOON format using ToonSerializer.
Overview
ToonSerializer is a static class that provides methods for converting .NET objects to TOON format. It uses expression trees (not reflection) for high performance.
Basic Serialization
Serialize to String
using ToonNet.Core;
var person = new Person { Name = "Alice", Age = 30 };
string toon = ToonSerializer.Serialize(person);
Serialize to Stream
using var stream = new MemoryStream();
ToonSerializer.Serialize(stream, person);
// Or with explicit encoding
ToonSerializer.Serialize(stream, person, Encoding.UTF8);
Serialize to File
// Synchronous
ToonSerializer.SerializeToFile("person.toon", person);
// Asynchronous
await ToonSerializer.SerializeToFileAsync("person.toon", person);
Serialization Options
Using ToonSerializerOptions
Configure serialization behavior with ToonSerializerOptions:
var options = new ToonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = PropertyNamingPolicy.CamelCase,
IgnoreNullValues = false
};
string toon = ToonSerializer.Serialize(person, options);
Write Indented (Formatting)
Control output formatting:
// Compact (default)
var options = new ToonSerializerOptions { WriteIndented = false };
string compact = ToonSerializer.Serialize(person, options);
// Output: Name: Alice\nAge: 30
// Indented (readable)
var options = new ToonSerializerOptions { WriteIndented = true };
string indented = ToonSerializer.Serialize(person, options);
// Output (with proper indentation for nested objects)
Property Naming Policy
Transform property names during serialization:
public enum PropertyNamingPolicy
{
Default, // Keep original names (default)
CamelCase, // firstName, lastName
SnakeCase, // first_name, last_name
KebabCase, // first-name, last-name
PascalCase // FirstName, LastName
}
Example:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
var person = new Person
{
FirstName = "Alice",
LastName = "Smith",
Age = 30
};
// Default naming
var defaultOptions = new ToonSerializerOptions
{
PropertyNamingPolicy = PropertyNamingPolicy.Default
};
string toon1 = ToonSerializer.Serialize(person, defaultOptions);
// Output:
// FirstName: Alice
// LastName: Smith
// Age: 30
// CamelCase naming
var camelOptions = new ToonSerializerOptions
{
PropertyNamingPolicy = PropertyNamingPolicy.CamelCase
};
string toon2 = ToonSerializer.Serialize(person, camelOptions);
// Output:
// firstName: Alice
// lastName: Smith
// age: 30
// SnakeCase naming
var snakeOptions = new ToonSerializerOptions
{
PropertyNamingPolicy = PropertyNamingPolicy.SnakeCase
};
string toon3 = ToonSerializer.Serialize(person, snakeOptions);
// Output:
// first_name: Alice
// last_name: Smith
// age: 30
Ignore Null Values
Control null value serialization:
public class User
{
public string Username { get; set; }
public string? Bio { get; set; }
public string? Website { get; set; }
}
var user = new User
{
Username = "alice",
Bio = "Engineer",
Website = null
};
// Include nulls (default)
var includeNulls = new ToonSerializerOptions { IgnoreNullValues = false };
string toon1 = ToonSerializer.Serialize(user, includeNulls);
// Output:
// Username: alice
// Bio: Engineer
// Website: null
// Ignore nulls
var ignoreNulls = new ToonSerializerOptions { IgnoreNullValues = true };
string toon2 = ToonSerializer.Serialize(user, ignoreNulls);
// Output:
// Username: alice
// Bio: Engineer
Advanced Scenarios
Serialize Collections
// Array
int[] numbers = { 1, 2, 3, 4, 5 };
string toon = ToonSerializer.Serialize(numbers);
// List
List<string> names = new() { "Alice", "Bob", "Charlie" };
string toon = ToonSerializer.Serialize(names);
// Dictionary
Dictionary<string, int> scores = new()
{
["Math"] = 95,
["Physics"] = 87
};
string toon = ToonSerializer.Serialize(scores);
Serialize with Custom Converters
Register custom converters for specific types:
var options = new ToonSerializerOptions();
options.Converters.Add(new CustomDateTimeConverter());
string toon = ToonSerializer.Serialize(obj, options);
See Custom Converters for details.
Serialize Polymorphic Types
public abstract class Shape
{
public string Color { get; set; }
}
public class Circle : Shape
{
public double Radius { get; set; }
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
}
// Serialize as base type
Shape shape = new Circle { Color = "Red", Radius = 5.0 };
string toon = ToonSerializer.Serialize<Shape>(shape);
// Output includes all properties from Circle
Serialize Complex Nested Structures
public class Company
{
public string Name { get; set; }
public List<Department> Departments { get; set; }
}
public class Department
{
public string Name { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee
{
public string Name { get; set; }
public string Position { get; set; }
public Dictionary<string, int> Skills { get; set; }
}
var company = new Company
{
Name = "TechCorp",
Departments = new List<Department>
{
new Department
{
Name = "Engineering",
Employees = new List<Employee>
{
new Employee
{
Name = "Alice",
Position = "Senior Engineer",
Skills = new Dictionary<string, int>
{
["C#"] = 9,
["Python"] = 7
}
}
}
}
}
};
string toon = ToonSerializer.Serialize(company);
Output:
Name: TechCorp
Departments:
- Name: Engineering
Employees:
- Name: Alice
Position: Senior Engineer
Skills:
C#: 9
Python: 7
Async Serialization
Serialize to Stream (Async)
using var fileStream = File.Create("data.toon");
await ToonSerializer.SerializeAsync(fileStream, data);
Serialize to File (Async)
await ToonSerializer.SerializeToFileAsync("data.toon", data);
// With options
var options = new ToonSerializerOptions { WriteIndented = true };
await ToonSerializer.SerializeToFileAsync("data.toon", data, options);
Performance Tips
- Reuse ToonSerializerOptions: Create once, use multiple times
- Use async methods for I/O-bound operations
- Avoid reflection: ToonNet uses expression trees automatically
- Stream for large data: Use stream methods instead of string methods
- Profile your code: Use BenchmarkDotNet for optimization
// Good: Reuse options
private static readonly ToonSerializerOptions _options = new()
{
WriteIndented = true,
PropertyNamingPolicy = PropertyNamingPolicy.CamelCase
};
public string SerializeUser(User user)
{
return ToonSerializer.Serialize(user, _options);
}
All Serialize Methods
| Method | Description | Use Case |
|---|---|---|
Serialize<T>(T value) | Serialize to string | Simple, in-memory data |
Serialize<T>(T value, ToonSerializerOptions) | Serialize with options | Custom formatting |
Serialize<T>(Stream, T value) | Serialize to stream | Large data, file output |
Serialize<T>(Stream, T, Encoding) | Serialize with encoding | Non-UTF8 encoding |
SerializeAsync<T>(Stream, T) | Async stream serialization | Async I/O |
SerializeAsync<T>(Stream, T, ToonSerializerOptions) | Async with options | Async + custom options |
SerializeToFile<T>(string, T) | Serialize to file | File persistence |
SerializeToFileAsync<T>(string, T) | Async file serialization | Async file I/O |
Error Handling
try
{
string toon = ToonSerializer.Serialize(obj);
}
catch (ToonSerializationException ex)
{
Console.WriteLine($"Serialization failed: {ex.Message}");
Console.WriteLine($"Property: {ex.PropertyName}");
Console.WriteLine($"Type: {ex.TargetType}");
}
catch (ToonEncodingException ex)
{
Console.WriteLine($"Encoding error: {ex.Message}");
Console.WriteLine($"Property path: {ex.PropertyPath}");
Console.WriteLine($"Value: {ex.ProblematicValue}");
}
Common Issues
Issue: Circular References
Problem: Object graph contains circular references.
Solution: ToonNet detects and throws ToonSerializationException. Break the cycle:
public class Parent
{
public string Name { get; set; }
public List<Child> Children { get; set; }
}
public class Child
{
public string Name { get; set; }
// Don't serialize parent reference
[ToonIgnore] // Custom attribute (if implemented)
public Parent Parent { get; set; }
}
Issue: Large Objects
Problem: Serializing very large objects causes memory issues.
Solution: Use streaming:
using var fileStream = File.Create("large-data.toon");
await ToonSerializer.SerializeAsync(fileStream, largeObject);
See Also
- Deserialization: Convert TOON back to objects
- Configuration: Detailed options guide
- Performance Tuning: Optimization strategies
- Custom Converters: Create custom type converters