using System.Collections.Generic;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Globalization;
using System.ComponentModel;
public class SerializedState
public SerializedState(byte [] data, Type type) => (Data, Type) = (data, type);
public byte [] Data { get; set; }
public System.Type Type { get; set; }
[ProtoMember(1)] public int Id { get; set; }
public abstract record State
public abstract ISet<Identity> Identities { get; }
public SerializedState Serialize()
using MemoryStream stream = new();
Serializer.Serialize(stream, this);
return new SerializedState(stream.ToArray(), GetType());
public sealed record Account(Identity Owner, string Identifier, decimal Balance) : State
public override ISet<Identity> Identities => new HashSet<Identity> {Owner};
public void TestAccount()
var accountMeta = RuntimeTypeModel
.Add<Account>(applyDefaultBehaviour : true);
accountMeta.UseConstructor = false;
var identity = new Identity { Id = 101 };
var account = new Account(identity, "Foo", 1.1m);
var state = account.Serialize();
var account2 = (Account)Serializer.NonGeneric.Deserialize(state.Type, new MemoryStream(state.Data));
Assert.AreEqual(account.Identifier, account2.Identifier);
Assert.AreEqual(account.Balance, account2.Balance);
Assert.AreEqual(account.Owner?.Id, account2.Owner?.Id);
using var ms = new MemoryStream();
var identity = new Identity { Id = 101 };
Serializer.Serialize(ms, identity);
var identity2 = (Identity)Serializer.NonGeneric.Deserialize(identity.GetType(), ms);
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("{0} version: {1}", typeof(ProtoBuf.Serializer).Assembly.GetName().Name, typeof(ProtoBuf.Serializer).Assembly.FullName);
RuntimeTypeModel.Default.AutoCompile = false;
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];