faster initialization of ParserInternalState
diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
index 3235cca..4c9234d 100644
--- a/csharp/src/Google.Protobuf/CodedInputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -143,7 +143,7 @@
             this.state.bufferSize = bufferSize;

             this.state.sizeLimit = DefaultSizeLimit;

             this.state.recursionLimit = DefaultRecursionLimit;

-            this.state.segmentedBufferHelper = new SegmentedBufferHelper(this);

+            SegmentedBufferHelper.Initialize(this, out this.state.segmentedBufferHelper);

             this.state.codedInputStream = this;

             this.leaveOpen = leaveOpen;

 

diff --git a/csharp/src/Google.Protobuf/ParseContext.cs b/csharp/src/Google.Protobuf/ParseContext.cs
index 4d0c140..6c74e73 100644
--- a/csharp/src/Google.Protobuf/ParseContext.cs
+++ b/csharp/src/Google.Protobuf/ParseContext.cs
@@ -89,7 +89,7 @@
             this.state.sizeLimit = DefaultSizeLimit;
             this.state.recursionLimit = recursionLimit;
             this.state.currentLimit = int.MaxValue;
-            this.state.segmentedBufferHelper = new SegmentedBufferHelper(input, out this.buffer);
+            SegmentedBufferHelper.Initialize(input, out this.state.segmentedBufferHelper, out this.buffer);
             this.state.bufferPos = 0;
             this.state.bufferSize = this.buffer.Length;
             this.state.codedInputStream = null;
diff --git a/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs b/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs
index 2c9db88..a8a7562 100644
--- a/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs
+++ b/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs
@@ -43,18 +43,37 @@
     /// </summary>
     internal struct SegmentedBufferHelper
     {
-        private readonly int? totalLength;
+        private int? totalLength;
         private ReadOnlySequence<byte>.Enumerator readOnlySequenceEnumerator;
-        private readonly CodedInputStream codedInputStream;
+        private CodedInputStream codedInputStream;
 
-        public SegmentedBufferHelper(ReadOnlySequence<byte> sequence, out ReadOnlySpan<byte> firstSpan)
+        /// <summary>
+        /// Initialize an instance with a coded input stream.
+        /// This approach is faster than using a constructor because the instance to initialize is passed by reference
+        /// and we can write directly into it without copying.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void Initialize(CodedInputStream codedInputStream, out SegmentedBufferHelper instance)
         {
-            this.codedInputStream = null;
+            instance.totalLength = codedInputStream.InternalInputStream == null ? (int?)codedInputStream.InternalBuffer.Length : null;
+            instance.readOnlySequenceEnumerator = default;
+            instance.codedInputStream = codedInputStream;
+        }
+
+        /// <summary>
+        /// Initialize an instance with a read only sequence.
+        /// This approach is faster than using a constructor because the instance to initialize is passed by reference
+        /// and we can write directly into it without copying.
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static void Initialize(ReadOnlySequence<byte> sequence, out SegmentedBufferHelper instance, out ReadOnlySpan<byte> firstSpan)
+        {
+            instance.codedInputStream = null;
             if (sequence.IsSingleSegment)
             {
                 firstSpan = sequence.First.Span;
-                this.totalLength = firstSpan.Length;
-                this.readOnlySequenceEnumerator = default;
+                instance.totalLength = firstSpan.Length;
+                instance.readOnlySequenceEnumerator = default;
             }
             else
             {
@@ -62,17 +81,10 @@
                 // very first read will result in slowpath (because the first thing to do is to
                 // refill to get the first buffer segment)
                 firstSpan = default;
-                this.totalLength = (int) sequence.Length;
-                this.readOnlySequenceEnumerator = sequence.GetEnumerator();
+                instance.totalLength = (int) sequence.Length;
+                instance.readOnlySequenceEnumerator = sequence.GetEnumerator();
             }
         }
-
-        public SegmentedBufferHelper(CodedInputStream codedInputStream)
-        {
-            this.totalLength = codedInputStream.InternalInputStream == null ? (int?)codedInputStream.InternalBuffer.Length : null;
-            this.readOnlySequenceEnumerator = default;
-            this.codedInputStream = codedInputStream;
-        }
         
         public bool RefillBuffer(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, bool mustSucceed)
         {