MessagePack serialization component

Introduction

MessagePack for C# (MessagePack-CSharp) is an extremely fast MessagePack serializer for C#, 10 times faster than MsgPack-Cli and has the best performance compared to all other C# serializers. MessagePack for C# has built-in LZ4 compression for ultra-fast serialization and a small binary footprint. Performance is always important! Can be used for games, distributed computing, microservices, data storage to Redis, etc. Supports .NET, .NET Core, Unity, Xamarin.

From the picture above, we can see that MessagePack for C# is the best in the performance test. Here is an explanation of the third MsgPack-Cli, which is the official implementation of MessagePack. The first and second items are both MessagePack for C#. The first item has slightly faster serialization and deserialization speeds than the second item, but the second item uses the L4 compression function, which significantly reduces the binary size. In actual use, it is recommended to use the L4 compression function.

use

This component has been published in Nuget, use the command to join the project.

Install-Package MessagePack

Analyzer

Install-Package MessagePackAnalyzer

Expand

Install-Package MessagePack.ImmutableCollection
Install-Package MessagePack.ReactiveProperty
Install-Package MessagePack.UnityShims
Install-Package MessagePack.AspNetCoreMvcFormatter

Unity Download Releases here  · MessagePack-CSharp/MessagePack-CSharp · GitHub

quick start

Define a class to add [MessagePackObject]characteristics, add [Key]characteristics to public members (properties or fields), and call MessagePackSerializer.Serialize<T>/Deserialize<T>serialization and deserialization, ToJsonwhich can help us dump the binary into json format.

// 标记 MessagePackObjectAttribute
[MessagePackObject]
public class MyClass
{
	// Key 是序列化索引,对于版本控制非常重要。
	[Key(0)]
	public int Age { get; set; }

	[Key(1)]
	public string FirstName { get; set; }

	[Key(2)]
	public string LastName { get; set; }

	// 公共成员中不序列化目标,标记IgnoreMemberAttribute
	[IgnoreMember]
	public string FullName { get { return FirstName + LastName; } }
}
class Program
{
    static void Main(string[] args)
    {
		var mc = new MyClass
	    {
		    Age = 99,
		    FirstName = "hoge",
		    LastName = "huga",
	    };

	    // 序列化
	    var bytes = MessagePackSerializer.Serialize(mc);
		//反序列化
	    var mc2 = MessagePackSerializer.Deserialize<MyClass>(bytes);

		// 你可以将msgpack二进制转储为可读的json。
		// 在默认情况下,MeesagePack for C#减少了属性名称信息。
		// [99,"hoge","huga"]
		var json = MessagePackSerializer.ToJson(bytes);
	    Console.WriteLine(json);

	    Console.ReadKey();

	}
}

Serialization index will affect the position of this information in the serialized data

By default the feature is required, but there are ways to change it so that it is not required, see below for details.

Analyzer

MessagePackAnalyzer Can help us define objects. If the rules are not followed, properties, assemblies, etc. can be detected and compilation errors will occur if we compile.

If you want to allow specific types (for example, when registering a custom type), place MessagePackAnalyzer.json in the project root and set the build action to AdditionalFiles(Other Files).

Here is an example of the contents of MessagePackAnalyzer.json.

[ "MyNamespace.FooClass", "MyNameSpace.BarStruct" ]

Built-in support types

These types can be serialized by default.

基元(int、string等等), Enum, Nullable<>, TimeSpan, DateTime, DateTimeOffset, Nil, Guid, Uri, Version, StringBuilder, BitArray, ArraySegment<>, BigInteger, Complext, Task, Array[], Array[,], Array[,,], Array[,,,], KeyValuePair<,>, Tuple<,...>, ValueTuple<,...>, List<>, LinkedList<>, Queue<>, Stack<>, HashSet<>, ReadOnlyCollection<>, IList<>, ICollection<>, IEnumerable<>, Dictionary<,>, IDictionary<,>, SortedDictionary<,>, SortedList<,>, ILookup<,>, IGrouping<,>, ObservableCollection<>, ReadOnlyOnservableCollection<>, IReadOnlyList<>, IReadOnlyCollection<>, ISet<>, ConcurrentBag<>, ConcurrentQueue<>, ConcurrentStack<>, ReadOnlyDictionary<,>, IReadOnlyDictionary<,>, ConcurrentDictionary<,>, Lazy<>, Task<>, 自定义继承ICollection <>或IDictionary <,>具有无参构造方法, IList,IDictionary和自定义继承ICollection或IDictionary具有无参构造函数(包括ArrayList和Hashtable)。

You can add custom type support and some official/third-party extension packs. For ImmutableCollections (ImmutableList<>, etc.), for ReactiveProperty and Unity (Vector3, Quaternion, etc.), for F# (Record, FsList, Discriminated Unions, etc.).

MessagePack.NilIs the built-in null/void/unit representation type of MessagePack for C#.

Object serialization

MessagePack for C# can serialize public Class or Struct. The serialization target must be marked [MessagePackObject] and [Key]. The Key type can be int or string. If the Key type is int, the serialization format is used as an array. If the Key type is a string, the serialization format is used as a key-value pair. If you define [MessagePackObject(keyAsPropertyName:true)], the Key attribute is not required.

[MessagePackObject]
public class Sample1
{
    [Key(0)]
    public int Foo { get; set; }
    [Key(1)]
    public int Bar { get; set; }
}

[MessagePackObject]
public class Sample2
{
    [Key("foo")]
    public int Foo { get; set; }
    [Key("bar")]
    public int Bar { get; set; }
}

[MessagePackObject(keyAsPropertyName: true)]
public class Sample3
{
    // 不需要key特性
    public int Foo { get; set; }

    // 不需要序列化的成员使用IgnoreMember特性
    [IgnoreMember]
    public int Bar { get; set; }
}

// 结果 [10,20]
Console.WriteLine(MessagePackSerializer.ToJson(new Sample1 { Foo = 10, Bar = 20 }));

// 结果 {"foo":10,"bar":20}
Console.WriteLine(MessagePackSerializer.ToJson(new Sample2 { Foo = 10, Bar = 20 }));

// 结果 {"Foo":10}
Console.WriteLine(MessagePackSerializer.ToJson(new Sample3 { Foo = 10, Bar = 20 }));

All schema serialization targets are public instance members (fields or properties). If you want to avoid serializing the target, you can [IgnoreMember]add to the target member.

The target class must be public, private and internal classes are not allowed.

Which Key type should be used, int or string? The author recommends using int key because it is faster and more compact than string key. But the string key has key name information, which is very useful for debugging.

When MessagePackSerializer serializes a target, you must use attributes on the target to ensure robustness. If the class is extended, you must be aware of version control. If Key does not exist, MessagePackSerializer will use the default value. If you are using an int key, it must start from 0. If unnecessary attributes appear, please fill in the blank numbers. Reuse is bad. In addition, if the jump number gap of Int Key is too large, it will affect the binary size.

[MessagePackObject]
public class IntKeySample
{
    [Key(3)]
    public int A { get; set; }
    [Key(10)]
    public int B { get; set; }
}

// int key不从0开始并且数字进行了跳跃,将会出现下面的结果
//[null,null,null,0,null,null,null,null,null,null,0]
Console.WriteLine(MessagePackSerializer.ToJson(new IntKeySample()));

If you want to use it like JSON.NET! I don’t want to add features! If you think so, you can use a convention-free parser.

public class ContractlessSample
{
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
}

var data = new ContractlessSample { MyProperty1 = 99, MyProperty2 = 9999 };
var bin = MessagePackSerializer.Serialize(data, MessagePack.Resolvers.ContractlessStandardResolver.Instance);

// {"MyProperty1":99,"MyProperty2":9999}
Console.WriteLine(MessagePackSerializer.ToJson(bin));

// 全局设置无约束解析器为默认解析器
MessagePackSerializer.SetDefaultResolver(MessagePack.Resolvers.ContractlessStandardResolver.Instance);

// 序列化
var bin2 = MessagePackSerializer.Serialize(data);

I want to serialize private members! By default, private members cannot be serialized/deserialized. But you can use the allow-private parser to serialize private members.

[MessagePackObject]
public class PrivateSample
{
    [Key(0)]
    int x;

    public void SetX(int v)
    {
        x = v;
    }

    public int GetX()
    {
        return x;
    }
}

var data = new PrivateSample();
data.SetX(9999);

// 你可以选择 StandardResolverAllowPrivate 或者  ContractlessStandardResolverAllowPrivate 解析器
var bin = MessagePackSerializer.Serialize(data, MessagePack.Resolvers.DynamicObjectResolverAllowPrivate.Instance);

I don't need types, I want to use it like BinaryFormatter! You can use untyped parsers and helpers. See the Typeless section.

The parser is the key customization point of MessagePack For C#. See the extensions section for details.

DataContract compatibility

You can use [DataContract] instead of [MessagePackObject]. If the type tag is DataContract, you can use [DataMember] instead of [Key] and [IgnoreDataMember] instead of [IgnoreMember].

[DataMember(Order = int)] is the same as [Key(int)], [DataMember(Name = string)] is the same as [Key(string)]. If [DataMember] is used, it is similar to [Key(nameof(propertyname) ].

Using DataContract makes it a shared class library and you don't have to reference MessagePack for C#. However, it is not included in the analyzer or mpc.exethe code generated by it. Furthermore, functions like UnionAttribute, MessagePackFormatterAttribute, SerializationConstructorAttribute etc. cannot be used. For this reason, I recommend that you basically use the MessagePack for C# feature.

Serialize immutable objects (serialization constructor)

MessagePack for C# supports deserializing immutable objects. For example, this struct can be serialized/deserialized naturally.

[MessagePackObject]
public struct Point
{
    [Key(0)]
    public readonly int X;
    [Key(1)]
    public readonly int Y;

    public Point(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

var data = new Point(99, 9999);
var bin = MessagePackSerializer.Serialize(data);

// Okay to deserialize immutable obejct
var point = MessagePackSerializer.Deserialize<Point>(bin);

MessagePackSerializer choose constructor with the least matched argument, match index if key in integer or match name(ignore case) if key is string. If encounts MessagePackDynamicObjectResolverException: can't find matched constructor parameter you should check about this.

MessagePackSerializer chooses the constructor with the fewest parameters, which will match the index if the key is an integer or the name if the key is a string (ignoring case). If you encounter it  MessagePackDynamicObjectResolverException: can't find matched constructor parameter you should check it out.

If it cannot be matched automatically, you can manually specify the use of the constructor through [SerializationConstructorAttribute].

[MessagePackObject]
public struct Point
{
    [Key(0)]
    public readonly int X;
    [Key(1)]
    public readonly int Y;

    // 如果没有标记特性,将会使用这方法(最少参数)
    public Point(int x)
    {
        X = x;
    }

    [SerializationConstructor]
    public Point(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

serialization callback

If the object is implemented IMessagePackSerializationCallbackReceiver, it is accepted OnBeforeSerializeand OnAfterDeserializeserialized.

[MessagePackObject]
public class SampleCallback : IMessagePackSerializationCallbackReceiver
{
    [Key(0)]
    public int Key { get; set; }

    public void OnBeforeSerialize()
    {
        Console.WriteLine("OnBefore");
    }

    public void OnAfterDeserialize()
    {
        Console.WriteLine("OnAfter");
    }
}

Union

MessagePack for C# supports serialization interface. This is like XmlInclude or ProtoInclude. It's called Union in MessagePack for C#. UnionAttribute can only be attached to interfaces or abstract classes. It needs to distinguish between integer keys and subtypes

// mark inheritance types
[MessagePack.Union(0, typeof(FooClass))]
[MessagePack.Union(1, typeof(BarClass))]
public interface IUnionSample
{
}

[MessagePackObject]
public class FooClass : IUnionSample
{
    [Key(0)]
    public int XYZ { get; set; }
}

[MessagePackObject]
public class BarClass : IUnionSample
{
    [Key(0)]
    public string OPQ { get; set; }
}

// ---

IUnionSample data = new FooClass() { XYZ = 999 };

// serialize interface.
var bin = MessagePackSerializer.Serialize(data);

// deserialize interface.
var reData = MessagePackSerializer.Deserialize<IUnionSample>(bin);

// use type-switch of C# 7.0
switch (reData)
{
    case FooClass x:
        Console.WriteLine(x.XYZ);
        break;
    case BarClass x:
        Console.WriteLine(x.OPQ);
        break;
    default:
        break;
}

C# 7.0 type-switch is the best choice for Union. Union is serialized into an array of two lengths.

IUnionSample data = new BarClass { OPQ = "FooBar" };

var bin = MessagePackSerializer.Serialize(data);

// Union is serialized to two-length array, [key, object]
// [1,["FooBar"]]
Console.WriteLine(MessagePackSerializer.ToJson(bin));

To use Union in an abstract class, you can use it like an interface.

[Union(0, typeof(SubUnionType1))]
[Union(1, typeof(SubUnionType2))]
[MessagePackObject]
public abstract class ParentUnionType
{
    [Key(0)]
    public int MyProperty { get; set; }
}

[MessagePackObject]
public class SubUnionType1 : ParentUnionType
{
    [Key(1)]
    public int MyProperty1 { get; set; }
}

[MessagePackObject]
public class SubUnionType2 : ParentUnionType
{
    [Key(1)]
    public int MyProperty2 { get; set; }
}

Serialization of inherited types, flattened in arrays (or key-value pairs), is irrelevant for integer keys, it cannot copy the parent class and all subclasses.

Dynamic (Untyped) deserialization

If used MessagePackSerializer.Deserialize<object> with or MessagePackSerializer.Deserialize<dynamic>, messagepack will be converted to primitive values ​​and msgpack-primitive will be converted to bool, char, sbyte, byte, short, int, long, ushort, uint, ulong, float, double, DateTime, string, byte[], object[], IDictionary<object, object>.

// sample binary.
var model = new DynamicModel { Name = "foobar", Items = new[] { 1, 10, 100, 1000 } };
var bin = MessagePackSerializer.Serialize(model, ContractlessStandardResolver.Instance);

// dynamic, untyped
var dynamicModel = MessagePackSerializer.Deserialize<dynamic>(bin, ContractlessStandardResolver.Instance);

Console.WriteLine(dynamicModel["Name"]); // foobar
Console.WriteLine(dynamicModel["Items"][2]); // 100

So you can access key-value pairs or arrays using indexes.

Object type serialization

StandardResolverand ContractlessStandardResolvercan be done by DynamicObjectTypeFallbackResolverserializing the Object type into a concrete type.

var objects = new object[] { 1, "aaa", new ObjectFieldType { Anything = 9999 } };
var bin = MessagePackSerializer.Serialize(objects);

// [1,"aaa",[9999]]
Console.WriteLine(MessagePackSerializer.ToJson(bin));

// Support Anonymous Type Serialize
var anonType = new { Foo = 100, Bar = "foobar" };
var bin2 = MessagePackSerializer.Serialize(anonType, MessagePack.Resolvers.ContractlessStandardResolver.Instance);

// {"Foo":100,"Bar":"foobar"}
Console.WriteLine(MessagePackSerializer.ToJson(bin2));

Unity support is limited.

When deserializing, it is the same as Dynamic (Untyped) deserialization.

Typeless

The Typeless API is like BinaryFormatter, embedding type information into the binary, so no type is required to deserialize.

object mc = new Sandbox.MyClass()
{
    Age = 10,
    FirstName = "hoge",
    LastName = "huga"
};

// serialize to typeless
var bin = MessagePackSerializer.Typeless.Serialize(mc);

// binary data is embeded type-assembly information.
// ["Sandbox.MyClass, Sandbox",10,"hoge","huga"]
Console.WriteLine(MessagePackSerializer.ToJson(bin));

// can deserialize to MyClass with typeless
var objModel = MessagePackSerializer.Typeless.Deserialize(bin) as MyClass;

Type information is serialized by mspgack ext format with typecode 100.

MessagePackSerializer.TypelessYes Serialize / Deserialize <object>(TypelessContractlessStandardResolver.Instance)shortcut. If you want to configure the default Typeless parser, you can MessagePackSerializer.Typeless.RegisterDefaultResolverset it via.

performance

Benchmarks comparison with other serializers on Windows 10 Pro x64 Intel Core i7-6700K 4.00GHz, 32GB RAM, Benchmark code here - Version information , ZeroFormatter and FlatBuffers have very fast deserializers, so deserialization is ignored performance.

MessagePack for C# uses many techniques to improve performance.

  • Serialization only uses ref byte [] and int offset, and does not use (Memory) Stream (calling the Stream api will have overhead)
  • The high-level API uses an internal memory pool and does not allocate working memory less than 64k
  • Intermediate utility instances (XxxWriter/Reader, XxxContext, etc.) are not created
  • All code avoids boxing, all platforms (including Unity/IL2CPP)
  • Cache the formatter generated by the static generic field, and look it up from the cache when looking up (do not use dictionary cache, because dictionary lookup requires certain overhead)
  • Retuned dynamic tag generation
  • Directly call PrimitiveAPI when code generation knows the target is primitive
  • Reduce branching for variable length formats when code generation knows target (integer/string) range
  • Don't use IEnumerable<T> abstraction on iterable collections
  • Use pre-generated lookup tables to reduce time spent checking message packet types
  • Use optimized type key dictionary for non-generic methods
  • Avoid string key decoding of lookup map (string key) keys and use automated name lookup with il inline code generation
  • For string key encoding, pre-generate member name bytes and use a fixed-size binary copy in IL

Before creating this library, Zuoze implemented a fast serializer with ZeroFormatter#Performance. This is a further evolved implementation. MessagePack for C# is always fast, optimized for all types (raw, small structures, large objects, any collection).

Performance of each method in deserialization

Performance depends on options. This is a mini-benchmark for BenchmarkDotNet. The target object has 9 members (MyProperty1~MyProperty9) with a value of zero.

Method Mean Error Scaled Gen 0 Allocated
IntKey 72.67 ns THAT 1.00 0.0132 56 B
StringKey 217.95 ns THAT 3.00 0.0131 56 B
Typeless_IntKey 176.71 ns THAT 2.43 0.0131 56 B
Typeless_StringKey 378.64 ns THAT 5.21 0.0129 56 B
MsgPackCliMap 1,355.26 ns THAT 18.65 0.1431 608 B
MsgPackCliArray 455.28 ns THAT 6.26 0.0415 176 B
ProtobufNet 265.85 ns THAT 3.66 0.0319 136 B
Hyperion 366.47 ns THAT 5.04 0.0949 400 B
JsonNetString 2,783.39 ns THAT 38.30 0.6790 2864 B
JsonNetStreamReader 3,297.90 ns THAT 45.38 1.4267 6000 B
JilString 553.65 ns THAT 7.62 0.0362 152 B
JilStreamReader 1,408.46 ns THAT 19.38 0.8450 3552 B

IntKey, StringKey, Typeless_IntKey, Typeless_StringKey are all methods of MessagePack for C#
that implement zero memory allocation during deserialization. JsonNetString/JilString deserializes from string. JsonStStreamReader/JilStreamReader is deserialized from a StreamReader's UTF8 byte[]. Deserialization usually reads from a Stream. So it will read from a byte array (or stream) instead of a string.

MessagePack for C#IntKey is the fastest. StringKey is slower than IntKey because StringKey requires matching from a string. If it is an IntKey, read the array length and perform for loop binary decoding based on the array length. If StringKey reads the map length and loops according to the map length, the key first needs to be decoded, then searched by key, and finally binary decoded, which requires two additional steps (decoding the key and searching by key).

String keys are generally useful for unconstrained, simple JSON replacement, interoperability with other languages, and more in some versions. MessagePack for C# is also optimized for String Key. First, it doesn't decode the UTF8 byte array into a string that matches the member name, it looks up the byte array as-is (avoiding the decoding cost and extra allocation).

It will try to match every long (every 8 characters, padding with 0s if not long enough) using automata and inline IL code at build time.

This also avoids computing the hash code of the byte array and allows multiple comparisons over long units.

Here is a decompilation of an example of the deserializer code generated by ILSpy.

GitHub - MessagePack-CSharp/MessagePack-CSharp: Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity, Xamarin). / msgpack.org[C#]

If the number of nodes is large, the search is done using embedded binary search.

Also note that these are serialized benchmark results.

Method Mean Error Scaled Gen 0 Allocated
IntKey 84.11 ns THAT 1.00 0.0094 40 B
StringKey 126.75 ns THAT 1.51 0.0341 144 B
Typeless_IntKey 183.31 ns THAT 2.18 0.0265 112 B
Typeless_StringKey 193.95 ns THAT 2.31 0.0513 216 B
MsgPackCliMap 967.68 ns THAT 11.51 0.1297 552 B
MsgPackCliArray 284.20 ns THAT 3.38 0.1006 424 B
ProtobufNet 176.43 ns THAT 2.10 0.0665 280 B
Hyperion 280.14 ns THAT 3.33 0.1674 704 B
ZeroFormatter 149.95 ns THAT 1.78 0.1009 424 B
JsonNetString 1,432.55 ns THAT 17.03 0.4616 1944 B
JsonNetStreamWriter 1,775.72 ns THAT 21.11 1.5526 6522 B
JilString 547.51 ns THAT 6.51 0.3481 1464 B
JilStreamWriter 778.78 ns THAT 9.26 1.4448 6066 B

Of course, IntKey is the fastest, but StringKey is also good.

LZ4 compression

MessagePack is a fast and compact format, but it is not a compressed format. LZ4 is a very fast compression algorithm, using MessagePack for C# you can achieve extremely fast performance and very compact binary size!

MessagePack for C# has built-in LZ4 support. You can use LZ4MessagePackSerializer instead of MessagePackSerializer. The built-in support is exceptional, the author has created the serialization compression pipeline and specifically tuned the pipeline so the working memory is shared, not allocated, and not tuned until completed.

Serializing the binary is not simply compressing the lz4 binary. The serialized binary is a valid MessagePack binary using ext format and a custom typecode (99).

var array= Enumerable.Range(1, 100).Select(x => new MyClass { Age = 5, FirstName = "foo", LastName = "bar" }).ToArray();

// call LZ4MessagePackSerializer instead of MessagePackSerializer, api is completely same
var lz4Bytes = LZ4MessagePackSerializer.Serialize(array);
var mc2 = LZ4MessagePackSerializer.Deserialize<MyClass[]>(lz4Bytes);

// you can dump lz4 message pack
// [[5,"hoge","huga"],[5,"hoge","huga"],....]
var json = LZ4MessagePackSerializer.ToJson(lz4Bytes);
Console.WriteLine(json);

// lz4Bytes is valid MessagePack, it is using ext-format( [TypeCode:99, SourceLength|CompressedBinary] )
// [99,"0gAAA+vf3ABkkwWjZm9vo2JhcgoAyVBvo2Jhcg=="]
var rawJson = MessagePackSerializer.ToJson(lz4Bytes);
Console.WriteLine(rawJson);

Comparison with protobuf, JSON, ZeroFormatter

protbuf-net is the most commonly used binary formatting library on .NET. I (the author) like protobuf-net and respect that great work. But if you use protobuf-net as a common serialization format, it may cause annoying problems.

[ProtoContract]
public class Parent
{
    [ProtoMember(1)]
    public int Primitive { get; set; }
    [ProtoMember(2)]
    public Child Prop { get; set; }
    [ProtoMember(3)]
    public int[] Array { get; set; }
}

[ProtoContract]
public class Child
{
    [ProtoMember(1)]
    public int Number { get; set; }
}

using (var ms = new MemoryStream())
{
    // serialize null.
    ProtoBuf.Serializer.Serialize<Parent>(ms, null);

    ms.Position = 0;
    var result = ProtoBuf.Serializer.Deserialize<Parent>(ms);

    Console.WriteLine(result != null); // True, not null. but all property are zero formatted.
    Console.WriteLine(result.Primitive); // 0
    Console.WriteLine(result.Prop); // null
    Console.WriteLine(result.Array); // null
}

using (var ms = new MemoryStream())
{
    // serialize empty array.
    ProtoBuf.Serializer.Serialize<Parent>(ms, new Parent { Array = new int[0] });

    ms.Position = 0;
    var result = ProtoBuf.Serializer.Deserialize<Parent>(ms);

    Console.WriteLine(result.Array == null); // True, null!
}

protobuf(-net) does not handle null and empty collections correctly. Because protobuf has no null representation (this is the answer from protobuf-net author).

The MessagePack specification can fully serialize C# types. This is why MessagePack is recommended instead of protobuf.

Protocol Buffers has good IDL and gRPC, which is much better than MessagePack. If you want to use IDL, I (the author) recommend Google.Protobuf.

JSON is a good general-purpose format. It's perfect, simple, and normative enough. Utf8Json was created by me using the same architecture as MessagePack for C# and avoids encoding/decoration costs, so works like a binary. If you want to know about binary vs. text, see the Utf8Json/Which serializer should be used section.

ZeroFormatter is similar to FlatBuffers, but specifically for C#. This is special. Deserialization is very fast, but the binary size is huge. The caching algorithm of ZeroFormatter requires additional memory.

ZeroFormatter is also special. When contrasted with ZeroFormatter, it shows the power of formatting. But for many common uses, MessagePack for C# will be better.

Expand

MessagePack for C# has extension points that allow you to add serialization support for external types. The following are official extensions supported.

Install-Package MessagePack.ImmutableCollection
Install-Package MessagePack.ReactiveProperty
Install-Package MessagePack.UnityShims
Install-Package MessagePack.AspNetCoreMvcFormatter

MessagePack.ImmutableCollectionAdded  System.Collections.Immutablesupport for. Added ImmutableArray<>, ImmutableList<>, ImmutableDictionary<,>, ImmutableHashSet<>, ImmutableSortedDictionary<,>, ImmutableSortedSet<>, ImmutableQueue<>, ImmutableStack<>, IImmutableList<>, IImmutableDictionary<,>, IImmutableQueue<>, IImmutableSet<>, IImmutableStack<>serialization support for .

The MessagePack.ReactiveProperty package adds support for the ReactiveProperty library. It adds ReactiveProperty <>,IReactiveProperty <>,IReadOnlyReactiveProperty <>,ReactiveCollection <>,unitserialization support. This is useful for saving view model state.

MessagePack.AspNetCoreMvcFormatter is an add-on for ASP.NET Core MVC serialization that improves performance. Here is an example configuration.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().AddMvcOptions(option =>
    {
        option.OutputFormatters.Clear();
        option.OutputFormatters.Add(new MessagePackOutputFormatter(ContractlessStandardResolver.Instance));
        option.InputFormatters.Clear();
        option.InputFormatters.Add(new MessagePackInputFormatter(ContractlessStandardResolver.Instance));
    });
}

For more information, please visit github:  GitHub - MessagePack-CSharp/MessagePack-CSharp: Extremely Fast MessagePack Serializer for C# (.NET, .NET Core, Unity, Xamarin). / msgpack.org[C#] 

Guess you like

Origin blog.csdn.net/weixin_41316824/article/details/134246700
Recommended