/// <summary> /// In lazy deserialization, FlatSharp reads from the underlying buffer each time. No caching is done. This will be /// the fastest option if your access patterns are sparse and you touch each element only once. /// </summary> public static void LazyDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Lazy deserialization reads objects from vectors each time you ask for them. InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(!object.ReferenceEquals(index0_1, index0_2), "A different instance is returned each time from lazy vectors"); // Properties from tables and structs are cached after they are read. string name = parsed.Name; string name2 = parsed.Name; Debug.Assert( !object.ReferenceEquals(name, name2), "When reading table/struct properties Lazy parsing returns a different instance each time."); // Invalidate the whole buffer. Undefined behavior past here! Array.Fill(buffer, (byte)0); try { var whoKnows = parsed.ListVector[1]; Debug.Assert(false); } catch { // This can be any sort of exception. This behavior is undefined. } }
/// <summary> /// In lazy deserialization, FlatSharp reads from the underlying buffer each time. No caching is done. This will be /// the fastest option if your access patterns are sparse and you touch each element only once. /// </summary> public static void LazyDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Lazy)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Lazy deserialization reads objects from vectors each time you ask for them. InnerTable index0_1 = parsed.ListVector ![0];
/// <summary> /// Greedy deserialization operates the same way that conventional serializers do. The entire buffer is traversed /// and the structure is copied into the deserialized object. This is the most straightforward way of using FlatSharp, /// because the results it gives are predictable, and require no developer cognitive overhead. However, it can be less efficient /// in cases where you do not need to access all data in the buffer. /// </summary> public static void GreedyDeserialization(DemoTable demo) { // Same as FlatBufferSerializer.Default var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); long originalSum = buffer.Sum(x => (long)x); var parsed = serializer.Parse <DemoTable>(buffer); // Fill array with 0. Source data is gone now, but we can still read the buffer because we were greedy! Array.Fill(buffer, (byte)0); InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(object.ReferenceEquals(index0_1, index0_2), "Greedy deserialization returns you the same instance each time"); // We cleared the data, but can still read the name. Greedy deserialization is easy! string name = parsed.Name; // By default, Flatsharp will not allow mutations to properties. You can learn more about this in the mutable example below. try { parsed.Name = "George Washington"; Debug.Assert(false); } catch (NotMutableException) { } try { parsed.ListVector.Clear(); Debug.Assert(false); } catch (NotSupportedException) { } }
/// <summary> /// The next step up in greediness is PropertyCache mode. In this mode, Flatsharp will cache the results of property accesses. /// So, if you read the results of FooObject.Property1 multiple times, the same value comes back each time. What this mode /// does not do is cache vectors. So reding FooObject.Vector[0] multiple times re-visits the buffer each time. /// </summary> public static void PropertyCacheDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.PropertyCache)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Properties from tables and structs are cached after they are read. string name = parsed.Name; string name2 = parsed.Name; Debug.Assert( object.ReferenceEquals(name, name2), "When reading table/struct properties, PropertyCache mode returns the same instance."); // PropertyCache deserialization doesn't cache the results of vector lookups. InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(!object.ReferenceEquals(index0_1, index0_2), "A different instance is returned each time from vectors in PropertyCache mode."); Debug.Assert(object.ReferenceEquals(parsed.ListVector, parsed.ListVector), "But the vector instance itself is the cached."); Debug.Assert(object.ReferenceEquals(index0_1.Fruit, index0_1.Fruit), "And the items returned from each vector exhibit property cache behavior"); // Invalidate the whole buffer. Undefined behavior past here! Array.Fill(buffer, (byte)0); try { var whoKnows = parsed.ListVector[1]; Debug.Assert(false); } catch { // This can be any sort of exception. This behavior is undefined. } }
/// <summary> /// Vector cache is a superset of PropertyCache. The difference is that when deserializing in VectorCache mode, FlatSharp /// will allocate a vector for you that gets lazily filled in as elements are accessed. This leads to some array allocations /// behind the scenes, since FlatSharp needs to know what objects have been returned for what indices. /// </summary> public static void VectorCacheDeserialization(DemoTable demo) { var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions(FlatBufferDeserializationOption.VectorCache)); byte[] buffer = new byte[1024]; serializer.Serialize(demo, buffer); var parsed = serializer.Parse <DemoTable>(buffer); // Properties from tables and structs are cached after they are read. string name = parsed.Name; string name2 = parsed.Name; Debug.Assert( object.ReferenceEquals(name, name2), "When reading table/struct properties, PropertyCache mode returns the same instance."); // VectorCache deserialization guarantees only one object per index. InnerTable index0_1 = parsed.ListVector[0]; InnerTable index0_2 = parsed.ListVector[0]; Debug.Assert(object.ReferenceEquals(index0_1, index0_2), "The same instance is returned each time from vectors in VectorCache mode."); Debug.Assert(object.ReferenceEquals(parsed.ListVector, parsed.ListVector), "And the vector instance itself is the same."); Debug.Assert(object.ReferenceEquals(index0_1.Fruit, index0_1.Fruit), "And the items returned from each vector exhibit property cache behavior"); }