using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public static partial class SerializationExtensions
public static RecyclableMemoryStreamManager Manager { get; } = new RecyclableMemoryStreamManager(
new RecyclableMemoryStreamManager.Options
public interface ICloneWorker
[return: NotNullIfNotNull(nameof(value))]
public class MessagePackCloneWorker : ICloneWorker
readonly MessagePackSerializerOptions? options = default;
public MessagePackCloneWorker(MessagePackSerializerOptions? options = default) => this.options = options;
[return: NotNullIfNotNull(nameof(value))]
public T? Clone<T>(T? value)
using Stream stream = SerializationExtensions.Manager.GetStream();
MessagePackSerializer.Serialize(stream, value, options);
return MessagePackSerializer.Deserialize<T>(stream, options)!;
public class NewtonsoftCloneWorker : ICloneWorker
static JsonSerializerSettings DefaultNewtonsoftCloneSettings { get; } = new()
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
DateParseHandling = DateParseHandling.None,
readonly JsonSerializerSettings settings;
public NewtonsoftCloneWorker(JsonSerializerSettings? settings = default) => this.settings = settings ?? DefaultNewtonsoftCloneSettings;
[return: NotNullIfNotNull(nameof(value))]
public T? Clone<T>(T? value)
var serializer = JsonSerializer.CreateDefault(settings);
return JToken.FromObject(value, serializer).ToObject<T>(serializer)!;
public List<string> Strings { get; set; } = new();
public Dictionary<string, string> Dictionary { get; set; } = new();
static MessagePackSerializerOptions? MessagePackOptions = default;
static MessagePackCloneWorker worker = new(MessagePackOptions);
public static T? DestroyReference<T>(T data) => worker.Clone(data);
public static void Test()
foreach (var model in GetModels())
TestWithMessagePack(model);
TestWithNewtonsoft(model);
public static IEnumerable<Model> GetModels() =>
Strings = { "a", "b", "c", "d" },
static void TestWithNewtonsoft(Model model)
Test(model, new NewtonsoftCloneWorker());
static void TestWithMessagePack(Model model)
Test(model, new MessagePackCloneWorker());
static void Test(Model model, ICloneWorker worker)
var newModel = worker.Clone(model);
Assert.That(model.Strings.SequenceEqual(newModel.Strings));
Assert.That(model.Dictionary.SequenceEqual(newModel.Dictionary));
Console.WriteLine("Testing {0}, result: {1}", worker, JsonConvert.SerializeObject(newModel));
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Namespace, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");