...

Text file src/github.com/google/flatbuffers/docs/source/CsharpUsage.md

Documentation: github.com/google/flatbuffers/docs/source

     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