public void Serialize(ref byte[] buffer, ref int offset, T value) { if (EqualityComparer <T> .Default.Equals(value, default)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias); return; } if (value is Type type) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, InlineType, Bias); _typeFormatter.Serialize(ref buffer, ref offset, type); return; } if (value is IExternalRootObject externalObj) { if (!object.ReferenceEquals(_serializer.InstanceData.CurrentRoot, value)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, ExternalObject, Bias); var refId = externalObj.GetReferenceId(); SerializerBinary.WriteInt32(ref buffer, ref offset, refId); _serializer.Config.OnExternalObject?.Invoke(externalObj); return; } } if (_serializer.InstanceData.ObjectCache.TryGetExistingObjectId(value, out int id)) { // Existing value SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias); } else { // Important: Insert the ID for this value into our dictionary BEFORE calling SerializeFirstTime, as that might recursively call us again (maybe with the same value!) _serializer.InstanceData.ObjectCache.RegisterObject(value); var specificType = value.GetType(); if (typeof(T) == specificType) { // New value (same type) SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValueSameType, Bias); } else { // New value (type included) SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValue, Bias); _typeFormatter.Serialize(ref buffer, ref offset, specificType); } // Write the object normally GetSpecificSerializerDispatcher(specificType)(ref buffer, ref offset, value); } }
public void Serialize(ref byte[] buffer, ref int offset, Person value) { SerializerBinary.WriteString(ref buffer, ref offset, value.Name); SerializerBinary.WriteInt32(ref buffer, ref offset, value.Health); PersonFormatter.Serialize(ref buffer, ref offset, value.BestFriend); // Important: // You might be tempted to just recursively call Serialize again for 'BestFriend', but that won't work! // Do not think you can manually serialize other instances. // It may look like that the object injected into "PersonFormatter" is just 'MyCustomPersonFormatter' itself again, // but that's not the case! // In fact, what you get is a lot of magic behind the scenes that deals with a ton of edge cases (object references, and reference loop handling, and more) }
public void Serialize(ref byte[] buffer, ref int offset, T member) { // Declaring type _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType); SerializerBinary.WriteInt32(ref buffer, ref offset, (int)member.MemberType); switch (member.MemberType) { // Write all the data we need to resolve overloads case MemberTypes.Constructor: case MemberTypes.Method: var method = (MethodBase)(MemberInfo)member; _stringFormatter.Serialize(ref buffer, ref offset, method.Name); var args = method.GetParameters(); SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length); for (int i = 0; i < args.Length; i++) { _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType); } break; case MemberTypes.Property: PropertyInfo prop = (PropertyInfo)(MemberInfo)member; _stringFormatter.Serialize(ref buffer, ref offset, prop.Name); _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType); break; case MemberTypes.Field: FieldInfo field = (FieldInfo)(MemberInfo)member; _stringFormatter.Serialize(ref buffer, ref offset, field.Name); _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType); break; default: throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'"); } }
public Ceras.Formatters.IFormatter <IEqualityComparer <byte?[]> > _comparerFormatter; // auto-implemented by Ceras using DynamicObjectFormatter public void Serialize(ref byte[] buffer, ref int offset, HashSet <byte?[]> set) { // What do we need? // - The comparer // - Number of entries // - Actual content // Comparer _comparerFormatter.Serialize(ref buffer, ref offset, set.Comparer); // Count // We could use a 'IFormatter<int>' field, but Ceras will resolve it to this method anyway... SerializerBinary.WriteInt32(ref buffer, ref offset, set.Count); // Actual content foreach (var array in set) { _byteArrayFormatter.Serialize(ref buffer, ref offset, array); } }
public void Serialize(ref byte[] buffer, ref int offset, Person value) { SerializerBinary.WriteString(ref buffer, ref offset, value.Name); SerializerBinary.WriteInt32(ref buffer, ref offset, value.Health); // !! Important - Read below! PersonFormatter.Serialize(ref buffer, ref offset, value.BestFriend); // You might be tempted to just recursively call your own Serialize method (this method) again for 'BestFriend', but that won't work! // That won't work because Ceras does many things behind the scenes to make reference-loops work. // // Think about it like this: // When we want to serialize '.BestFriend' and someone is their own best friend (silly, i know :P) then we'd want the serialized data to // say "this object was already written, look it up here..." // Otherwise we'd get into an infinite loop, which is exactly what is happening if we'd just write "this.Serialize(ref buffer, ref offset, value.BestFriend);" here. // // Now, as for the 'PersonFormatter' field in this class. // Ceras can inject fields of type 'IFormatter' and 'CerasSerializer' into all its formatters. // So, even though it may look like that the object injected into "PersonFormatter" is just 'MyCustomPersonFormatter' itself again, that's not the case! // // In case you are interested in what's going on behind the scenes: // Ceras actually injects a 'ReferenceFormatter<Person>' into our 'PersonFormatter' field, which deals with reference loops. }
public void Serialize(ref byte[] buffer, ref int offset, T value) { if (ReferenceEquals(value, null)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias); return; } var specificType = value.GetType(); var entry = GetOrCreateEntry(specificType); if (entry.IsType) // This is very rare, so we cache the check itself, and do the cast below { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, InlineType, Bias); _typeFormatter.Serialize(ref buffer, ref offset, (Type)(object)value); return; } if (entry.IsExternalRootObject) { var externalObj = (IExternalRootObject)value; if (!ReferenceEquals(_ceras.InstanceData.CurrentRoot, value)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, ExternalObject, Bias); var refId = externalObj.GetReferenceId(); SerializerBinary.WriteInt32(ref buffer, ref offset, refId); _ceras.Config.OnExternalObject?.Invoke(externalObj); return; } } if (_allowReferences) { if (_ceras.InstanceData.ObjectCache.TryGetExistingObjectId(value, out int id)) { // Existing value SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias); } else { // Register new object _ceras.InstanceData.ObjectCache.RegisterObject(value); // Embedd type (if needed) if (ReferenceEquals(typeof(T), specificType)) { // New value (same type) SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValueSameType, Bias); } else { // New value (type included) SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValue, Bias); _typeFormatter.Serialize(ref buffer, ref offset, specificType); } // Write object entry.CurrentSerializeDispatcher(ref buffer, ref offset, value); } } else { // Embedd type (if needed) if (ReferenceEquals(typeof(T), specificType)) { // New value (same type) SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValueSameType, Bias); } else { // New value (type included) SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewValue, Bias); _typeFormatter.Serialize(ref buffer, ref offset, specificType); } // Write object entry.CurrentSerializeDispatcher(ref buffer, ref offset, value); } }
public void Serialize(ref byte[] buffer, ref int offset, T member) { // Declaring type _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType); byte bindingData = 0; switch (member.MemberType) { // Write all the data we need to resolve overloads case MemberTypes.Constructor: case MemberTypes.Method: var method = (MethodBase)(MemberInfo)member; if (method.ContainsGenericParameters) { throw new ArgumentException($"The method or constructor '{method.DeclaringType?.FullName}.{method.Name}' can not be serialized because it is not closed. If you need this functionality (or don't know what this means) please report an issue on GitHub."); } bindingData = PackBindingData(method.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Method Name _stringFormatter.Serialize(ref buffer, ref offset, method.Name); // 3. Parameters var args = method.GetParameters(); SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length); for (int i = 0; i < args.Length; i++) { _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType); } break; case MemberTypes.Property: PropertyInfo prop = (PropertyInfo)(MemberInfo)member; bindingData = PackBindingData(prop.GetAccessors(true)[0].IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Property Name _stringFormatter.Serialize(ref buffer, ref offset, prop.Name); // 3. Property Type _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType); break; case MemberTypes.Field: FieldInfo field = (FieldInfo)(MemberInfo)member; bindingData = PackBindingData(field.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Field Name _stringFormatter.Serialize(ref buffer, ref offset, field.Name); // 3. Field Type _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType); break; case MemberTypes.TypeInfo: case MemberTypes.NestedType: // This should never happen, because root types as well as nested types are simply "Type", // so they should be handled by the TypeFormatter! goto default; default: throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'"); } }
public void Serialize(ref byte[] buffer, ref int offset, T member) { // Declaring type _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType); byte bindingData = 0; switch (member.MemberType) { // Write all the data we need to resolve overloads case MemberTypes.Constructor: case MemberTypes.Method: var method = (MethodBase)(MemberInfo)member; bindingData = PackBindingData(method.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Method Name _stringFormatter.Serialize(ref buffer, ref offset, method.Name); // todo: parameter count can be merged into the unused bits of bindingData, but so much bit-packing makes things more complicated than they need to be; // it's extremely unlikely that anyone would notice the savings, even if they'd serialize tons of MemberInfos // 3. Parameters var args = method.GetParameters(); SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length); for (int i = 0; i < args.Length; i++) { _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType); } break; case MemberTypes.Property: PropertyInfo prop = (PropertyInfo)(MemberInfo)member; bindingData = PackBindingData(prop.GetAccessors(true)[0].IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Property Name _stringFormatter.Serialize(ref buffer, ref offset, prop.Name); // 3. Property Type _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType); break; case MemberTypes.Field: FieldInfo field = (FieldInfo)(MemberInfo)member; bindingData = PackBindingData(field.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Field Name _stringFormatter.Serialize(ref buffer, ref offset, field.Name); // 3. Field Type _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType); break; case MemberTypes.TypeInfo: case MemberTypes.NestedType: // This should never happen, because root types as well as nested types are simply "Type", // so they should be handled by the TypeFormatter! goto default; default: throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'"); } }
public void Serialize(ref byte[] buffer, ref int offset, bool value) { SerializerBinary.WriteInt32(ref buffer, ref offset, value ? 1 : 0); }