Last active
January 5, 2021 02:49
-
-
Save jozkee/0b50c40b58fa93c006a3ba322b4e1165 to your computer and use it in GitHub Desktop.
preserving references across multiple (de)serialization calls
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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