-
-
Notifications
You must be signed in to change notification settings - Fork 181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to use built primitive type serialization instead of writing wrapper types for every possible value #225
Comments
@neuecc Proposal: Add API to get an index (or id) of a formatter and a formatter by index (or id): public class KnownObjectFormatter : MemoryPackFormatter<Object?> {
public override void Serialize<TBufferWriter>(
ref MemoryPackWriter<TBufferWriter> writer,
scoped ref Object? value) {
if (value == null) {
writer.WriteNullObjectHeader();
return;
}
Type type = value.GetType();
ushort index = MemoryPackFormatterProvider.GetFormatterIndex(type);
var formatter = MemoryPackFormatterProvider.GetFormatter(type);
writer.WriteValue(index);
formatter.Serialize(writer, value);
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref Object? value) {
if (!reader.TryReadObjectHeader(out var count)) {
value = null;
return;
}
ushort index = reader.ReadValue<ushort>();
var formatter = MemoryPackFormatterProvider.GetFormatterByIndex();
value = formatter.Deserialize(reader);
}
} It is slower than when using static types, but not that much. I would expect it to be much faster that when having to wrap every value into an object on the heap. And there is no need to write boiler plate wrapper classes for primitives. |
I helped myself with the following formatter: public class KnownObjectFormatter : MemoryPackFormatter<Object?> {
public class KnownObjectFormatterException(string message) : Exception(message);
private static readonly Bictionary<Type, ushort> RegisteredTypes = new Bictionary<Type, ushort>();
public static void RegisterType(Type type) {
if (!RegisteredTypes.ContainsKeyForward(type)) {
ushort index = (ushort)RegisteredTypes.Count;
RegisteredTypes.Add(type, index);
}
}
public override void Serialize<TBufferWriter>(
ref MemoryPackWriter<TBufferWriter> writer,
scoped ref Object? value) {
if (value == null) {
writer.WriteNullObjectHeader();
return;
}
Type type = value.GetType();
if (!RegisteredTypes.TryGetValueForward(type, out ushort index)) {
throw new KnownObjectFormatterException($"Type {type} not registered");
}
writer.WriteUnmanaged<ushort>(index);
var formatter = writer.GetFormatter(type);
formatter.Serialize(ref writer, ref value);
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref Object? value) {
if (reader.PeekIsNull()) {
reader.Advance(1);
value = null;
return;
}
ushort index = reader.ReadUnmanaged<ushort>();
if (!RegisteredTypes.TryGetValueReverse(index, out var type)) {
throw new KnownObjectFormatterException($"No type with index {index} registered");
}
var formatter = reader.GetFormatter(type!);
formatter.Deserialize(ref reader, ref value);
}
public class Attribute : MemoryPackCustomFormatterAttribute<object?> {
private static readonly KnownObjectFormatter Formatter = new KnownObjectFormatter();
public override IMemoryPackFormatter<object?> GetFormatter() {
return Formatter;
}
}
} That boils down to usage: KnownObjectFormatter.RegisterType(typeof(int));
KnownObjectFormatter.RegisterType(typeof(int?));
KnownObjectFormatter.RegisterType(typeof(int[]));
KnownObjectFormatter.RegisterType(typeof(bool));
KnownObjectFormatter.RegisterType(typeof(bool?));
KnownObjectFormatter.RegisterType(typeof(bool[]));
KnownObjectFormatter.RegisterType(typeof(string));
KnownObjectFormatter.RegisterType(typeof(string[]));
...
KnownObjectFormatter.RegisterType(typeof(MyCustomType));
KnownObjectFormatter.RegisterType(typeof(MyCustomType?));
KnownObjectFormatter.RegisterType(typeof(MyCustomType[]));
... It still is tedious to do that for every possible already mapped type, but it at least is better than having to write wrapper classes. So proposal as changed to:
|
Hello. We have looked at your KnownObjectFormatter and would like to recommend using Union for official support. The above sample should be substitutable with Union. |
Deep in many of my static networked data types (all implement my own ISerializable) I have the following type.
Value
here can be almost anything (I write a library, so it is up to the user of the library). Of course I want to support as many types as possible. Right now I have ImplemtedISerializable
as union:This works fine, but I still have to write basic wrapper type for every known types, which already is becoming tedious, inflexible and error prone.
Example of how I would convert to
ISerializable
:Example of a wrapper
ISerializable
:MemoryPack already supports many standard types (at least the primitives). How can I make use of those without having to write those wrapper types?
The text was updated successfully, but these errors were encountered: