Skip to content

Instantly share code, notes, and snippets.

@Jozkee
Last active January 5, 2021 02:49
Show Gist options
  • Save Jozkee/0b50c40b58fa93c006a3ba322b4e1165 to your computer and use it in GitHub Desktop.
Save Jozkee/0b50c40b58fa93c006a3ba322b4e1165 to your computer and use it in GitHub Desktop.
preserving references across multiple (de)serialization calls
// Assuming that you have a list of `Employee`s and you have to serialize each one individually
// and you also want to take advantage of the references saved in the `ReferenceHandler`'s resolver.
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ConsoleApp4
{
class Program
{
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public List<Employee> DirectReports { get; set; }
}
static void Main(string[] args)
{
Employee tyler = new()
{
Name = "Tyler Stein"
};
Employee adrian = new()
{
Name = "Adrian King"
};
tyler.DirectReports = new List<Employee> { adrian };
adrian.Manager = tyler;
var employees = new List<Employee> { tyler, adrian };
SerializeEmployees(employees);
}
static void SerializeEmployees(List<Employee> employees)
{
var options = new JsonSerializerOptions();
var myReferenceHandler = new MyReferenceHandler();
options.ReferenceHandler = myReferenceHandler;
string json;
foreach (Employee emp in employees)
{
json = JsonSerializer.Serialize(emp, options);
DoSomething(json);
}
// Always reset after you are done serializing in order to avoid out of bounds memory growth in the resolver.
myReferenceHandler.Reset();
}
static void DoSomething(string json)
{
Console.WriteLine(json);
}
class MyReferenceHandler : ReferenceHandler
{
private ReferenceResolver _rootedResolver;
public MyReferenceHandler() => Reset();
public override ReferenceResolver CreateResolver() => _rootedResolver;
public void Reset() => _rootedResolver = new MyReferenceResolver();
class MyReferenceResolver : ReferenceResolver
{
private uint _referenceCount;
private readonly Dictionary<string, object> _referenceIdToObjectMap = new Dictionary<string, object>();
private readonly Dictionary<object, string> _objectToReferenceIdMap = new Dictionary<object, string>(ReferenceEqualityComparer.Instance);
public override void AddReference(string referenceId, object value)
{
if (!_referenceIdToObjectMap.TryAdd(referenceId, value))
{
throw new JsonException();
}
}
public override string GetReference(object value, out bool alreadyExists)
{
if (_objectToReferenceIdMap.TryGetValue(value, out string referenceId))
{
alreadyExists = true;
}
else
{
_referenceCount++;
referenceId = _referenceCount.ToString();
_objectToReferenceIdMap.Add(value, referenceId);
alreadyExists = false;
}
return referenceId;
}
public override object ResolveReference(string referenceId)
{
if (!_referenceIdToObjectMap.TryGetValue(referenceId, out object value))
{
throw new JsonException();
}
return value;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment