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 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## Text parsing 146 147There currently is no support for parsing text (Schema's and JSON) directly 148from C#, though you could use the C++ parser through native call 149interfaces available to each language. Please see the 150C++ documentation for more on text parsing. 151 152## Object based API 153 154FlatBuffers is all about memory efficiency, which is why its base API is written 155around using as little as possible of it. This does make the API clumsier 156(requiring pre-order construction of all data, and making mutation harder). 157 158For times when efficiency is less important a more convenient object based API 159can be used (through `--gen-object-api`) that is able to unpack & pack a 160FlatBuffer into objects and standard `System.Collections.Generic` containers, 161allowing for convenient construction, access and mutation. 162 163To use: 164 165~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs} 166 // Deserialize from buffer into object. 167 MonsterT monsterobj = GetMonster(flatbuffer).UnPack(); 168 169 // Update object directly like a C# class instance. 170 Console.WriteLine(monsterobj.Name); 171 monsterobj.Name = "Bob"; // Change the name. 172 173 // Serialize into new flatbuffer. 174 FlatBufferBuilder fbb = new FlatBufferBuilder(1); 175 fbb.Finish(Monster.Pack(fbb, monsterobj).Value); 176~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 177 178### Json Serialization 179 180An additional feature of the object API is the ability to allow you to 181serialize & deserialize a JSON text. 182To use Json Serialization, add `--cs-gen-json-serializer` option to `flatc` and 183add `Newtonsoft.Json` nuget package to csproj. 184 185~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs} 186 // Deserialize MonsterT from json 187 string jsonText = File.ReadAllText(@"Resources/monsterdata_test.json"); 188 MonsterT mon = MonsterT.DeserializeFromJson(jsonText); 189 190 // Serialize MonsterT to json 191 string jsonText2 = mon.SerializeToJson(); 192~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 193 194* Limitation 195 * `hash` attribute currentry not supported. 196* NuGet package Dependency 197 * [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) 198 199## Conditional compilation symbols 200 201There are three conditional compilation symbols that have an impact on 202performance/features of the C# `ByteBuffer` implementation. 203 204* `UNSAFE_BYTEBUFFER` 205 206 This will use unsafe code to manipulate the underlying byte array. This can 207 yield a reasonable performance increase. 208 209* `BYTEBUFFER_NO_BOUNDS_CHECK` 210 211 This will disable the bounds check asserts to the byte array. This can yield a 212 small performance gain in normal code. 213 214* `ENABLE_SPAN_T` 215 216 This will enable reading and writing blocks of memory with a `Span<T>` instead 217 of just `T[]`. You can also enable writing directly to shared memory or other 218 types of memory by providing a custom implementation of `ByteBufferAllocator`. 219 `ENABLE_SPAN_T` also requires `UNSAFE_BYTEBUFFER` to be defined, or .NET 220 Standard 2.1. 221 222Using `UNSAFE_BYTEBUFFER` and `BYTEBUFFER_NO_BOUNDS_CHECK` together can yield a 223performance gain of ~15% for some operations, however doing so is potentially 224dangerous. Do so at your own risk! 225 226<br> 227