1Use in C# {#flatbuffers_guide_use_c-sharp}
2==============
3
4## Before you get started
5
6Before diving into the FlatBuffers usage in C#, it should be noted that
7the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
8general FlatBuffers usage in all of the supported languages (including C#).
9This page is designed to cover the nuances of FlatBuffers usage,
10specific to C#.
11
12You should also have read the [Building](@ref flatbuffers_guide_building)
13documentation to build `flatc` and should be familiar with
14[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
15[Writing a schema](@ref flatbuffers_guide_writing_schema).
16
17## FlatBuffers C# code location
18
19The code for the FlatBuffers C# library can be found at
20`flatbuffers/net/FlatBuffers`. You can browse the library on the
21[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/net/
22FlatBuffers).
23
24## Building the FlatBuffers C# library
25
26The `FlatBuffers.csproj` project contains multitargeting for .NET Standard 2.1,
27.NET Standard 2.0, and .NET Framework 4.6 (Unity 2017). Support for .NET
28Framework 3.5 (Unity 5) is provided by the `FlatBuffers.net35.csproj` project.
29In most cases (including Unity 2018 and newer), .NET Standard 2.0 is
30recommended.
31
32You can build for a specific framework target when using the cross-platform
33[.NET Core SDK](https://dotnet.microsoft.com/download) by adding the `-f`
34command line option:
35
36~~~{.sh}
37 dotnet build -f netstandard2.0 "FlatBuffers.csproj"
38~~~
39
40The `FlatBuffers.csproj` project also provides support for defining various
41conditional compilation symbols (see "Conditional compilation symbols" section
42below) using the `-p` command line option:
43
44~~~{.sh}
45 dotnet build -f netstandard2.1 -p:ENABLE_SPAN_T=true -p:UNSAFE_BYTEBUFFER=true "FlatBuffers.csproj"
46~~~
47
48## Testing the FlatBuffers C# library
49
50The code to test the libraries can be found at `flatbuffers/tests`.
51
52The test code for C# is located in the [FlatBuffers.Test](https://github.com/
53google/flatbuffers/tree/master/tests/FlatBuffers.Test) subfolder. To run the
54tests, open `FlatBuffers.Test.csproj` in [Visual Studio](
55https://www.visualstudio.com), and compile/run the project.
56
57Optionally, you can run this using [Mono](http://www.mono-project.com/) instead.
58Once you have installed Mono, you can run the tests from the command line
59by running the following commands from inside the `FlatBuffers.Test` folder:
60
61~~~{.sh}
62 mcs *.cs ../MyGame/Example/*.cs ../../net/FlatBuffers/*.cs
63 mono Assert.exe
64~~~
65
66## Using the FlatBuffers C# library
67
68*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
69example of how to use FlatBuffers in C#.*
70
71FlatBuffers supports reading and writing binary FlatBuffers in C#.
72
73To use FlatBuffers in your own code, first generate C# classes from your
74schema with the `--csharp` option to `flatc`.
75Then you can include both FlatBuffers and the generated code to read
76or write a FlatBuffer.
77
78For example, here is how you would read a FlatBuffer binary file in C#:
79First, import the library and generated code. Then, you read a FlatBuffer binary
80file into a `byte[]`. You then turn the `byte[]` into a `ByteBuffer`, which you
81pass to the `GetRootAsMyRootType` function:
82
83~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
84 using MyGame.Example;
85 using Google.FlatBuffers;
86
87 // This snippet ignores exceptions for brevity.
88 byte[] data = File.ReadAllBytes("monsterdata_test.mon");
89
90 ByteBuffer bb = new ByteBuffer(data);
91 Monster monster = Monster.GetRootAsMonster(bb);
92~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
93
94Now you can access the data from the `Monster monster`:
95
96~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
97 short hp = monster.Hp;
98 Vec3 pos = monster.Pos;
99~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100
101C# code naming follows standard C# style with PascalCasing identifiers,
102e.g. `GetRootAsMyRootType`. Also, values (except vectors and unions) are
103available as properties instead of parameterless accessor methods.
104The performance-enhancing methods to which you can pass an already created
105object are prefixed with `Get`, e.g.:
106
107~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
108 // property
109 var pos = monster.Pos;
110
111 // method filling a preconstructed object
112 var preconstructedPos = new Vec3();
113 monster.GetPos(preconstructedPos);
114~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115
116## Storing dictionaries in a FlatBuffer
117
118FlatBuffers doesn't support dictionaries natively, but there is support to
119emulate their behavior with vectors and binary search, which means you
120can have fast lookups directly from a FlatBuffer without having to unpack
121your data into a `Dictionary` or similar.
122
123To use it:
124- Designate one of the fields in a table as the "key" field. You do this
125 by setting the `key` attribute on this field, e.g.
126 `name:string (key)`.
127 You may only have one key field, and it must be of string or scalar type.
128- Write out tables of this type as usual, collect their offsets in an
129 array.
130- Instead of calling standard generated method,
131 e.g.: `Monster.createTestarrayoftablesVector`,
132 call `CreateSortedVectorOfMonster` in C#
133 which will first sort all offsets such that the tables they refer to
134 are sorted by the key field, then serialize it.
135- Now when you're accessing the FlatBuffer, you can use
136 the `ByKey` accessor to access elements of the vector, e.g.:
137 `monster.TestarrayoftablesByKey("Frodo")` in C#,
138 which returns an object of the corresponding table type,
139 or `null` if not found.
140 `ByKey` performs a binary search, so should have a similar
141 speed to `Dictionary`, though may be faster because of better caching.
142 `ByKey` only works if the vector has been sorted, it will
143 likely not find elements if it hasn't been sorted.
144
145## Buffer verification
146
147As mentioned in [C++ Usage](@ref flatbuffers_guide_use_cpp) buffer
148accessor functions do not verify buffer offsets at run-time.
149If it is necessary, you can optionally use a buffer verifier before you
150access the data. This verifier will check all offsets, all sizes of
151fields, and null termination of strings to ensure that when a buffer
152is accessed, all reads will end up inside the buffer.
153
154Each root type will have a verification function generated for it,
155e.g. `Monster.VerifyMonster`. This can be called as shown:
156~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
157 var ok = Monster.VerifyMonster(buf);
158~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
159if `ok` is true, the buffer is safe to read.
160
161For a more detailed control of verification `MonsterVerify.Verify`
162for `Monster` type can be used:
163~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
164 # Sequence of calls
165 FlatBuffers.Verifier verifier = new FlatBuffers.Verifier(buf);
166 var ok = verifier.VerifyBuffer("MONS", false, MonsterVerify.Verify);
167
168 # Or single line call
169 var ok = new FlatBuffers.Verifier(bb).setStringCheck(true).\
170 VerifyBuffer("MONS", false, MonsterVerify.Verify);
171
172~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
173if `ok` is true, the buffer is safe to read.
174
175A second parameter of `verifyBuffer` specifies whether buffer content is
176size prefixed or not. In the example above, the buffer is assumed to not include
177size prefix (`false`).
178
179Verifier supports options that can be set using appropriate fluent methods:
180* SetMaxDepth - limit the nesting depth. Default: 1000000
181* SetMaxTables - total amount of tables the verifier may encounter. Default: 64
182* SetAlignmentCheck - check content alignment. Default: True
183* SetStringCheck - check if strings contain termination '0' character. Default: true
184
185
186## Text parsing
187
188There currently is no support for parsing text (Schema's and JSON) directly
189from C#, though you could use the C++ parser through native call
190interfaces available to each language. Please see the
191C++ documentation for more on text parsing.
192
193## Object based API
194
195FlatBuffers is all about memory efficiency, which is why its base API is written
196around using as little as possible of it. This does make the API clumsier
197(requiring pre-order construction of all data, and making mutation harder).
198
199For times when efficiency is less important a more convenient object based API
200can be used (through `--gen-object-api`) that is able to unpack & pack a
201FlatBuffer into objects and standard `System.Collections.Generic` containers,
202allowing for convenient construction, access and mutation.
203
204To use:
205
206~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
207 // Deserialize from buffer into object.
208 MonsterT monsterobj = GetMonster(flatbuffer).UnPack();
209
210 // Update object directly like a C# class instance.
211 Console.WriteLine(monsterobj.Name);
212 monsterobj.Name = "Bob"; // Change the name.
213
214 // Serialize into new flatbuffer.
215 FlatBufferBuilder fbb = new FlatBufferBuilder(1);
216 fbb.Finish(Monster.Pack(fbb, monsterobj).Value);
217~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218
219### Json Serialization
220
221An additional feature of the object API is the ability to allow you to
222serialize & deserialize a JSON text.
223To use Json Serialization, add `--cs-gen-json-serializer` option to `flatc` and
224add `Newtonsoft.Json` nuget package to csproj. This requires explicitly setting
225the `--gen-object-api` option as well.
226
227~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
228 // Deserialize MonsterT from json
229 string jsonText = File.ReadAllText(@"Resources/monsterdata_test.json");
230 MonsterT mon = MonsterT.DeserializeFromJson(jsonText);
231
232 // Serialize MonsterT to json
233 string jsonText2 = mon.SerializeToJson();
234~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
235
236* Limitation
237 * `hash` attribute currently not supported.
238* NuGet package Dependency
239 * [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
240
241## Conditional compilation symbols
242
243There are three conditional compilation symbols that have an impact on
244performance/features of the C# `ByteBuffer` implementation.
245
246* `UNSAFE_BYTEBUFFER`
247
248 This will use unsafe code to manipulate the underlying byte array. This can
249 yield a reasonable performance increase.
250
251* `BYTEBUFFER_NO_BOUNDS_CHECK`
252
253 This will disable the bounds check asserts to the byte array. This can yield a
254 small performance gain in normal code.
255
256* `ENABLE_SPAN_T`
257
258 This will enable reading and writing blocks of memory with a `Span<T>` instead
259 of just `T[]`. You can also enable writing directly to shared memory or other
260 types of memory by providing a custom implementation of `ByteBufferAllocator`.
261 `ENABLE_SPAN_T` also requires `UNSAFE_BYTEBUFFER` to be defined, or .NET
262 Standard 2.1.
263
264Using `UNSAFE_BYTEBUFFER` and `BYTEBUFFER_NO_BOUNDS_CHECK` together can yield a
265performance gain of ~15% for some operations, however doing so is potentially
266dangerous. Do so at your own risk!
267
268<br>
View as plain text