public void NonGenericSerializer_FromInstance() { var flatBufferSerializer = new FlatBufferSerializer(FlatBufferDeserializationOption.Lazy); ISerializer serializer = flatBufferSerializer.Compile(new SomeTable()); Assert.IsAssignableFrom <ISerializer <SomeTable> >(serializer); Assert.Equal(typeof(SomeTable), serializer.RootType); Assert.True(serializer.GetMaxSize(new SomeTable()) > 0); Assert.Throws <ArgumentNullException>(() => serializer.GetMaxSize(null)); Assert.Throws <ArgumentException>(() => serializer.GetMaxSize(new SomeOtherTable())); var bw = new ArrayBufferWriter <byte>(); Assert.Throws <ArgumentNullException>(() => serializer.Write(bw, null)); Assert.Throws <ArgumentException>(() => serializer.Write(bw, new SomeOtherTable())); int written = serializer.Write(bw, new SomeTable { A = 3 }); Assert.True(written > 0); Assert.Equal(written, bw.WrittenCount); object parsed = serializer.Parse(bw.WrittenMemory); Assert.True(typeof(SomeTable).IsAssignableFrom(parsed.GetType())); Assert.NotEqual(typeof(SomeTable), parsed.GetType()); Assert.IsAssignableFrom <IFlatBufferDeserializedObject>(parsed); var deserialized = (IFlatBufferDeserializedObject)parsed; Assert.Equal(typeof(SomeTable), deserialized.TableOrStructType); Assert.NotNull(deserialized.InputBuffer); // lazy Assert.Equal(FlatBufferDeserializationOption.Lazy, deserialized.DeserializationContext.DeserializationOption); Assert.Equal(FlatBufferDeserializationOption.Lazy, serializer.DeserializationOption); ISerializer parsedSerializer = flatBufferSerializer.Compile(deserialized); ISerializer parsedSerializer2 = flatBufferSerializer.Compile(parsed); Assert.Same(serializer, parsedSerializer); Assert.Same(serializer, parsedSerializer2); // Test that items deserialized from serializer 1 can be used by serializer 2. Why? Who knows! var flatBufferSerializer2 = new FlatBufferSerializer(FlatBufferDeserializationOption.Lazy); ISerializer serializer3 = flatBufferSerializer2.Compile(parsed); Assert.Equal(typeof(SomeTable), serializer3.RootType); Assert.NotSame(serializer, serializer3); bw = new ArrayBufferWriter <byte>(); serializer3.Write(bw, parsed); }
public void Success_Nullable(FlatBufferDeserializationOption option) { FlatBufferSerializer serializer = new FlatBufferSerializer(option); WriteThroughTable_Required <ValueStruct?> table = new() { Item = new ValueStruct { Value = 1 } }; byte[] result = new byte[1024]; var code = serializer.Compile <WriteThroughTable_Required <ValueStruct?> >().CSharp; serializer.Serialize(table, result); var parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct?> >(result); Assert.Equal(1, parsed.Item.Value.Value); parsed.Item = new ValueStruct { Value = 4 }; // Re-read and verify the in-struct writethrough succeeded. parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct?> >(result); Assert.Equal(4, parsed.Item.Value.Value); var ex = Assert.Throws <InvalidOperationException>(() => parsed.Item = null); Assert.Equal( "Nullable object must have a value.", ex.Message); }
public void Parse_NonNullable(Type type, bool enableMarshal, bool expectMarshal) { byte[] data = { 4, 0, 0, 0, 232, 255, 255, 255, 1, 0, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0,0, 0, 0, 0, 5, 0, 0, 0, 6, 0, 24, 0, 4, 0, }; Type tableType = typeof(SimpleTableNonNullable <>).MakeGenericType(type); var fbs = new FlatBufferSerializer(new FlatBufferSerializerOptions { EnableValueStructMemoryMarshalDeserialization = enableMarshal }); ISerializer serializer = fbs.Compile(tableType); ISimpleTable table = (ISimpleTable)serializer.Parse(data); Assert.Equal( expectMarshal, serializer.CSharp.Contains($"MemoryMarshal.Cast<byte, {type.GetGlobalCompilableTypeName()}>")); Assert.Equal(1, table.Item.IA); Assert.Equal(2, table.Item.IB); Assert.Equal(3, table.Item.IC); Assert.Equal(4, table.Item.ID); Assert.Equal(5, table.Item.IInner.Test); }
public void Serialize_SixteenByte(bool marshal) { byte[] data = { 4, 0, 0, 0, 236, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 6, 0, 20, 0, 4, 0, }; SimpleTableAnything <SixteenByteStruct?> source = new() { Item = new SixteenByteStruct { A = 1, B = 2ul, } }; byte[] buffer = new byte[1024]; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions { EnableValueStructMemoryMarshalDeserialization = marshal }); var written = serializer.Serialize(source, buffer); Assert.True(data.AsSpan().SequenceEqual(buffer.AsSpan().Slice(0, written))); Assert.Equal(marshal, serializer.Compile(source.GetType()).CSharp.Contains("MemoryMarshal.Cast")); } }
public void Serialize_NineByte(bool marshal) { byte[] data = { 4, 0, 0, 0, 242, 255, 255, 255, 1, 0, 0, 0,0, 0, 0, 0, 2, 0, 6, 0, 13, 0, 4, 0, }; var table = new SimpleTableAnything <NineByteStruct> { Item = new NineByteStruct { A = 1, B = 2, } }; byte[] buffer = new byte[1024]; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions { EnableValueStructMemoryMarshalDeserialization = marshal }); int bytesWritten = serializer.Serialize(table, buffer); Assert.True(data.AsSpan().SequenceEqual(buffer.AsSpan().Slice(0, bytesWritten))); Assert.Equal(marshal, serializer.Compile(table.GetType()).CSharp.Contains("MemoryMarshal.Cast")); }
public void GreedyMemoryCopySerialization_NoEffect() { TestTable <Struct> t = new() { Foo = "foobar", Struct = new Struct { Bar = 12, } }; FlatBufferSerializer serializer = new FlatBufferSerializer(FlatBufferDeserializationOption.GreedyMutable); var compiled = serializer.Compile <TestTable <Struct> >().WithSettings(new SerializerSettings { EnableMemoryCopySerialization = true }); byte[] data = new byte[1024]; Assert.Equal(70, compiled.GetMaxSize(t)); int actualBytes = compiled.Write(data, t); // First test: Parse the array but don't trim the buffer. This causes the underlying // buffer to be much larger than the actual data. var parsed = compiled.Parse(data); byte[] data2 = new byte[2048]; int bytesWritten = compiled.Write(data2, parsed); Assert.Equal(35, actualBytes); Assert.Equal(35, bytesWritten); Assert.Equal(70, compiled.GetMaxSize(parsed)); }
public void Facade_NullReturnedFromConverter() { TypeModelContainer container = TypeModelContainer.CreateDefault(); container.RegisterTypeFacade <string, DateTimeOffset, InvalidDateTimeStringConverter>(); FlatBufferSerializer serializer = new FlatBufferSerializer( new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy), container); byte[] destination = new byte[200]; var compiled = serializer.Compile <ExtensionTable <DateTimeOffset> >(); try { serializer.Serialize( new ExtensionTable <DateTimeOffset> { Item = DateTimeOffset.UtcNow }, destination); Assert.False(true, "expected exception"); } catch (InvalidOperationException ex) { Assert.Contains("ITypeFacadeConverter", ex.Message); } }
private SimpleTable SerializeAndParse(FlatBufferSerializerOptions options, out WeakReference <byte[]> buffer) { SimpleTable table = new SimpleTable { String = "hi", Struct = new SimpleStruct { Byte = 1, Long = 2, Uint = 3 }, StructVector = new List <SimpleStruct> { new SimpleStruct { Byte = 4, Long = 5, Uint = 6 } }, }; var serializer = new FlatBufferSerializer(options); var rawBuffer = new byte[1024]; serializer.Serialize(table, rawBuffer); buffer = new WeakReference <byte[]>(rawBuffer); string csharp = serializer.Compile <SimpleTable>().CSharp; return(serializer.Parse <SimpleTable>(rawBuffer)); }
public void Success_NonNullable(FlatBufferDeserializationOption option) { FlatBufferSerializer serializer = new FlatBufferSerializer(option); WriteThroughTable_Required <ValueStruct> table = new() { Item = new ValueStruct { Value = 1 } }; byte[] result = new byte[1024]; var code = serializer.Compile <WriteThroughTable_Required <ValueStruct> >().CSharp; serializer.Serialize(table, result); var parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct> >(result); Assert.Equal(1, parsed.Item.Value); parsed.Item = new ValueStruct { Value = 4 }; // Re-read and verify the in-struct writethrough succeeded. parsed = serializer.Parse <WriteThroughTable_Required <ValueStruct> >(result); Assert.Equal(4, parsed.Item.Value); }
public void Facade_NullReturnedFromConverter2() { TypeModelContainer container = TypeModelContainer.CreateDefault(); container.RegisterTypeFacade <long?, DateTimeOffset?, InvalidNullableDateTimeNullableLongConverter>(); FlatBufferSerializer serializer = new FlatBufferSerializer( new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy), container); byte[] destination = new byte[200]; var compiled = serializer.Compile <ExtensionTable <DateTimeOffset?> >(); try { serializer.Serialize( new ExtensionTable <DateTimeOffset?> { Item = DateTimeOffset.UtcNow }, destination); Assert.Fail(); } catch (InvalidOperationException ex) { Assert.IsTrue(ex.Message.Contains("ITypeFacadeConverter")); } }
public void Parse_SixteenByte(bool marshal) { byte[] data = { 4, 0, 0, 0, 236, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 6, 0, 20, 0, 4, 0, }; var serializer = new FlatBufferSerializer(new FlatBufferSerializerOptions { EnableValueStructMemoryMarshalDeserialization = marshal }); var parsed = serializer.Parse <SimpleTableAnything <SixteenByteStruct?> >(data); Assert.NotNull(parsed); Assert.NotNull(parsed.Item); Assert.Equal(1, parsed.Item.Value.A); Assert.Equal(2ul, parsed.Item.Value.B); Assert.Equal(marshal, serializer.Compile <SimpleTableAnything <SixteenByteStruct?> >().CSharp.Contains("MemoryMarshal.Cast")); }
public void NonGenericSerializer_FromInstance() { var flatBufferSerializer = new FlatBufferSerializer(FlatBufferDeserializationOption.Lazy); ISerializer serializer = flatBufferSerializer.Compile(new SomeTable()); Assert.IsInstanceOfType(serializer, typeof(ISerializer <SomeTable>)); Assert.AreEqual(typeof(SomeTable), serializer.RootType); Assert.IsTrue(serializer.GetMaxSize(new SomeTable()) > 0); Assert.ThrowsException <ArgumentNullException>(() => serializer.GetMaxSize(null)); Assert.ThrowsException <ArgumentException>(() => serializer.GetMaxSize(new SomeOtherTable())); Memory <byte> data = new byte[1024]; Assert.IsTrue(serializer.Write(data, new SomeTable { A = 3 }) > 0); Assert.ThrowsException <ArgumentNullException>(() => serializer.Write(data, null)); Assert.ThrowsException <ArgumentException>(() => serializer.Write(data, new SomeOtherTable())); object parsed = serializer.Parse(data); Assert.IsTrue(typeof(SomeTable).IsAssignableFrom(parsed.GetType())); Assert.AreNotEqual(typeof(SomeTable), parsed.GetType()); Assert.IsInstanceOfType(parsed, typeof(IFlatBufferDeserializedObject)); var deserialized = (IFlatBufferDeserializedObject)parsed; Assert.AreEqual(deserialized.TableOrStructType, typeof(SomeTable)); Assert.IsNotNull(deserialized.InputBuffer); // lazy Assert.AreEqual(FlatBufferDeserializationOption.Lazy, deserialized.DeserializationContext.DeserializationOption); ISerializer parsedSerializer = flatBufferSerializer.Compile(deserialized); ISerializer parsedSerializer2 = flatBufferSerializer.Compile(parsed); Assert.AreSame(serializer, parsedSerializer); Assert.AreSame(serializer, parsedSerializer2); // Test that items deserialized from serializer 1 can be used by serializer 2. Why? Who knows! var flatBufferSerializer2 = new FlatBufferSerializer(FlatBufferDeserializationOption.Lazy); ISerializer serializer3 = flatBufferSerializer2.Compile(parsed); Assert.AreEqual(typeof(SomeTable), serializer3.RootType); Assert.AreNotSame(serializer, serializer3); serializer3.Write(data, parsed); }
public void Failure_Greedy(FlatBufferDeserializationOption option) { FlatBufferSerializer serializer = new FlatBufferSerializer(option); var ex = Assert.Throws <InvalidFlatBufferDefinitionException>(() => serializer.Compile <WriteThroughTable_Required <ValueStruct> >()); Assert.Equal( "Property 'Item' of Table 'FlatSharpTests.WriteThroughTests.WriteThroughTable_Required<FlatSharpTests.WriteThroughTests.ValueStruct>' specifies the WriteThrough option. However, WriteThrough is only supported when using deserialization option 'Progressive' or 'Lazy'.", ex.Message); }
public void Failures(FlatBufferDeserializationOption option, Type vectorType) { FlatBufferSerializer serializer = new FlatBufferSerializer(option); var tableType = typeof(WriteThroughTable_NotRequired <>).MakeGenericType(vectorType); var ex = Assert.Throws <InvalidFlatBufferDefinitionException>(() => serializer.Compile(tableType)); Assert.Equal( $"Field '{tableType.GetCompilableTypeName()}.Item' declares the WriteThrough option. WriteThrough is not supported when using Greedy deserialization.", ex.Message); }
public void Serialize_NonNullable(Type type, bool enableMarshal, bool expectMarshal) { Type tableType = typeof(SimpleTableNonNullable <>).MakeGenericType(type); ISimpleTable simpleTable = (ISimpleTable)Activator.CreateInstance(tableType); IValidStruct s = (IValidStruct)Activator.CreateInstance(type); s.IA = 1; s.IB = 2; s.IC = 3; s.ID = 4; s.IInner = new ValidStruct_Inner { Test = 5 }; simpleTable.Item = s; var fbs = new FlatBufferSerializer(new FlatBufferSerializerOptions { EnableValueStructMemoryMarshalDeserialization = enableMarshal }); ISerializer serializer = fbs.Compile(simpleTable); byte[] data = new byte[1024]; int bytesWritten = serializer.Write(data, simpleTable); byte[] expectedData = { 4, 0, 0, 0, 232, 255, 255, 255, 1, 0, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0,0, 0, 0, 0, 5, 0, 0, 0, 6, 0, 24, 0, 4, 0, }; Assert.Equal(expectedData.Length, bytesWritten); Assert.True(expectedData.AsSpan().SequenceEqual(data.AsSpan().Slice(0, bytesWritten))); Assert.Equal( expectMarshal, serializer.CSharp.Contains($"MemoryMarshal.Cast<byte, {type.GetGlobalCompilableTypeName()}>")); }
public void LazyMemoryCopySerialization() { TestTable <WriteThroughStruct> t = new() { Foo = "foobar", Struct = new WriteThroughStruct { Bar = 12, } }; FlatBufferSerializer serializer = new FlatBufferSerializer(FlatBufferDeserializationOption.Lazy); var compiled = serializer.Compile <TestTable <WriteThroughStruct> >().WithSettings(new SerializerSettings { EnableMemoryCopySerialization = true }); byte[] data = new byte[1024]; Assert.Equal(70, compiled.GetMaxSize(t)); int actualBytes = compiled.Write(data, t); // First test: Parse the array but don't trim the buffer. This causes the underlying // buffer to be much larger than the actual data. var parsed = compiled.Parse(data); byte[] data2 = new byte[2048]; int bytesWritten = compiled.Write(data2, parsed); Assert.Equal(35, actualBytes); Assert.Equal(1024, bytesWritten); // We use mem copy serialization here, and we gave it 1024 bytes when we parsed. So we get 1024 bytes back out. Assert.Equal(1024, compiled.GetMaxSize(parsed)); Assert.Throws <BufferTooSmallException>(() => compiled.Write(new byte[35], parsed)); // Repeat, but now using the trimmed array. parsed = compiled.Parse(data.AsMemory().Slice(0, actualBytes)); bytesWritten = compiled.Write(data2, parsed); Assert.Equal(35, actualBytes); Assert.Equal(35, bytesWritten); Assert.Equal(35, compiled.GetMaxSize(parsed)); // Default still returns 70. Assert.Equal(70, serializer.GetMaxSize(parsed)); }
private void FacadeTest <TUnderlyingType, TType, TConverter>( TUnderlyingType underlyingValue, TType value, TypeModelContainer container = null) where TConverter : struct, ITypeFacadeConverter <TUnderlyingType, TType> { if (container == null) { container = TypeModelContainer.CreateDefault(); container.RegisterTypeFacade <TUnderlyingType, TType, TConverter>(); } FlatBufferSerializer serializer = new FlatBufferSerializer( new FlatBufferSerializerOptions(FlatBufferDeserializationOption.Greedy), container); byte[] destination = new byte[1024]; byte[] destination2 = new byte[1024]; var compiled = serializer.Compile <ExtensionTable <TType> >(); var underlyingItem = new ExtensionTable <TUnderlyingType> { Item = underlyingValue }; var facadeItem = new ExtensionTable <TType> { Item = value }; serializer.Serialize(facadeItem, destination); serializer.Serialize(underlyingItem, destination2); Assert.True(destination.AsSpan().SequenceEqual(destination2)); var parsed = serializer.Parse <ExtensionTable <TType> >(destination); Assert.Equal(parsed.Item, value); Assert.Equal(serializer.GetMaxSize(facadeItem), serializer.GetMaxSize(underlyingItem)); }
public void WriteThrough_InvalidDeserializationOption() { foreach (FlatBufferDeserializationOption option in Enum.GetValues(typeof(FlatBufferDeserializationOption))) { if (option == FlatBufferDeserializationOption.Progressive || option == FlatBufferDeserializationOption.Lazy) { continue; } var serializer = new FlatBufferSerializer(option); var ex = Assert.Throws <InvalidFlatBufferDefinitionException>(() => serializer.Compile <Table <WriteThroughStruct <bool> > >()); Assert.Equal( "Property 'Value' of Struct 'FlatSharpTests.WriteThroughTests.WriteThroughStruct<System.Boolean>' specifies the WriteThrough option. However, WriteThrough is only supported when using deserialization option 'Progressive' or 'Lazy'.", ex.Message); } }
private void RunTest <T>(string fbsType, int length, FlatBufferDeserializationOption option) where T : struct { string schema = $@" namespace StructVectorTests; table Table ({MetadataKeys.SerializerKind}) {{ foo:Foo; }} struct Foo {{ V:[{fbsType}:{length}]; }}"; Assembly asm = FlatSharpCompiler.CompileAndLoadAssembly( schema, new()); Type tableType = asm.GetType("StructVectorTests.Table"); Type fooType = asm.GetType("StructVectorTests.Foo"); var typeModel = TypeModelContainer.CreateDefault().CreateTypeModel(fooType); Assert.AreEqual(FlatBufferSchemaType.Struct, typeModel.SchemaType); for (int i = 0; i < length; ++i) { PropertyInfo p = fooType.GetProperty($"__flatsharp__V_{i}"); Assert.IsTrue(p.GetMethod.IsPublic); Assert.IsTrue(p.SetMethod.IsPublic); Assert.IsTrue(p.GetMethod.IsVirtual); Assert.IsTrue(p.SetMethod.IsVirtual); var attr = p.GetCustomAttribute <FlatBufferItemAttribute>(); Assert.IsNotNull(attr); Assert.AreEqual(i, attr.Index); var browsableAttr = p.GetCustomAttribute <EditorBrowsableAttribute>(); Assert.IsNotNull(browsableAttr); Assert.AreEqual(EditorBrowsableState.Advanced, browsableAttr.State); } var vectorProperty = fooType.GetProperty("V"); Assert.IsNull(vectorProperty.GetCustomAttribute <FlatBufferItemAttribute>()); // pseudo-item, not actual. Assert.IsNull(vectorProperty.GetCustomAttribute <EditorBrowsableAttribute>()); Assert.IsTrue(vectorProperty.GetMethod.IsPublic); Assert.IsFalse(vectorProperty.GetMethod.IsVirtual); Assert.IsNull(vectorProperty.SetMethod); dynamic table = Activator.CreateInstance(tableType); dynamic foo = Activator.CreateInstance(fooType); table.foo = foo; Assert.AreEqual(length, foo.V.Count); for (int i = 0; i < length; ++i) { foo.V[i] = GetRandom <T>(); } byte[] data = new byte[1024]; var fbs = new FlatBufferSerializer( new FlatBufferSerializerOptions(option) { EnableAppDomainInterceptOnAssemblyLoad = true }); var serializer = fbs.Compile((object)table); serializer.Write(data, (object)table); dynamic parsed = serializer.Parse(data); dynamic copy = Activator.CreateInstance(tableType, (object)parsed); Assert.AreEqual(length, parsed.foo.V.Count); for (int i = 0; i < length; ++i) { CheckRandom <T>(foo.V[i], parsed.foo.V[i]); CheckRandom <T>(foo.V[i], copy.foo.V[i]); } bool isMutable = option is FlatBufferDeserializationOption.VectorCacheMutable or FlatBufferDeserializationOption.GreedyMutable; if (length == 0) { return; } try { for (int i = 0; i < length; ++i) { parsed.foo.V[i] = GetRandom <T>(); } Assert.IsTrue(isMutable); } catch (NotMutableException) { Assert.IsFalse(isMutable); } }
private void RunTest <T>(string fbsType, int length, FlatBufferDeserializationOption option) where T : struct { string schema = $@" {MetadataHelpers.AllAttributes} namespace StructVectorTests; table Table ({MetadataKeys.SerializerKind}) {{ foo:Foo; }} struct Foo {{ V:[{fbsType}:{length}]; }}"; (Assembly asm, string code) = FlatSharpCompiler.CompileAndLoadAssemblyWithCode( schema, new()); Type tableType = asm.GetType("StructVectorTests.Table"); Type fooType = asm.GetType("StructVectorTests.Foo"); var typeModel = TypeModelContainer.CreateDefault().CreateTypeModel(fooType); Assert.Equal(FlatBufferSchemaType.Struct, typeModel.SchemaType); for (int i = 0; i < length; ++i) { PropertyInfo p = fooType.GetProperty($"__flatsharp__V_{i}", BindingFlags.Instance | BindingFlags.NonPublic); Assert.True(p.GetMethod.IsFamily); Assert.True(p.SetMethod.IsFamily); Assert.True(p.GetMethod.IsVirtual); Assert.True(p.SetMethod.IsVirtual); var metaAttr = p.GetCustomAttribute <FlatBufferMetadataAttribute>(); var attr = p.GetCustomAttribute <FlatBufferItemAttribute>(); Assert.NotNull(attr); Assert.NotNull(metaAttr); Assert.Equal(i, attr.Index); Assert.Equal(FlatBufferMetadataKind.Accessor, metaAttr.Kind); Assert.Equal($"V[{attr.Index}]", metaAttr.Value); } var vectorProperty = fooType.GetProperty("V"); Assert.Null(vectorProperty.GetCustomAttribute <FlatBufferItemAttribute>()); // pseudo-item, not actual. Assert.True(vectorProperty.GetMethod.IsPublic); Assert.False(vectorProperty.GetMethod.IsVirtual); Assert.Null(vectorProperty.SetMethod); dynamic table = Activator.CreateInstance(tableType); dynamic foo = Activator.CreateInstance(fooType); table.foo = foo; Assert.Equal(length, foo.V.Count); // Test copyFrom with full array. List <T> items = new List <T>(); for (int i = 0; i < length; ++i) { items.Add(GetRandom <T>()); } table.foo.V.CopyFrom((IReadOnlyList <T>)items); for (int i = 0; i < length; ++i) { CheckRandom <T>(items[i], table.foo.V[i]); } for (int i = 0; i < length; ++i) { foo.V[i] = GetRandom <T>(); } byte[] data = new byte[1024]; var fbs = new FlatBufferSerializer( new FlatBufferSerializerOptions(option) { EnableAppDomainInterceptOnAssemblyLoad = true }); var serializer = fbs.Compile((object)table); serializer.Write(data, (object)table); dynamic parsed = serializer.Parse(data); dynamic copy = Activator.CreateInstance(tableType, (object)parsed); Assert.Equal(length, parsed.foo.V.Count); for (int i = 0; i < length; ++i) { CheckRandom <T>(foo.V[i], parsed.foo.V[i]); CheckRandom <T>(foo.V[i], copy.foo.V[i]); } bool isMutable = option is FlatBufferDeserializationOption.GreedyMutable; if (length == 0) { return; } try { for (int i = 0; i < length; ++i) { parsed.foo.V[i] = GetRandom <T>(); } Assert.True(isMutable); } catch (NotMutableException) { Assert.False(isMutable); } }