You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by fl...@apache.org on 2021/04/21 15:24:15 UTC

[tinkerpop] branch TINKERPOP-2348 updated: WIP Enabled nullable warnings for most GraphBinary types

This is an automated email from the ASF dual-hosted git repository.

florianhockmann pushed a commit to branch TINKERPOP-2348
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/TINKERPOP-2348 by this push:
     new d91ca33  WIP Enabled nullable warnings for most GraphBinary types
d91ca33 is described below

commit d91ca336e7bded7d11b56f5c50e6a8bc9185c749
Author: Florian Hockmann <fh...@florian-hockmann.de>
AuthorDate: Wed Apr 21 17:22:49 2021 +0200

    WIP Enabled nullable warnings for most GraphBinary types
    
    Stopped at PathSerializer
---
 gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj  |   7 +-
 .../src/Gremlin.Net/Process/Traversal/Binding.cs   |  34 +---
 .../src/Gremlin.Net/Process/Traversal/Bytecode.cs  |  10 +-
 gremlin-dotnet/src/Gremlin.Net/Structure/Edge.cs   |   8 +-
 .../src/Gremlin.Net/Structure/Element.cs           |  14 +-
 gremlin-dotnet/src/Gremlin.Net/Structure/Graph.cs  |   4 +-
 .../Structure/IO/GraphBinary/DataType.cs           | 149 +++++----------
 .../IO/GraphBinary/GraphBinaryMessageSerializer.cs |   8 +-
 .../Structure/IO/GraphBinary/GraphBinaryReader.cs  |  25 ++-
 .../Structure/IO/GraphBinary/GraphBinaryWriter.cs  |  31 +--
 .../Structure/IO/GraphBinary/ITypeSerializer.cs    |  29 ++-
 .../IO/GraphBinary/RequestMessageSerializer.cs     |  10 +-
 .../IO/GraphBinary/ResponseMessageSerializer.cs    |  16 +-
 .../Structure/IO/GraphBinary/StreamExtensions.cs   |   2 +
 .../IO/GraphBinary/TypeSerializerRegistry.cs       | 208 +++++++++++----------
 .../IO/GraphBinary/Types/ArraySerializer.cs        |   4 +-
 .../IO/GraphBinary/Types/BigDecimalSerializer.cs   |  10 +-
 .../IO/GraphBinary/Types/BigIntegerSerializer.cs   |   6 +-
 .../IO/GraphBinary/Types/BindingSerializer.cs      |   6 +-
 .../IO/GraphBinary/Types/BulkSetSerializer.cs      |   6 +-
 .../IO/GraphBinary/Types/ByteBufferSerializer.cs   |   6 +-
 .../IO/GraphBinary/Types/ByteCodeSerializer.cs     |  22 ++-
 .../IO/GraphBinary/Types/CharSerializer.cs         |   2 +
 .../IO/GraphBinary/Types/ClassSerializer.cs        |   4 +-
 .../GraphBinary/Types/DateTimeOffsetSerializer.cs  |   7 +-
 .../IO/GraphBinary/Types/DurationSerializer.cs     |   2 +
 .../IO/GraphBinary/Types/EdgeSerializer.cs         |  14 +-
 .../IO/GraphBinary/Types/EnumSerializer.cs         |  36 ++--
 .../Structure/IO/GraphBinary/Types/GremlinType.cs  |   4 +-
 .../IO/GraphBinary/Types/LambdaSerializer.cs       |  14 +-
 .../IO/GraphBinary/Types/ListSerializer.cs         |  16 +-
 .../IO/GraphBinary/Types/MapSerializer.cs          |  18 +-
 .../Structure/IO/GraphBinary/Types/PSerializer.cs  |   8 +-
 .../IO/GraphBinary/Types/PropertySerializer.cs     |   4 +-
 .../IO/GraphBinary/Types/SetSerializer.cs          |   4 +-
 .../IO/GraphBinary/Types/SimpleTypeSerializer.cs   |  46 ++---
 .../IO/GraphBinary/Types/SingleTypeSerializer.cs   |  28 ++-
 .../IO/GraphBinary/Types/StringSerializer.cs       |   4 +-
 .../IO/GraphBinary/Types/TraversalSerializer.cs    |   2 +-
 .../Types/TraversalStrategySerializer.cs           |   4 +-
 .../IO/GraphBinary/Types/TraverserSerializer.cs    |   4 +-
 .../IO/GraphBinary/Types/TypeSerializer.cs         |   2 +-
 .../GraphBinary/Types/VertexPropertySerializer.cs  |   4 +-
 .../IO/GraphBinary/Types/VertexSerializer.cs       |   4 +-
 .../Structure/IO/SerializationTokens.cs            |   2 +
 gremlin-dotnet/src/Gremlin.Net/Structure/Path.cs   |  41 ++--
 .../src/Gremlin.Net/Structure/Property.cs          |  10 +-
 gremlin-dotnet/src/Gremlin.Net/Structure/Vertex.cs |   4 +-
 .../src/Gremlin.Net/Structure/VertexProperty.cs    |   6 +-
 .../Gremlin.Net.UnitTest/Structure/PathTests.cs    |   2 +-
 50 files changed, 463 insertions(+), 448 deletions(-)

diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
index 0756da6..3334d9c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
+++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
@@ -71,11 +71,14 @@ NOTE that versions suffixed with "-rc" are considered release candidates (i.e. p
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
-    <PackageReference Include="IsExternalInit" Version="1.0.0" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />    
     <PackageReference Include="System.Text.Json" Version="5.0.2" />
     <PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
     <PackageReference Include="Polly" Version="7.2.0" />
+      
+    <!-- These are only needed to get support for newer C# features in .NET Standard 2.0 -->
+    <PackageReference Include="IsExternalInit" Version="1.0.0" PrivateAssets="all" />
+    <PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Binding.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Binding.cs
index 80c8269..c100701 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Binding.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Binding.cs
@@ -21,21 +21,21 @@
 
 #endregion
 
-using System;
+#nullable enable warnings
 
 namespace Gremlin.Net.Process.Traversal
 {
     /// <summary>
     ///     Associates a variable with a value.
     /// </summary>
-    public class Binding : IEquatable<Binding>
+    public record Binding
     {
         /// <summary>
         ///     Initializes a new instance of the <see cref="Binding" /> class.
         /// </summary>
         /// <param name="key">The key that identifies the <see cref="Binding" />.</param>
         /// <param name="value">The value of the <see cref="Binding" />.</param>
-        public Binding(string key, object value)
+        public Binding(string key, object? value)
         {
             Key = key;
             Value = value;
@@ -49,32 +49,6 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Gets the value of the <see cref="Binding" />.
         /// </summary>
-        public object Value { get; }
-
-        /// <inheritdoc />
-        public bool Equals(Binding other)
-        {
-            if (other == null)
-                return false;
-            return Key == other.Key && Value.Equals(other.Value);
-        }
-
-        /// <inheritdoc />
-        public override bool Equals(object other)
-        {
-            if (ReferenceEquals(null, other)) return false;
-            if (ReferenceEquals(this, other)) return true;
-            if (other.GetType() != GetType()) return false;
-            return Equals(other as Binding);
-        }
-
-        /// <inheritdoc />
-        public override int GetHashCode()
-        {
-            unchecked
-            {
-                return ((Key?.GetHashCode() ?? 0) * 397) ^ (Value?.GetHashCode() ?? 0);
-            }
-        }
+        public object? Value { get; }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
index 7149e8b..f4e44f4 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
@@ -60,19 +60,19 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Gets the traversal source instructions.
         /// </summary>
-        public List<Instruction> SourceInstructions { get; } = new List<Instruction>();
+        public List<Instruction> SourceInstructions { get; } = new();
 
         /// <summary>
         ///     Gets the <see cref="ITraversal" /> instructions.
         /// </summary>
-        public List<Instruction> StepInstructions { get; } = new List<Instruction>();
+        public List<Instruction> StepInstructions { get; } = new();
 
         /// <summary>
         ///     Add a traversal source instruction to the bytecode.
         /// </summary>
         /// <param name="sourceName">The traversal source method name (e.g. withSack()).</param>
         /// <param name="args">The traversal source method arguments.</param>
-        public void AddSource(string sourceName, params object[] args)
+        public void AddSource(string sourceName, params object?[] args)
         {
             SourceInstructions.Add(new Instruction(sourceName, FlattenArguments(args)));
             Bindings.Clear();
@@ -83,7 +83,7 @@ namespace Gremlin.Net.Process.Traversal
         /// </summary>
         /// <param name="stepName">The traversal method name (e.g. out()).</param>
         /// <param name="args">The traversal method arguments.</param>
-        public void AddStep(string stepName, params object[] args)
+        public void AddStep(string stepName, params object?[] args)
         {
             StepInstructions.Add(new Instruction(stepName, FlattenArguments(args)));
             Bindings.Clear();
@@ -108,7 +108,7 @@ namespace Gremlin.Net.Process.Traversal
             return flatArguments.ToArray();
         }
 
-        private object ConvertArgument(object argument, bool searchBindings)
+        private object? ConvertArgument(object? argument, bool searchBindings)
         {
             if (null == argument)
             {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Edge.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/Edge.cs
index fddbd69..efffdf2 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Edge.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Edge.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 namespace Gremlin.Net.Structure
 {
     /// <summary>
@@ -35,7 +37,7 @@ namespace Gremlin.Net.Structure
         /// <param name="outV">The outgoing/tail vertex of the edge.</param>
         /// <param name="label">The label of the edge.</param>
         /// <param name="inV">The incoming/head vertex of the edge.</param>
-        public Edge(object id, Vertex outV, string label, Vertex inV)
+        public Edge(object? id, Vertex outV, string label, Vertex inV)
             : base(id, label)
         {
             OutV = outV;
@@ -45,12 +47,12 @@ namespace Gremlin.Net.Structure
         /// <summary>
         ///     Gets or sets the incoming/head vertex of this edge.
         /// </summary>
-        public Vertex InV { get; set; }
+        public Vertex InV { get; }
 
         /// <summary>
         ///     Gets or sets the outgoing/tail vertex of this edge.
         /// </summary>
-        public Vertex OutV { get; set; }
+        public Vertex OutV { get; }
 
         /// <inheritdoc />
         public override string ToString()
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
index f4fc847..7218600 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Element.cs
@@ -21,21 +21,21 @@
 
 #endregion
 
-using System;
+#nullable enable warnings
 
 namespace Gremlin.Net.Structure
 {
     /// <summary>
     ///     A common base class for Graph elements.
     /// </summary>
-    public abstract class Element : IEquatable<Element>
+    public abstract class Element
     {
         /// <summary>
         ///     Initializes a new instance of the <see cref="Element" /> class.
         /// </summary>
         /// <param name="id">The id of the element.</param>
         /// <param name="label">The label of the element.</param>
-        protected Element(object id, string label)
+        protected Element(object? id, string label)
         {
             Id = id;
             Label = label;
@@ -44,7 +44,7 @@ namespace Gremlin.Net.Structure
         /// <summary>
         ///     Gets the id of this <see cref="Element" />.
         /// </summary>
-        public object Id { get; }
+        public object? Id { get; }
 
         /// <summary>
         ///     Gets the label of this <see cref="Element" />.
@@ -52,7 +52,7 @@ namespace Gremlin.Net.Structure
         public string Label { get; }
 
         /// <inheritdoc />
-        public bool Equals(Element other)
+        public bool Equals(Element? other)
         {
             if (ReferenceEquals(null, other)) return false;
             if (ReferenceEquals(this, other)) return true;
@@ -60,7 +60,7 @@ namespace Gremlin.Net.Structure
         }
 
         /// <inheritdoc />
-        public override bool Equals(object obj)
+        public override bool Equals(object? obj)
         {
             if (ReferenceEquals(null, obj)) return false;
             if (ReferenceEquals(this, obj)) return true;
@@ -71,7 +71,7 @@ namespace Gremlin.Net.Structure
         /// <inheritdoc />
         public override int GetHashCode()
         {
-            return Id.GetHashCode();
+            return Id != null ? Id.GetHashCode() : 0;
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Graph.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/Graph.cs
index 4d49689..fde7f09 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Graph.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Graph.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using Gremlin.Net.Process.Traversal;
 
@@ -39,7 +41,7 @@ namespace Gremlin.Net.Structure
         [Obsolete("As of release 3.3.5, replaced by AnonymousTraversalSource.Traversal() called statically.", false)]
         public GraphTraversalSource Traversal()
         {
-            return new GraphTraversalSource();
+            return new();
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
index cb309c2..b2f3068 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
@@ -21,67 +21,67 @@
 
 #endregion
 
-using System;
+#nullable enable warnings
 
 namespace Gremlin.Net.Structure.IO.GraphBinary
 {
     /// <summary>
     /// Represents a GraphBinary data type.
     /// </summary>
-    public class DataType : IEquatable<DataType>
+    public record DataType
     {
 #pragma warning disable 1591
-        public static readonly DataType Int = new DataType(0x01);
-        public static readonly DataType Long = new DataType(0x02);
-        public static readonly DataType String = new DataType(0x03);
-        public static readonly DataType Date = new DataType(0x04);
-        public static readonly DataType Timestamp = new DataType(0x05);
-        public static readonly DataType Class = new DataType(0x06);
-        public static readonly DataType Double = new DataType(0x07);
-        public static readonly DataType Float = new DataType(0x08);
-        public static readonly DataType List = new DataType(0x09);
-        public static readonly DataType Map = new DataType(0X0A);
-        public static readonly DataType Set = new DataType(0X0B);
-        public static readonly DataType Uuid = new DataType(0X0C);
-        public static readonly DataType Edge = new DataType(0x0D);
-        public static readonly DataType Path = new DataType(0x0E);
-        public static readonly DataType Property = new DataType(0x0F);
+        public static readonly DataType Int = new(0x01);
+        public static readonly DataType Long = new(0x02);
+        public static readonly DataType String = new(0x03);
+        public static readonly DataType Date = new(0x04);
+        public static readonly DataType Timestamp = new(0x05);
+        public static readonly DataType Class = new(0x06);
+        public static readonly DataType Double = new(0x07);
+        public static readonly DataType Float = new(0x08);
+        public static readonly DataType List = new(0x09);
+        public static readonly DataType Map = new(0X0A);
+        public static readonly DataType Set = new(0X0B);
+        public static readonly DataType Uuid = new(0X0C);
+        public static readonly DataType Edge = new(0x0D);
+        public static readonly DataType Path = new(0x0E);
+        public static readonly DataType Property = new(0x0F);
         
-        public static readonly DataType Vertex = new DataType(0x11);
-        public static readonly DataType VertexProperty = new DataType(0x12);
-        public static readonly DataType Barrier = new DataType(0x13);
-        public static readonly DataType Binding = new DataType(0x14);
-        public static readonly DataType Bytecode = new DataType(0x15);
-        public static readonly DataType Cardinality = new DataType(0x16);
-        public static readonly DataType Column = new DataType(0x17);
-        public static readonly DataType Direction = new DataType(0x18);
-        public static readonly DataType Operator = new DataType(0x19);
-        public static readonly DataType Order = new DataType(0x1A);
-        public static readonly DataType Pick = new DataType(0x1B);
-        public static readonly DataType Pop = new DataType(0x1C);
-        public static readonly DataType Lambda = new DataType(0x1D);
-        public static readonly DataType P = new DataType(0x1E);
-        public static readonly DataType Scope = new DataType(0x1F);
-        public static readonly DataType T = new DataType(0x20);
-        public static readonly DataType Traverser = new DataType(0x21);
-        public static readonly DataType BigDecimal = new DataType(0x22);
-        public static readonly DataType BigInteger = new DataType(0x23);
-        public static readonly DataType Byte = new DataType(0x24);
-        public static readonly DataType ByteBuffer = new DataType(0x25);
-        public static readonly DataType Short = new DataType(0x26);
-        public static readonly DataType Boolean = new DataType(0x27);
-        public static readonly DataType TextP = new DataType(0x28);
-        public static readonly DataType TraversalStrategy = new DataType(0x29);
-        public static readonly DataType BulkSet = new DataType(0x2A);
+        public static readonly DataType Vertex = new(0x11);
+        public static readonly DataType VertexProperty = new(0x12);
+        public static readonly DataType Barrier = new(0x13);
+        public static readonly DataType Binding = new(0x14);
+        public static readonly DataType Bytecode = new(0x15);
+        public static readonly DataType Cardinality = new(0x16);
+        public static readonly DataType Column = new(0x17);
+        public static readonly DataType Direction = new(0x18);
+        public static readonly DataType Operator = new(0x19);
+        public static readonly DataType Order = new(0x1A);
+        public static readonly DataType Pick = new(0x1B);
+        public static readonly DataType Pop = new(0x1C);
+        public static readonly DataType Lambda = new(0x1D);
+        public static readonly DataType P = new(0x1E);
+        public static readonly DataType Scope = new(0x1F);
+        public static readonly DataType T = new(0x20);
+        public static readonly DataType Traverser = new(0x21);
+        public static readonly DataType BigDecimal = new(0x22);
+        public static readonly DataType BigInteger = new(0x23);
+        public static readonly DataType Byte = new(0x24);
+        public static readonly DataType ByteBuffer = new(0x25);
+        public static readonly DataType Short = new(0x26);
+        public static readonly DataType Boolean = new(0x27);
+        public static readonly DataType TextP = new(0x28);
+        public static readonly DataType TraversalStrategy = new(0x29);
+        public static readonly DataType BulkSet = new(0x2A);
         // TODO: Support metrics and traversal metrics
-        public static readonly DataType Char = new DataType(0x80);
-        public static readonly DataType Duration = new DataType(0x81);
+        public static readonly DataType Char = new(0x80);
+        public static readonly DataType Duration = new(0x81);
 #pragma warning restore 1591
 
         /// <summary>
         /// A null value for an unspecified Object value.
         /// </summary>
-        public static readonly DataType UnspecifiedNull = new DataType(0xFE);
+        public static readonly DataType UnspecifiedNull = new(0xFE);
 
         private DataType(int code)
         {
@@ -98,62 +98,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         /// </summary>
         public static DataType FromTypeCode(int code)
         {
-            return new DataType(code);
-        }
-
-        /// <inheritdoc />
-        public bool Equals(DataType other)
-        {
-            if (ReferenceEquals(null, other)) return false;
-            if (ReferenceEquals(this, other)) return true;
-            return TypeCode == other.TypeCode;
-        }
-
-        /// <inheritdoc />
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != GetType()) return false;
-            return Equals((DataType) obj);
-        }
-
-        /// <inheritdoc />
-        public override int GetHashCode()
-        {
-            return TypeCode.GetHashCode();
-        }
-
-        /// <summary>
-        /// Determines whether two specified <see cref="DataType"/> have the same values.
-        /// </summary>
-        public static bool operator ==(DataType first, DataType second)
-        {
-            if (ReferenceEquals(null, first))
-            {
-                if (ReferenceEquals(null, second))
-                {
-                    return true;
-                }
-
-                return false;
-            }
-
-            return first.Equals(second);
-        }
-
-        /// <summary>
-        /// Determines whether two specified <see cref="DataType"/> have different values.
-        /// </summary>
-        public static bool operator !=(DataType first, DataType second)
-        {
-            return !(first == second);
-        }
-
-        /// <inheritdoc />
-        public override string ToString()
-        {
-            return $"DataType{{ TypeCode = {TypeCode} }}";
+            return new(code);
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryMessageSerializer.cs
index 2b56935..2ca971c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryMessageSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryMessageSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
@@ -40,15 +42,15 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         
         private readonly GraphBinaryReader _reader;
         private readonly GraphBinaryWriter _writer;
-        private readonly RequestMessageSerializer _requestSerializer = new RequestMessageSerializer();
-        private readonly ResponseMessageSerializer _responseSerializer = new ResponseMessageSerializer();
+        private readonly RequestMessageSerializer _requestSerializer = new();
+        private readonly ResponseMessageSerializer _responseSerializer = new();
 
         /// <summary>
         /// Initializes a new instance of the <see cref="GraphBinaryMessageSerializer" /> class.
         /// </summary>
         /// <param name="reader">The <see cref="GraphBinaryReader"/> used to deserialize from GraphBinary.</param>
         /// <param name="writer">The <see cref="GraphBinaryWriter"/> used to serialize to GraphBinary.</param>
-        public GraphBinaryMessageSerializer(GraphBinaryReader reader = null, GraphBinaryWriter writer = null)
+        public GraphBinaryMessageSerializer(GraphBinaryReader? reader = null, GraphBinaryWriter? writer = null)
         {
             _reader = reader ?? new GraphBinaryReader();
             _writer = writer ?? new GraphBinaryWriter();
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryReader.cs
index deaf31a..521c774 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryReader.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryReader.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 
@@ -31,19 +33,30 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
     /// </summary>
     public class GraphBinaryReader
     {
-        private readonly TypeSerializerRegistry _registry = new TypeSerializerRegistry();
+        private readonly TypeSerializerRegistry _registry = new();
+        
+        /// <summary>
+        /// Reads only the value for a specific type <typeparamref name="T"/>.
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <typeparam name="T">The type of the object to read.</typeparam>
+        /// <returns>The read value.</returns>
+        public async Task<object?> ReadNullableValueAsync<T>(Stream stream)
+        {
+            var typedSerializer = _registry.GetSerializerFor(typeof(T));
+            return await typedSerializer.ReadNullableValueAsync(stream, this).ConfigureAwait(false);
+        }
         
         /// <summary>
         /// Reads only the value for a specific type <typeparamref name="T"/>.
         /// </summary>
         /// <param name="stream">The GraphBinary data to parse.</param>
-        /// <param name="nullable">Whether or not the value can be null.</param>
         /// <typeparam name="T">The type of the object to read.</typeparam>
         /// <returns>The read value.</returns>
-        public async Task<object> ReadValueAsync<T>(Stream stream, bool nullable)
+        public async Task<object> ReadNonNullableValueAsync<T>(Stream stream)
         {
             var typedSerializer = _registry.GetSerializerFor(typeof(T));
-            return await typedSerializer.ReadValueAsync(stream, this, nullable).ConfigureAwait(false);
+            return await typedSerializer.ReadNonNullableValueAsync(stream, this).ConfigureAwait(false);
         }
         
         /// <summary>
@@ -51,14 +64,14 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         /// </summary>
         /// <param name="stream">The GraphBinary data to parse.</param>
         /// <returns>The read value.</returns>
-        public async Task<object> ReadAsync(Stream stream)
+        public async Task<object?> ReadAsync(Stream stream)
         {
             var type = DataType.FromTypeCode(await stream.ReadByteAsync().ConfigureAwait(false));
 
             if (type == DataType.UnspecifiedNull)
             {
                 await stream.ReadByteAsync().ConfigureAwait(false); // read value byte to advance the index
-                return default; // should be null (TODO?)
+                return null;
             }
 
             var typedSerializer = _registry.GetSerializerFor(type);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryWriter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryWriter.cs
index e1eec8f..435f752 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryWriter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/GraphBinaryWriter.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 
@@ -41,31 +43,38 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
 
         private static readonly byte[] UnspecifiedNullBytes = {DataType.UnspecifiedNull.TypeCode, 0x01};
 
-        private readonly TypeSerializerRegistry _registry = new TypeSerializerRegistry();
+        private readonly TypeSerializerRegistry _registry = new();
 
         /// <summary>
-        /// Writes a value without including type information.
+        /// Writes a nullable value without including type information.
         /// </summary>
         /// <param name="value">The value to write.</param>
         /// <param name="stream">The stream to write to.</param>
-        /// <param name="nullable">Whether or not the value can be null.</param>
         /// <returns>A task that represents the asynchronous write operation.</returns>
-        public async Task WriteValueAsync(object value, Stream stream, bool nullable)
+        public async Task WriteNullableValueAsync(object? value, Stream stream)
         {
             if (value == null)
             {
-                if (!nullable)
-                {
-                    throw new IOException("Unexpected null value when nullable is false");
-                }
-
                 await WriteValueFlagNullAsync(stream).ConfigureAwait(false);
                 return;
             }
             
             var valueType = value.GetType();
             var serializer = _registry.GetSerializerFor(valueType);
-            await serializer.WriteValueAsync(value, stream, this, nullable).ConfigureAwait(false);
+            await serializer.WriteNullableValueAsync(value, stream, this).ConfigureAwait(false);
+        }
+        
+        /// <summary>
+        /// Writes a non-nullable value without including type information.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        public async Task WriteNonNullableValueAsync(object value, Stream stream)
+        {
+            var valueType = value.GetType();
+            var serializer = _registry.GetSerializerFor(valueType);
+            await serializer.WriteNonNullableValueAsync(value, stream, this).ConfigureAwait(false);
         }
         
         /// <summary>
@@ -74,7 +83,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         /// <param name="value">The value to write.</param>
         /// <param name="stream">The stream to write to.</param>
         /// <returns>A task that represents the asynchronous write operation.</returns>
-        public async Task WriteAsync(object value, Stream stream)
+        public async Task WriteAsync(object? value, Stream stream)
         {
             if (value == null)
             {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ITypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ITypeSerializer.cs
index fd21f52..f2bd67d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ITypeSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ITypeSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 
@@ -46,14 +48,22 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         Task WriteAsync(object value, Stream stream, GraphBinaryWriter writer);
 
         /// <summary>
-        /// Writes the value to a stream, composed by the value flag and the sequence of bytes.
+        /// Writes the nullable value to a stream, composed by the value flag and the sequence of bytes.
+        /// </summary>
+        /// <param name="value">The value to write.</param>
+        /// <param name="stream">The stream to write to.</param>
+        /// <param name="writer">A <see cref="GraphBinaryWriter"/> that can be used to write nested values.</param>
+        /// <returns>A task that represents the asynchronous write operation.</returns>
+        Task WriteNullableValueAsync(object? value, Stream stream, GraphBinaryWriter writer);
+        
+        /// <summary>
+        /// Writes the non-nullable value to a stream, composed by the value flag and the sequence of bytes.
         /// </summary>
         /// <param name="value">The value to write.</param>
         /// <param name="stream">The stream to write to.</param>
         /// <param name="writer">A <see cref="GraphBinaryWriter"/> that can be used to write nested values.</param>
-        /// <param name="nullable">Whether or not the value can be null.</param>
         /// <returns>A task that represents the asynchronous write operation.</returns>
-        Task WriteValueAsync(object value, Stream stream, GraphBinaryWriter writer, bool nullable);
+        Task WriteNonNullableValueAsync(object value, Stream stream, GraphBinaryWriter writer);
 
         /// <summary>
         /// Reads the type information and value from the stream.
@@ -61,15 +71,22 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         /// <param name="stream">The GraphBinary data to parse.</param>
         /// <param name="reader">A <see cref="GraphBinaryReader"/> that can be used to read nested values.</param>
         /// <returns>The read value.</returns>
-        Task<object> ReadAsync(Stream stream, GraphBinaryReader reader);
+        Task<object?> ReadAsync(Stream stream, GraphBinaryReader reader);
 
         /// <summary>
         /// Reads the value from the stream (not the type information).
         /// </summary>
         /// <param name="stream">The GraphBinary data to parse.</param>
         /// <param name="reader">A <see cref="GraphBinaryReader"/> that can be used to read nested values.</param>
-        /// <param name="nullable">Whether or not the value can be null.</param>
         /// <returns>The read value.</returns>
-        Task<object> ReadValueAsync(Stream stream, GraphBinaryReader reader, bool nullable);
+        Task<object?> ReadNullableValueAsync(Stream stream, GraphBinaryReader reader);
+        
+        /// <summary>
+        /// Reads the value from the stream (not the type information).
+        /// </summary>
+        /// <param name="stream">The GraphBinary data to parse.</param>
+        /// <param name="reader">A <see cref="GraphBinaryReader"/> that can be used to read nested values.</param>
+        /// <returns>The read value.</returns>
+        Task<object> ReadNonNullableValueAsync(Stream stream, GraphBinaryReader reader);
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/RequestMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/RequestMessageSerializer.cs
index e9e22f3..cd8fed0 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/RequestMessageSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/RequestMessageSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver.Messages;
@@ -42,10 +44,10 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         public async Task WriteValueAsync(RequestMessage requestMessage, MemoryStream stream, GraphBinaryWriter writer)
         {
             await stream.WriteByteAsync(GraphBinaryWriter.VersionByte).ConfigureAwait(false);
-            await writer.WriteValueAsync(requestMessage.RequestId, stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(requestMessage.Operation, stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(requestMessage.Processor, stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(requestMessage.Arguments, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(requestMessage.RequestId, stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(requestMessage.Operation, stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(requestMessage.Processor, stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(requestMessage.Arguments, stream).ConfigureAwait(false);
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ResponseMessageSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ResponseMessageSerializer.cs
index ec8cfae..25aabf7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ResponseMessageSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/ResponseMessageSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -51,17 +53,17 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
                 throw new IOException("The most significant bit should be set according to the format");
             }
 
-            var requestId = (Guid?) await reader.ReadValueAsync<Guid>(stream, true).ConfigureAwait(false);
-            var code = (ResponseStatusCode) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
-            var message = (string) await reader.ReadValueAsync<string>(stream, true).ConfigureAwait(false);
-            var dictObj = await reader
-                .ReadValueAsync<Dictionary<string, object>>(stream, false).ConfigureAwait(false);
+            var requestId = (Guid?) await reader.ReadNullableValueAsync<Guid>(stream).ConfigureAwait(false);
+            var code = (ResponseStatusCode) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
+            var message = (string?) await reader.ReadNullableValueAsync<string>(stream).ConfigureAwait(false);
+            var dictObj = await reader.ReadNonNullableValueAsync<Dictionary<string, object>>(stream)
+                .ConfigureAwait(false);
             var attributes = (Dictionary<string, object>) dictObj;
 
             var status = new ResponseStatus(code, attributes, message);
             var result = new ResponseResult<List<object>>(
-                (List<object>) await reader.ReadAsync(stream).ConfigureAwait(false),
-                (Dictionary<string, object>) await reader.ReadValueAsync<Dictionary<string, object>>(stream, false)
+                (List<object>) (await reader.ReadAsync(stream).ConfigureAwait(false))!,
+                (Dictionary<string, object>) await reader.ReadNonNullableValueAsync<Dictionary<string, object>>(stream)
                     .ConfigureAwait(false));
 
             return new ResponseMessage<List<object>>(requestId, status, result);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/StreamExtensions.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/StreamExtensions.cs
index c407c21..86746c7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/StreamExtensions.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/StreamExtensions.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Threading.Tasks;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
index efa1699..826d3b3 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -36,98 +38,96 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
     /// </summary>
     public class TypeSerializerRegistry
     {
-        private static readonly Dictionary<Type, ITypeSerializer> SerializerByType =
-            new Dictionary<Type, ITypeSerializer>
-            {
-                {typeof(int), SingleTypeSerializers.IntSerializer},
-                {typeof(long), SingleTypeSerializers.LongSerializer},
-                {typeof(string), new StringSerializer()},
-                {typeof(DateTimeOffset), DateTimeOffsetSerializer.DateSerializer},
-                {typeof(GremlinType), new ClassSerializer()},
-                {typeof(Type), new TypeSerializer()},
-                {typeof(double), SingleTypeSerializers.DoubleSerializer},
-                {typeof(float), SingleTypeSerializers.FloatSerializer},
-                {typeof(Guid), new UuidSerializer()},
-                {typeof(Edge), new EdgeSerializer()},
-                {typeof(Path), new PathSerializer()},
-                {typeof(Property), new PropertySerializer()},
-                {typeof(Vertex), new VertexSerializer()},
-                {typeof(VertexProperty), new VertexPropertySerializer()},
-                {typeof(Barrier), EnumSerializers.BarrierSerializer},
-                {typeof(Binding), new BindingSerializer()},
-                {typeof(Bytecode), new BytecodeSerializer()},
-                {typeof(ITraversal), new TraversalSerializer()},
-                {typeof(Cardinality), EnumSerializers.CardinalitySerializer},
-                {typeof(Column), EnumSerializers.ColumnSerializer},
-                {typeof(Direction), EnumSerializers.DirectionSerializer},
-                {typeof(Operator), EnumSerializers.OperatorSerializer},
-                {typeof(Order), EnumSerializers.OrderSerializer},
-                {typeof(Pick), EnumSerializers.PickSerializer},
-                {typeof(Pop), EnumSerializers.PopSerializer},
-                {typeof(ILambda), new LambdaSerializer()},
-                {typeof(P), new PSerializer(DataType.P)},
-                {typeof(Scope), EnumSerializers.ScopeSerializer},
-                {typeof(T), EnumSerializers.TSerializer},
-                {typeof(Traverser), new TraverserSerializer()},
-                {typeof(decimal), new BigDecimalSerializer()},
-                {typeof(BigInteger), new BigIntegerSerializer()},
-                {typeof(byte), SingleTypeSerializers.ByteSerializer},
-                {typeof(byte[]), new ByteBufferSerializer()},
-                {typeof(short), SingleTypeSerializers.ShortSerializer},
-                {typeof(bool), SingleTypeSerializers.BooleanSerializer},
-                {typeof(TextP), new PSerializer(DataType.TextP)},
-                {typeof(AbstractTraversalStrategy), new TraversalStrategySerializer()},
-                {typeof(char), new CharSerializer()},
-                {typeof(TimeSpan), new DurationSerializer()},
-            };
+        private static readonly Dictionary<Type, ITypeSerializer> SerializerByType = new()
+        {
+            {typeof(int), SingleTypeSerializers.IntSerializer},
+            {typeof(long), SingleTypeSerializers.LongSerializer},
+            {typeof(string), new StringSerializer()},
+            {typeof(DateTimeOffset), DateTimeOffsetSerializer.DateSerializer},
+            {typeof(GremlinType), new ClassSerializer()},
+            {typeof(Type), new TypeSerializer()},
+            {typeof(double), SingleTypeSerializers.DoubleSerializer},
+            {typeof(float), SingleTypeSerializers.FloatSerializer},
+            {typeof(Guid), new UuidSerializer()},
+            {typeof(Edge), new EdgeSerializer()},
+            {typeof(Path), new PathSerializer()},
+            {typeof(Property), new PropertySerializer()},
+            {typeof(Vertex), new VertexSerializer()},
+            {typeof(VertexProperty), new VertexPropertySerializer()},
+            {typeof(Barrier), EnumSerializers.BarrierSerializer},
+            {typeof(Binding), new BindingSerializer()},
+            {typeof(Bytecode), new BytecodeSerializer()},
+            {typeof(ITraversal), new TraversalSerializer()},
+            {typeof(Cardinality), EnumSerializers.CardinalitySerializer},
+            {typeof(Column), EnumSerializers.ColumnSerializer},
+            {typeof(Direction), EnumSerializers.DirectionSerializer},
+            {typeof(Operator), EnumSerializers.OperatorSerializer},
+            {typeof(Order), EnumSerializers.OrderSerializer},
+            {typeof(Pick), EnumSerializers.PickSerializer},
+            {typeof(Pop), EnumSerializers.PopSerializer},
+            {typeof(ILambda), new LambdaSerializer()},
+            {typeof(P), new PSerializer(DataType.P)},
+            {typeof(Scope), EnumSerializers.ScopeSerializer},
+            {typeof(T), EnumSerializers.TSerializer},
+            {typeof(Traverser), new TraverserSerializer()},
+            {typeof(decimal), new BigDecimalSerializer()},
+            {typeof(BigInteger), new BigIntegerSerializer()},
+            {typeof(byte), SingleTypeSerializers.ByteSerializer},
+            {typeof(byte[]), new ByteBufferSerializer()},
+            {typeof(short), SingleTypeSerializers.ShortSerializer},
+            {typeof(bool), SingleTypeSerializers.BooleanSerializer},
+            {typeof(TextP), new PSerializer(DataType.TextP)},
+            {typeof(AbstractTraversalStrategy), new TraversalStrategySerializer()},
+            {typeof(char), new CharSerializer()},
+            {typeof(TimeSpan), new DurationSerializer()}
+        };
 
-        private static readonly Dictionary<DataType, ITypeSerializer> SerializerByDataType =
-            new Dictionary<DataType, ITypeSerializer>
-            {
-                {DataType.Int, SingleTypeSerializers.IntSerializer},
-                {DataType.Long, SingleTypeSerializers.LongSerializer},
-                {DataType.String, new StringSerializer()},
-                {DataType.Date, DateTimeOffsetSerializer.DateSerializer},
-                {DataType.Timestamp, DateTimeOffsetSerializer.TimestampSerializer},
-                {DataType.Class, new ClassSerializer()},
-                {DataType.Double, SingleTypeSerializers.DoubleSerializer},
-                {DataType.Float, SingleTypeSerializers.FloatSerializer},
-                {DataType.List, new ListSerializer<object>()},
-                {DataType.Map, new MapSerializer<object, object>()},
-                {DataType.Set, new SetSerializer<HashSet<object>, object>()},
-                {DataType.Uuid, new UuidSerializer()},
-                {DataType.Edge, new EdgeSerializer()},
-                {DataType.Path, new PathSerializer()},
-                {DataType.Property, new PropertySerializer()},
-                {DataType.Vertex, new VertexSerializer()},
-                {DataType.VertexProperty, new VertexPropertySerializer()},
-                {DataType.Barrier, EnumSerializers.BarrierSerializer},
-                {DataType.Binding, new BindingSerializer()},
-                {DataType.Bytecode, new BytecodeSerializer()},
-                {DataType.Cardinality, EnumSerializers.CardinalitySerializer},
-                {DataType.Column, EnumSerializers.ColumnSerializer},
-                {DataType.Direction, EnumSerializers.DirectionSerializer},
-                {DataType.Operator, EnumSerializers.OperatorSerializer},
-                {DataType.Order, EnumSerializers.OrderSerializer},
-                {DataType.Pick, EnumSerializers.PickSerializer},
-                {DataType.Pop, EnumSerializers.PopSerializer},
-                {DataType.Lambda, new LambdaSerializer()},
-                {DataType.P, new PSerializer(DataType.P)},
-                {DataType.Scope, EnumSerializers.ScopeSerializer},
-                {DataType.T, EnumSerializers.TSerializer},
-                {DataType.Traverser, new TraverserSerializer()},
-                {DataType.BigDecimal, new BigDecimalSerializer()},
-                {DataType.BigInteger, new BigIntegerSerializer()},
-                {DataType.Byte, SingleTypeSerializers.ByteSerializer},
-                {DataType.ByteBuffer, new ByteBufferSerializer()},
-                {DataType.Short, SingleTypeSerializers.ShortSerializer},
-                {DataType.Boolean, SingleTypeSerializers.BooleanSerializer},
-                {DataType.TextP, new PSerializer(DataType.TextP)},
-                {DataType.TraversalStrategy, new TraversalStrategySerializer()},
-                {DataType.BulkSet, new BulkSetSerializer<List<object>>()},
-                {DataType.Char, new CharSerializer()},
-                {DataType.Duration, new DurationSerializer()},
-            };
+        private static readonly Dictionary<DataType, ITypeSerializer> SerializerByDataType = new()
+        {
+            {DataType.Int, SingleTypeSerializers.IntSerializer},
+            {DataType.Long, SingleTypeSerializers.LongSerializer},
+            {DataType.String, new StringSerializer()},
+            {DataType.Date, DateTimeOffsetSerializer.DateSerializer},
+            {DataType.Timestamp, DateTimeOffsetSerializer.TimestampSerializer},
+            {DataType.Class, new ClassSerializer()},
+            {DataType.Double, SingleTypeSerializers.DoubleSerializer},
+            {DataType.Float, SingleTypeSerializers.FloatSerializer},
+            {DataType.List, new ListSerializer<object>()},
+            {DataType.Map, new MapSerializer<object, object>()},
+            {DataType.Set, new SetSerializer<HashSet<object>, object>()},
+            {DataType.Uuid, new UuidSerializer()},
+            {DataType.Edge, new EdgeSerializer()},
+            {DataType.Path, new PathSerializer()},
+            {DataType.Property, new PropertySerializer()},
+            {DataType.Vertex, new VertexSerializer()},
+            {DataType.VertexProperty, new VertexPropertySerializer()},
+            {DataType.Barrier, EnumSerializers.BarrierSerializer},
+            {DataType.Binding, new BindingSerializer()},
+            {DataType.Bytecode, new BytecodeSerializer()},
+            {DataType.Cardinality, EnumSerializers.CardinalitySerializer},
+            {DataType.Column, EnumSerializers.ColumnSerializer},
+            {DataType.Direction, EnumSerializers.DirectionSerializer},
+            {DataType.Operator, EnumSerializers.OperatorSerializer},
+            {DataType.Order, EnumSerializers.OrderSerializer},
+            {DataType.Pick, EnumSerializers.PickSerializer},
+            {DataType.Pop, EnumSerializers.PopSerializer},
+            {DataType.Lambda, new LambdaSerializer()},
+            {DataType.P, new PSerializer(DataType.P)},
+            {DataType.Scope, EnumSerializers.ScopeSerializer},
+            {DataType.T, EnumSerializers.TSerializer},
+            {DataType.Traverser, new TraverserSerializer()},
+            {DataType.BigDecimal, new BigDecimalSerializer()},
+            {DataType.BigInteger, new BigIntegerSerializer()},
+            {DataType.Byte, SingleTypeSerializers.ByteSerializer},
+            {DataType.ByteBuffer, new ByteBufferSerializer()},
+            {DataType.Short, SingleTypeSerializers.ShortSerializer},
+            {DataType.Boolean, SingleTypeSerializers.BooleanSerializer},
+            {DataType.TextP, new PSerializer(DataType.TextP)},
+            {DataType.TraversalStrategy, new TraversalStrategySerializer()},
+            {DataType.BulkSet, new BulkSetSerializer<List<object>>()},
+            {DataType.Char, new CharSerializer()},
+            {DataType.Duration, new DurationSerializer()}
+        };
 
         /// <summary>
         /// Gets a serializer for the given type of the value to be serialized.
@@ -147,8 +147,10 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
                 var dictKeyType = valueType.GetGenericArguments()[0];
                 var dictValueType = valueType.GetGenericArguments()[1];
                 var serializerType = typeof(MapSerializer<,>).MakeGenericType(dictKeyType, dictValueType);
-                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
-                SerializerByType[valueType] = serializer;
+                var serializer = (ITypeSerializer?) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer ??
+                                              throw new InvalidOperationException(
+                                                  $"Cannot create a serializer for the dictionary type {valueType}.");
                 return serializer;
             }
 
@@ -156,17 +158,21 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
             {
                 var memberType = valueType.GetGenericArguments()[0];
                 var serializerType = typeof(SetSerializer<,>).MakeGenericType(valueType, memberType);
-                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
-                SerializerByType[valueType] = serializer;
+                var serializer = (ITypeSerializer?) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer ??
+                                              throw new InvalidOperationException(
+                                                  $"Cannot create a serializer for the set type {valueType}.");
                 return serializer;
             }
 
             if (valueType.IsArray)
             {
                 var memberType = valueType.GetElementType();
-                var serializerType = typeof(ArraySerializer<>).MakeGenericType(memberType);
-                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
-                SerializerByType[valueType] = serializer;
+                var serializerType = typeof(ArraySerializer<>).MakeGenericType(memberType!);
+                var serializer = (ITypeSerializer?) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer ??
+                                              throw new InvalidOperationException(
+                                                  $"Cannot create a serializer for the array type {valueType}.");
                 return serializer;
             }
 
@@ -174,8 +180,10 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
             {
                 var memberType = valueType.GetGenericArguments()[0];
                 var serializerType = typeof(ListSerializer<>).MakeGenericType(memberType);
-                var serializer = (ITypeSerializer) Activator.CreateInstance(serializerType);
-                SerializerByType[valueType] = serializer;
+                var serializer = (ITypeSerializer?) Activator.CreateInstance(serializerType);
+                SerializerByType[valueType] = serializer ??
+                                              throw new InvalidOperationException(
+                                                  $"Cannot create a serializer for the list type {valueType}.");
                 return serializer;
             }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ArraySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ArraySerializer.cs
index fecac6d..4b4abc4 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ArraySerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ArraySerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Threading.Tasks;
@@ -43,7 +45,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(TMember[] value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Length, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Length, stream).ConfigureAwait(false);
             
             foreach (var item in value)
             {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigDecimalSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigDecimalSerializer.cs
index 3aebd85..19f6145 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigDecimalSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigDecimalSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Numerics;
@@ -44,8 +46,8 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task WriteValueAsync(decimal value, Stream stream, GraphBinaryWriter writer)
         {
             var (unscaledValue, scale) = GetUnscaledValueAndScale(value);
-            await writer.WriteValueAsync(scale, stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(unscaledValue, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(scale, stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(unscaledValue, stream).ConfigureAwait(false);
         }
         
         private static (BigInteger, int) GetUnscaledValueAndScale(decimal input)
@@ -76,8 +78,8 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task<decimal> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var scale = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
-            var unscaled = (BigInteger) await reader.ReadValueAsync<BigInteger>(stream, false).ConfigureAwait(false);
+            var scale = (int) (await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false))!;
+            var unscaled = (BigInteger) (await reader.ReadNonNullableValueAsync<BigInteger>(stream).ConfigureAwait(false))!;
 
             return ConvertScaleAndUnscaledValue(scale, unscaled);
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigIntegerSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigIntegerSerializer.cs
index e781504..2c707a9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigIntegerSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BigIntegerSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Linq;
 using System.Numerics;
@@ -44,14 +46,14 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task WriteValueAsync(BigInteger value, Stream stream, GraphBinaryWriter writer)
         {
             var bytes = value.ToByteArray().Reverse().ToArray();
-            await writer.WriteValueAsync(bytes.Length, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(bytes.Length, stream).ConfigureAwait(false);
             await stream.WriteAsync(bytes).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
         protected override async Task<BigInteger> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var length = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
             var bytes = new byte[length];
             await stream.ReadAsync(bytes).ConfigureAwait(false);
             return new BigInteger(bytes.Reverse().ToArray());
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BindingSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BindingSerializer.cs
index 1cb5d9a..825576c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BindingSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BindingSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 using Gremlin.Net.Process.Traversal;
@@ -42,14 +44,14 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(Binding value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Key, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Key, stream).ConfigureAwait(false);
             await writer.WriteAsync(value.Value, stream).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
         protected override async Task<Binding> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var key = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+            var key = (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false);
             var value = await reader.ReadAsync(stream).ConfigureAwait(false);
             return new Binding(key, value);
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BulkSetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BulkSetSerializer.cs
index 862c2c7..ecf5a75 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BulkSetSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/BulkSetSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.Collections;
 using System.IO;
 using System.Threading.Tasks;
@@ -53,13 +55,13 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task<TList> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var length = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
 
             var result = new TList();
             for (var i = 0; i < length; i++)
             {
                 var value = await reader.ReadAsync(stream).ConfigureAwait(false);
-                var bulk = (long) await reader.ReadValueAsync<long>(stream, false).ConfigureAwait(false);
+                var bulk = (long) await reader.ReadNonNullableValueAsync<long>(stream).ConfigureAwait(false);
                 for (var j = 0; j < bulk; j++)
                 {
                     result.Add(value);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteBufferSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteBufferSerializer.cs
index 0e3bf1d..9c94afe 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteBufferSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteBufferSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 
@@ -42,14 +44,14 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(byte[] value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Length, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Length, stream).ConfigureAwait(false);
             await stream.WriteAsync(value, 0, value.Length).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
         protected override async Task<byte[]> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var length = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
             var buffer = new byte[length];
             await stream.ReadAsync(buffer, 0, length).ConfigureAwait(false);
             return buffer;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteCodeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteCodeSerializer.cs
index bc59b4b..55a0e59 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteCodeSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ByteCodeSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.Collections.Generic;
 using System.IO;
 using System.Threading.Tasks;
@@ -50,18 +52,18 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         private static async Task WriteInstructionsAsync(IReadOnlyCollection<Instruction> instructions, Stream stream,
             GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(instructions.Count, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(instructions.Count, stream).ConfigureAwait(false);
 
             foreach (var instruction in instructions)
             {
-                await writer.WriteValueAsync(instruction.OperatorName, stream, false).ConfigureAwait(false);
+                await writer.WriteNonNullableValueAsync(instruction.OperatorName, stream).ConfigureAwait(false);
                 await WriteArgumentsAsync(instruction.Arguments, stream, writer).ConfigureAwait(false);
             }
         }
 
-        private static async Task WriteArgumentsAsync(object[] arguments, Stream stream, GraphBinaryWriter writer)
+        private static async Task WriteArgumentsAsync(object?[] arguments, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(arguments.Length, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(arguments.Length, stream).ConfigureAwait(false);
 
             foreach (var value in arguments)
             {
@@ -74,27 +76,27 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         {
             var result = new Bytecode();
 
-            var stepsLength = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var stepsLength = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
             for (var i = 0; i < stepsLength; i++)
             {
-                result.AddStep((string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+                result.AddStep((string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false),
                     await ReadArgumentsAsync(stream, reader).ConfigureAwait(false));
             }
             
             var sourcesLength = await stream.ReadIntAsync().ConfigureAwait(false);
             for (var i = 0; i < sourcesLength; i++)
             {
-                result.AddSource((string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+                result.AddSource((string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false),
                     await ReadArgumentsAsync(stream, reader).ConfigureAwait(false));
             }
             
             return result;
         }
 
-        private static async Task<object[]> ReadArgumentsAsync(Stream stream, GraphBinaryReader reader)
+        private static async Task<object?[]> ReadArgumentsAsync(Stream stream, GraphBinaryReader reader)
         {
-            var valuesLength = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
-            var values = new object[valuesLength];
+            var valuesLength = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
+            var values = new object?[valuesLength];
             for (var i = 0; i < valuesLength; i++)
             {
                 values[i] = await reader.ReadAsync(stream).ConfigureAwait(false);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/CharSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/CharSerializer.cs
index 3c456cd..ac735bf 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/CharSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/CharSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Text;
 using System.Threading.Tasks;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ClassSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ClassSerializer.cs
index 721c7fe..b27044f 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ClassSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ClassSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Threading.Tasks;
@@ -43,7 +45,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(GremlinType value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Fqcn, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Fqcn, stream).ConfigureAwait(false);
         }
 
         
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs
index 52ffae3..1234c56 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Threading.Tasks;
@@ -36,13 +38,12 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <summary>
         /// A serializer for the GraphBinary type Date, represented as <see cref="DateTimeOffset"/> in .NET.
         /// </summary>
-        public static readonly DateTimeOffsetSerializer DateSerializer = new DateTimeOffsetSerializer(DataType.Date);
+        public static readonly DateTimeOffsetSerializer DateSerializer = new(DataType.Date);
 
         /// <summary>
         /// A serializer for the GraphBinary type Timestamp, represented as <see cref="DateTimeOffset"/> in .NET.
         /// </summary>
-        public static readonly DateTimeOffsetSerializer TimestampSerializer =
-            new DateTimeOffsetSerializer(DataType.Timestamp);
+        public static readonly DateTimeOffsetSerializer TimestampSerializer = new(DataType.Timestamp);
         
         private DateTimeOffsetSerializer(DataType dataType) : base(dataType)
         {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DurationSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DurationSerializer.cs
index 89e669d..c4b4c27 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DurationSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DurationSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Threading.Tasks;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EdgeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EdgeSerializer.cs
index 81e925c..df1c887 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EdgeSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EdgeSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 
@@ -42,12 +44,12 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task WriteValueAsync(Edge value, Stream stream, GraphBinaryWriter writer)
         {
             await writer.WriteAsync(value.Id, stream).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Label, stream).ConfigureAwait(false);
             
             await writer.WriteAsync(value.InV.Id, stream).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.InV.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.InV.Label, stream).ConfigureAwait(false);
             await writer.WriteAsync(value.OutV.Id, stream).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.OutV.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.OutV.Label, stream).ConfigureAwait(false);
 
             // Placeholder for the parent vertex
             await writer.WriteAsync(null, stream).ConfigureAwait(false);
@@ -60,12 +62,12 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task<Edge> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
             var id = await reader.ReadAsync(stream).ConfigureAwait(false);
-            var label = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+            var label = (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false);
 
             var inV = new Vertex(await reader.ReadAsync(stream).ConfigureAwait(false),
-                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false));
+                (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false));
             var outV = new Vertex(await reader.ReadAsync(stream).ConfigureAwait(false),
-                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false));
+                (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false));
             
             // discard possible parent vertex
             await reader.ReadAsync(stream).ConfigureAwait(false);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs
index d561c2a..8ce23a9 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Threading.Tasks;
@@ -36,62 +38,55 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <summary>
         /// A serializer for <see cref="Barrier"/> values.
         /// </summary>
-        public static readonly EnumSerializer<Barrier> BarrierSerializer =
-            new EnumSerializer<Barrier>(DataType.Barrier, Barrier.GetByValue);
+        public static readonly EnumSerializer<Barrier> BarrierSerializer = new(DataType.Barrier, Barrier.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Cardinality"/> values.
         /// </summary>
         public static readonly EnumSerializer<Cardinality> CardinalitySerializer =
-            new EnumSerializer<Cardinality>(DataType.Cardinality, Cardinality.GetByValue);
+            new(DataType.Cardinality, Cardinality.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Column"/> values.
         /// </summary>
-        public static readonly EnumSerializer<Column> ColumnSerializer =
-            new EnumSerializer<Column>(DataType.Column, Column.GetByValue);
+        public static readonly EnumSerializer<Column> ColumnSerializer = new(DataType.Column, Column.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Direction"/> values.
         /// </summary>
         public static readonly EnumSerializer<Direction> DirectionSerializer =
-            new EnumSerializer<Direction>(DataType.Direction, Direction.GetByValue);
+            new(DataType.Direction, Direction.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Operator"/> values.
         /// </summary>
-        public static readonly EnumSerializer<Operator> OperatorSerializer =
-            new EnumSerializer<Operator>(DataType.Operator, Operator.GetByValue);
+        public static readonly EnumSerializer<Operator>
+            OperatorSerializer = new(DataType.Operator, Operator.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Order"/> values.
         /// </summary>
-        public static readonly EnumSerializer<Order> OrderSerializer =
-            new EnumSerializer<Order>(DataType.Order, Order.GetByValue);
+        public static readonly EnumSerializer<Order> OrderSerializer = new(DataType.Order, Order.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Pick"/> values.
         /// </summary>
-        public static readonly EnumSerializer<Pick> PickSerializer =
-            new EnumSerializer<Pick>(DataType.Pick, Pick.GetByValue);
+        public static readonly EnumSerializer<Pick> PickSerializer = new(DataType.Pick, Pick.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Pop"/> values.
         /// </summary>
-        public static readonly EnumSerializer<Pop> PopSerializer =
-            new EnumSerializer<Pop>(DataType.Pop, Pop.GetByValue);
+        public static readonly EnumSerializer<Pop> PopSerializer = new(DataType.Pop, Pop.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="Scope"/> values.
         /// </summary>
-        public static readonly EnumSerializer<Scope> ScopeSerializer =
-            new EnumSerializer<Scope>(DataType.Scope, Scope.GetByValue);
+        public static readonly EnumSerializer<Scope> ScopeSerializer = new(DataType.Scope, Scope.GetByValue);
 
         /// <summary>
         /// A serializer for <see cref="T"/> values.
         /// </summary>
-        public static readonly EnumSerializer<T> TSerializer =
-            new EnumSerializer<T>(DataType.T, T.GetByValue);
+        public static readonly EnumSerializer<T> TSerializer = new(DataType.T, T.GetByValue);
     }
 
     /// <summary>
@@ -117,7 +112,10 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task<TEnum> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var enumValue = (string) await reader.ReadAsync(stream).ConfigureAwait(false);
+            // This should probably be `reader.ReadNonNullableValueAsync<string>(stream)` instead, but it's 
+            // the same in other GLVs and changing this would be a breaking change for the GraphBinary format.
+            var enumValue = (string?) await reader.ReadAsync(stream).ConfigureAwait(false);
+            if (enumValue == null) throw new IOException($"Read null as a value for {DataType}");
             return _readFunc.Invoke(enumValue);
         }
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/GremlinType.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/GremlinType.cs
index 4484454..7b18cdd 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/GremlinType.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/GremlinType.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 namespace Gremlin.Net.Structure.IO.GraphBinary.Types
 {
     /// <summary>
@@ -43,7 +45,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// </summary>
         public static GremlinType FromFqcn(string fqcn)
         {
-            return new GremlinType(fqcn);
+            return new(fqcn);
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/LambdaSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/LambdaSerializer.cs
index b7f0683..d6eb670 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/LambdaSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/LambdaSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 using Gremlin.Net.Process.Traversal;
@@ -42,19 +44,19 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(ILambda value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Language, stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.LambdaExpression, stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.Arguments, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Language, stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.LambdaExpression, stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Arguments, stream).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
         protected override async Task<ILambda> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var language = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
-            var expression = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
+            var language = (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false);
+            var expression = (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false);
             
             // discard the arguments
-            await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
 
             return new StringBasedLambda(expression, language);
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ListSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ListSerializer.cs
index ad374e9..eb6c577 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ListSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/ListSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.Collections.Generic;
 using System.IO;
 using System.Threading.Tasks;
@@ -31,7 +33,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
     /// A generic list serializer.
     /// </summary>
     /// <typeparam name="TMember">The type of elements in the list.</typeparam>
-    public class ListSerializer<TMember> : SimpleTypeSerializer<IList<TMember>>
+    public class ListSerializer<TMember> : SimpleTypeSerializer<IList<TMember?>>
     {
         /// <summary>
         ///     Initializes a new instance of the <see cref="ListSerializer{TList}" /> class.
@@ -41,9 +43,9 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         }
 
         /// <inheritdoc />
-        protected override async Task WriteValueAsync(IList<TMember> value, Stream stream, GraphBinaryWriter writer)
+        protected override async Task WriteValueAsync(IList<TMember?> value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Count, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Count, stream).ConfigureAwait(false);
             
             foreach (var item in value)
             {
@@ -52,13 +54,13 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         }
 
         /// <inheritdoc />
-        protected override async Task<IList<TMember>> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        protected override async Task<IList<TMember?>> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
-            var result = new List<TMember>(length);
+            var length = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
+            var result = new List<TMember?>(length);
             for (var i = 0; i < length; i++)
             {
-                result.Add((TMember) await reader.ReadAsync(stream).ConfigureAwait(false));
+                result.Add((TMember?) await reader.ReadAsync(stream).ConfigureAwait(false));
             }
 
             return result;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/MapSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/MapSerializer.cs
index 60c7e4a..770c115 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/MapSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/MapSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.Collections.Generic;
 using System.IO;
 using System.Threading.Tasks;
@@ -32,7 +34,8 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
     /// </summary>
     /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
     /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
-    public class MapSerializer<TKey, TValue> : SimpleTypeSerializer<IDictionary<TKey, TValue>>
+    public class MapSerializer<TKey, TValue> : SimpleTypeSerializer<IDictionary<TKey, TValue?>>
+        where TKey : notnull
     {
         /// <summary>
         ///     Initializes a new instance of the <see cref="MapSerializer{TKey, TValue}" /> class.
@@ -42,9 +45,9 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         }
 
         /// <inheritdoc />
-        protected override async Task WriteValueAsync(IDictionary<TKey, TValue> value, Stream stream, GraphBinaryWriter writer)
+        protected override async Task WriteValueAsync(IDictionary<TKey, TValue?> value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Count, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Count, stream).ConfigureAwait(false);
 
             foreach (var key in value.Keys)
             {
@@ -54,15 +57,16 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         }
 
         /// <inheritdoc />
-        protected override async Task<IDictionary<TKey, TValue>> ReadValueAsync(Stream stream, GraphBinaryReader reader)
+        protected override async Task<IDictionary<TKey, TValue?>> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
             var length = await stream.ReadIntAsync().ConfigureAwait(false);
-            var result = new Dictionary<TKey, TValue>(length);
+            var result = new Dictionary<TKey, TValue?>(length);
             
             for (var i = 0; i < length; i++)
             {
-                var key = (TKey) await reader.ReadAsync(stream).ConfigureAwait(false);
-                var value = (TValue) await reader.ReadAsync(stream).ConfigureAwait(false);
+                var key = (TKey?) await reader.ReadAsync(stream).ConfigureAwait(false);
+                if (key == null) throw new IOException("Read null as the key for a dictionary.");
+                var value = (TValue?) await reader.ReadAsync(stream).ConfigureAwait(false);
                 result.Add(key, value);
             }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PSerializer.cs
index 194d3f7..11ad1d6 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PSerializer.cs
@@ -48,8 +48,8 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
 
             var argsLength = value.Other == null ? args.Count : args.Count + 1;
             
-            await writer.WriteValueAsync(value.OperatorName, stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(argsLength, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.OperatorName, stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(argsLength, stream).ConfigureAwait(false);
 
             foreach (var arg in args)
             {
@@ -65,8 +65,8 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task<P> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var operatorName = (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false);
-            var argsLength = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var operatorName = (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false);
+            var argsLength = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
 
             var args = new object[argsLength];
             for (var i = 0; i < argsLength; i++)
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PropertySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PropertySerializer.cs
index cb7f5ed..89bac10 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PropertySerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/PropertySerializer.cs
@@ -41,7 +41,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(Property value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Key, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Key, stream).ConfigureAwait(false);
             await writer.WriteAsync(value.Value, stream).ConfigureAwait(false);
             
             // placeholder for the parent element
@@ -51,7 +51,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task<Property> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var p = new Property((string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+            var p = new Property((string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false),
                 await reader.ReadAsync(stream).ConfigureAwait(false));
 
             // discard parent element
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SetSerializer.cs
index ae4a366..b6c6337 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SetSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SetSerializer.cs
@@ -50,7 +50,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
             var enumerable = (IEnumerable) value;
             var list = enumerable.Cast<object>().ToList();
 
-            await writer.WriteValueAsync(list.Count, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(list.Count, stream).ConfigureAwait(false);
             
             foreach (var item in list)
             {
@@ -61,7 +61,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task<TSet> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var length = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
             var result = new TSet();
             for (var i = 0; i < length; i++)
             {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SimpleTypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SimpleTypeSerializer.cs
index 498566b..0499ce0 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SimpleTypeSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SimpleTypeSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System.IO;
 using System.Threading.Tasks;
 
@@ -45,30 +47,27 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         public DataType DataType { get; }
 
         /// <inheritdoc />
-        public async Task WriteAsync(object value, Stream stream, GraphBinaryWriter writer)
+        public async Task WriteAsync(object? value, Stream stream, GraphBinaryWriter writer)
         {
-            await WriteValueAsync((T) value, stream, writer, true).ConfigureAwait(false);
+            await WriteNullableValueAsync((T?) value, stream, writer).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
-        public async Task WriteValueAsync(object value, Stream stream, GraphBinaryWriter writer, bool nullable)
+        public async Task WriteNullableValueAsync(object? value, Stream stream, GraphBinaryWriter writer)
         {
             if (value == null)
             {
-                if (!nullable)
-                {
-                    throw new IOException("Unexpected null value when nullable is false");
-                }
-
                 await writer.WriteValueFlagNullAsync(stream).ConfigureAwait(false);
                 return;
             }
 
-            if (nullable)
-            {
-                await writer.WriteValueFlagNoneAsync(stream).ConfigureAwait(false);
-            }
-
+            await writer.WriteValueFlagNoneAsync(stream).ConfigureAwait(false);
+            await WriteValueAsync((T) value, stream, writer).ConfigureAwait(false);
+        }
+        
+        /// <inheritdoc />
+        public async Task WriteNonNullableValueAsync(object value, Stream stream, GraphBinaryWriter writer)
+        {
             await WriteValueAsync((T) value, stream, writer).ConfigureAwait(false);
         }
 
@@ -82,25 +81,28 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected abstract Task WriteValueAsync(T value, Stream stream, GraphBinaryWriter writer);
 
         /// <inheritdoc />
-        public async Task<object> ReadAsync(Stream stream, GraphBinaryReader reader)
+        public async Task<object?> ReadAsync(Stream stream, GraphBinaryReader reader)
         {
-            return await ReadValueAsync(stream, reader, true).ConfigureAwait(false);
+            return await ReadNullableValueAsync(stream, reader).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
-        public async Task<object> ReadValueAsync(Stream stream, GraphBinaryReader reader, bool nullable)
+        public async Task<object?> ReadNullableValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            if (nullable)
+            var valueFlag = await stream.ReadByteAsync().ConfigureAwait(false);
+            if ((valueFlag & 1) == 1)
             {
-                var valueFlag = await stream.ReadByteAsync().ConfigureAwait(false);
-                if ((valueFlag & 1) == 1)
-                {
-                    return null;
-                }
+                return null;
             }
 
             return await ReadValueAsync(stream, reader).ConfigureAwait(false);
         }
+        
+        /// <inheritdoc />
+        public async Task<object> ReadNonNullableValueAsync(Stream stream, GraphBinaryReader reader)
+        {
+            return (await ReadValueAsync(stream, reader).ConfigureAwait(false))!;
+        }
 
         /// <summary>
         /// Reads a non-nullable value according to the type format.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SingleTypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SingleTypeSerializer.cs
index c2c9f58..3d07092 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SingleTypeSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/SingleTypeSerializer.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.IO;
 using System.Threading.Tasks;
@@ -36,48 +38,44 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <summary>
         /// A serializer for <see cref="int"/> values.
         /// </summary>
-        public static readonly SingleTypeSerializer<int> IntSerializer = new SingleTypeSerializer<int>(DataType.Int,
-            (value, stream) => stream.WriteIntAsync(value), stream => stream.ReadIntAsync());
-        
+        public static readonly SingleTypeSerializer<int> IntSerializer =
+            new(DataType.Int, (value, stream) => stream.WriteIntAsync(value), stream => stream.ReadIntAsync());
+
         /// <summary>
         /// A serializer for <see cref="long"/> values.
         /// </summary>
-        public static readonly SingleTypeSerializer<long> LongSerializer = new SingleTypeSerializer<long>(DataType.Long,
-            (value, stream) => stream.WriteLongAsync(value), stream => stream.ReadLongAsync());
+        public static readonly SingleTypeSerializer<long> LongSerializer =
+            new(DataType.Long, (value, stream) => stream.WriteLongAsync(value), stream => stream.ReadLongAsync());
 
         /// <summary>
         /// A serializer for <see cref="double"/> values.
         /// </summary>
         public static readonly SingleTypeSerializer<double> DoubleSerializer =
-            new SingleTypeSerializer<double>(DataType.Double, (value, stream) => stream.WriteDoubleAsync(value),
-                stream => stream.ReadDoubleAsync());
+            new(DataType.Double, (value, stream) => stream.WriteDoubleAsync(value), stream => stream.ReadDoubleAsync());
 
         /// <summary>
         /// A serializer for <see cref="float"/> values.
         /// </summary>
         public static readonly SingleTypeSerializer<float> FloatSerializer =
-            new SingleTypeSerializer<float>(DataType.Float, (value, stream) => stream.WriteFloatAsync(value),
-                stream => stream.ReadFloatAsync());
+            new(DataType.Float, (value, stream) => stream.WriteFloatAsync(value), stream => stream.ReadFloatAsync());
 
         /// <summary>
         /// A serializer for <see cref="short"/> values.
         /// </summary>
         public static readonly SingleTypeSerializer<short> ShortSerializer =
-            new SingleTypeSerializer<short>(DataType.Short, (value, stream) => stream.WriteShortAsync(value),
-                stream => stream.ReadShortAsync());
+            new(DataType.Short, (value, stream) => stream.WriteShortAsync(value), stream => stream.ReadShortAsync());
 
         /// <summary>
         /// A serializer for <see cref="bool"/> values.
         /// </summary>
         public static readonly SingleTypeSerializer<bool> BooleanSerializer =
-            new SingleTypeSerializer<bool>(DataType.Boolean, (value, stream) => stream.WriteBoolAsync(value),
-                stream => stream.ReadBoolAsync());
+            new(DataType.Boolean, (value, stream) => stream.WriteBoolAsync(value), stream => stream.ReadBoolAsync());
 
         /// <summary>
         /// A serializer for <see cref="byte"/> values.
         /// </summary>
-        public static readonly SingleTypeSerializer<byte> ByteSerializer = new SingleTypeSerializer<byte>(DataType.Byte,
-            (value, stream) => stream.WriteByteAsync(value), stream => stream.ReadByteAsync());
+        public static readonly SingleTypeSerializer<byte> ByteSerializer =
+            new(DataType.Byte, (value, stream) => stream.WriteByteAsync(value), stream => stream.ReadByteAsync());
     }
     
     /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/StringSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/StringSerializer.cs
index c8d8dca..072ffa1 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/StringSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/StringSerializer.cs
@@ -43,14 +43,14 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task WriteValueAsync(string value, Stream stream, GraphBinaryWriter writer)
         {
             var bytes = Encoding.UTF8.GetBytes(value);
-            await writer.WriteValueAsync(bytes.Length, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(bytes.Length, stream).ConfigureAwait(false);
             await stream.WriteAsync(bytes).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
         protected override async Task<string> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var length = (int) await reader.ReadValueAsync<int>(stream, false).ConfigureAwait(false);
+            var length = (int) await reader.ReadNonNullableValueAsync<int>(stream).ConfigureAwait(false);
             var bytes = new byte[length];
             await stream.ReadAsync(bytes, 0, length).ConfigureAwait(false);
             return Encoding.UTF8.GetString(bytes);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalSerializer.cs
index d6fe159..dadc7b0 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalSerializer.cs
@@ -43,7 +43,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(ITraversal value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Bytecode, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Bytecode, stream).ConfigureAwait(false);
         }
 
         /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalStrategySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalStrategySerializer.cs
index af6e792..6d66136 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalStrategySerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraversalStrategySerializer.cs
@@ -44,8 +44,8 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task WriteValueAsync(AbstractTraversalStrategy value, Stream stream,
             GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(GremlinType.FromFqcn(value.Fqcn), stream, false).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.Configuration, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(GremlinType.FromFqcn(value.Fqcn), stream).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Configuration, stream).ConfigureAwait(false);
         }
 
         /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraverserSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraverserSerializer.cs
index 8318813..2d24d4c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraverserSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TraverserSerializer.cs
@@ -42,14 +42,14 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         /// <inheritdoc />
         protected override async Task WriteValueAsync(Traverser value, Stream stream, GraphBinaryWriter writer)
         {
-            await writer.WriteValueAsync(value.Bulk, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Bulk, stream).ConfigureAwait(false);
             await writer.WriteAsync(value.Object, stream).ConfigureAwait(false);
         }
 
         /// <inheritdoc />
         protected override async Task<Traverser> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
-            var bulk = (long) await reader.ReadValueAsync<long>(stream, false).ConfigureAwait(false);
+            var bulk = (long) await reader.ReadNonNullableValueAsync<long>(stream).ConfigureAwait(false);
             var v = await reader.ReadAsync(stream).ConfigureAwait(false);
             return new Traverser(v, bulk);
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TypeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TypeSerializer.cs
index 7723942..cae6f08 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TypeSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/TypeSerializer.cs
@@ -47,7 +47,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
             if (typeof(AbstractTraversalStrategy).IsAssignableFrom(value))
             {
                 var strategyInstance = (AbstractTraversalStrategy) Activator.CreateInstance(value);
-                await writer.WriteValueAsync(strategyInstance.Fqcn, stream, false).ConfigureAwait(false);
+                await writer.WriteNonNullableValueAsync(strategyInstance.Fqcn, stream).ConfigureAwait(false);
             }
             else
             {
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexPropertySerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexPropertySerializer.cs
index f14cfd8..27ab4b2 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexPropertySerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexPropertySerializer.cs
@@ -42,7 +42,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task WriteValueAsync(VertexProperty value, Stream stream, GraphBinaryWriter writer)
         {
             await writer.WriteAsync(value.Id, stream).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Label, stream).ConfigureAwait(false);
             await writer.WriteAsync(value.Value, stream).ConfigureAwait(false);
             
             // placeholder for the parent vertex
@@ -57,7 +57,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task<VertexProperty> ReadValueAsync(Stream stream, GraphBinaryReader reader)
         {
             var vp = new VertexProperty(await reader.ReadAsync(stream).ConfigureAwait(false),
-                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false),
+                (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false),
                 await reader.ReadAsync(stream).ConfigureAwait(false));
 
             // discard the parent vertex
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexSerializer.cs
index f4fc704..3a745ab 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/VertexSerializer.cs
@@ -42,7 +42,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         protected override async Task WriteValueAsync(Vertex value, Stream stream, GraphBinaryWriter writer)
         {
             await writer.WriteAsync(value.Id, stream).ConfigureAwait(false);
-            await writer.WriteValueAsync(value.Label, stream, false).ConfigureAwait(false);
+            await writer.WriteNonNullableValueAsync(value.Label, stream).ConfigureAwait(false);
             await writer.WriteAsync(null, stream).ConfigureAwait(false);
         }
 
@@ -51,7 +51,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
         {
 
             var v = new Vertex(await reader.ReadAsync(stream).ConfigureAwait(false),
-                (string) await reader.ReadValueAsync<string>(stream, false).ConfigureAwait(false));
+                (string) await reader.ReadNonNullableValueAsync<string>(stream).ConfigureAwait(false));
             
             // discard properties
             await reader.ReadAsync(stream).ConfigureAwait(false);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
index c615c7c..c439a58 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/SerializationTokens.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 namespace Gremlin.Net.Structure.IO
 {
     /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Path.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/Path.cs
index d205a88..e60c1bd 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Path.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Path.cs
@@ -21,9 +21,12 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Gremlin.Net.Process.Traversal;
 
@@ -70,15 +73,15 @@ namespace Gremlin.Net.Structure
         {
             get
             {
-                var objFound = TryGetValue(label, out object obj);
+                var objFound = TryGetValue(label, out var obj);
                 if (!objFound)
                     throw new KeyNotFoundException($"The step with label {label} does not exist");
-                return obj;
+                return obj!;
             }
         }
 
         /// <inheritdoc />
-        public bool Equals(Path other)
+        public bool Equals(Path? other)
         {
             if (ReferenceEquals(null, other)) return false;
             if (ReferenceEquals(this, other)) return true;
@@ -131,7 +134,7 @@ namespace Gremlin.Net.Structure
         /// <param name="label">The label of the path.</param>
         /// <param name="value">The object associated with the label of the path.</param>
         /// <returns>True, if an object was found for the label.</returns>
-        public bool TryGetValue(string label, out object value)
+        public bool TryGetValue(string label, [NotNullWhen(true)] out object? value)
         {
             value = null;
             for (var i = 0; i < Labels.Count; i++)
@@ -149,33 +152,28 @@ namespace Gremlin.Net.Structure
 
         private bool ObjectsEqual(ICollection<object> otherObjects)
         {
-            if (Objects == null)
-                return otherObjects == null;
             return Objects.SequenceEqual(otherObjects);
         }
 
         private bool LabelsEqual(ICollection<ISet<string>> otherLabels)
         {
-            if (Labels == null)
-                return otherLabels == null;
             if (Labels.Count != otherLabels.Count)
                 return false;
-            using (var enumOther = otherLabels.GetEnumerator())
-            using (var enumThis = Labels.GetEnumerator())
+            using var enumOther = otherLabels.GetEnumerator();
+            using var enumThis = Labels.GetEnumerator();
+            while (enumOther.MoveNext() && enumThis.MoveNext())
             {
-                while (enumOther.MoveNext() && enumThis.MoveNext())
+                if (!enumOther.Current.SequenceEqual(enumThis.Current))
                 {
-                    if (!enumOther.Current.SequenceEqual(enumThis.Current))
-                    {
-                        return false;
-                    }
+                    return false;
                 }
             }
+
             return true;
         }
 
         /// <inheritdoc />
-        public override bool Equals(object obj)
+        public override bool Equals(object? obj)
         {
             if (ReferenceEquals(null, obj)) return false;
             if (ReferenceEquals(this, obj)) return true;
@@ -189,13 +187,10 @@ namespace Gremlin.Net.Structure
             unchecked
             {
                 var hashCode = 19;
-                if (Labels != null)
-                    hashCode = Labels.Where(objLabels => objLabels != null)
-                        .Aggregate(hashCode,
-                            (current1, objLabels) => objLabels.Aggregate(current1,
-                                (current, label) => current * 31 + label.GetHashCode()));
-                if (Objects != null)
-                    hashCode = Objects.Aggregate(hashCode, (current, obj) => current * 31 + obj.GetHashCode());
+                hashCode = Labels.Aggregate(hashCode,
+                        (current1, objLabels) => objLabels.Aggregate(current1,
+                            (current, label) => current * 31 + label.GetHashCode()));
+                hashCode = Objects.Aggregate(hashCode, (current, obj) => current * 31 + obj.GetHashCode());
                 return hashCode;
             }
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs
index b2adee7..44b46ef 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Property.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 using System;
 
 namespace Gremlin.Net.Structure
@@ -36,7 +38,7 @@ namespace Gremlin.Net.Structure
         /// <param name="key">The key of the property.</param>
         /// <param name="value">The value of the property.</param>
         /// <param name="element">The (optional) element that the property is associated with.</param>
-        public Property(string key, dynamic value, Element element = null)
+        public Property(string key, dynamic value, Element? element = null)
         {
             Key = key;
             Value = value;
@@ -56,10 +58,10 @@ namespace Gremlin.Net.Structure
         /// <summary>
         ///     Gets the element that this property is associated with.
         /// </summary>
-        public Element Element { get; }
+        public Element? Element { get; }
 
         /// <inheritdoc />
-        public bool Equals(Property other)
+        public bool Equals(Property? other)
         {
             if (ReferenceEquals(null, other)) return false;
             if (ReferenceEquals(this, other)) return true;
@@ -73,7 +75,7 @@ namespace Gremlin.Net.Structure
         }
 
         /// <inheritdoc />
-        public override bool Equals(object obj)
+        public override bool Equals(object? obj)
         {
             if (ReferenceEquals(null, obj)) return false;
             if (ReferenceEquals(this, obj)) return true;
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/Vertex.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/Vertex.cs
index f667d26..cf3dab4 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/Vertex.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/Vertex.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 namespace Gremlin.Net.Structure
 {
     /// <summary>
@@ -38,7 +40,7 @@ namespace Gremlin.Net.Structure
         /// </summary>
         /// <param name="id">The id of the vertex.</param>
         /// <param name="label">The label of the vertex.</param>
-        public Vertex(object id, string label = DefaultLabel)
+        public Vertex(object? id, string label = DefaultLabel)
             : base(id, label)
         {
         }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs
index a8dd943..06c50ff 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/VertexProperty.cs
@@ -21,6 +21,8 @@
 
 #endregion
 
+#nullable enable warnings
+
 namespace Gremlin.Net.Structure
 {
     /// <summary>
@@ -35,7 +37,7 @@ namespace Gremlin.Net.Structure
         /// <param name="label">The label of the vertex property.</param>
         /// <param name="value">The id of the vertex property.</param>
         /// <param name="vertex">The (optional) <see cref="Vertex" /> that owns this <see cref="VertexProperty" />.</param>
-        public VertexProperty(object id, string label, dynamic value, Vertex vertex = null)
+        public VertexProperty(object id, string label, dynamic value, Vertex? vertex = null)
             : base(id, label)
         {
             Value = value;
@@ -50,7 +52,7 @@ namespace Gremlin.Net.Structure
         /// <summary>
         ///     The <see cref="Vertex" /> that owns this <see cref="VertexProperty" />.
         /// </summary>
-        public Vertex Vertex { get; }
+        public Vertex? Vertex { get; }
 
         /// <summary>
         ///     The key of this <see cref="VertexProperty" />.
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs
index 6df92ba..72b4c90 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/PathTests.cs
@@ -408,7 +408,7 @@ namespace Gremlin.Net.UnitTest.Structure
         {
             var path = new Path(new List<ISet<string>>(), new List<object>());
 
-            var success = path.TryGetValue("unknownKey", out object _);
+            var success = path.TryGetValue("unknownKey", out _);
 
             Assert.False(success);
         }