misc. netstd improvements
Client: netstd
Patch: Jens Geyer

This closes #2344
diff --git a/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj b/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj
index baef759..d55074f 100644
--- a/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj
+++ b/lib/netstd/Benchmarks/Thrift.Benchmarks/Thrift.Benchmarks.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <!--
     Licensed to the Apache Software Foundation(ASF) under one
     or more contributor license agreements.See the NOTICE file
@@ -20,8 +20,9 @@
   
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFrameworks>net5.0;net48</TargetFrameworks>
+    <TargetFramework>net5.0</TargetFramework>
     <TieredCompilation>false</TieredCompilation>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
index 28b7d29..9c23469 100644
--- a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
@@ -23,6 +23,9 @@
 using Thrift.Protocol.Entities;
 using Thrift.Transport;
 
+#pragma warning disable IDE0079 // unnecessary suppression
+#pragma warning disable IDE0066 // use switch expression
+
 namespace Thrift.Protocol
 {
     // ReSharper disable once InconsistentNaming
@@ -36,7 +39,7 @@
 
         // minimize memory allocations by means of an preallocated bytes buffer
         // The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
-        private byte[] PreAllocatedBuffer = new byte[128];
+        private readonly byte[] PreAllocatedBuffer = new byte[128];
 
         public TBinaryProtocol(TTransport trans)
             : this(trans, false, true)
@@ -442,7 +445,7 @@
                 case TType.Map: return sizeof(int);  // element count
                 case TType.Set: return sizeof(int);  // element count
                 case TType.List: return sizeof(int);  // element count
-                default: throw new TTransportException(TTransportException.ExceptionType.Unknown, "unrecognized type code");
+                default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
             }
         }
 
diff --git a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
index 066b327..3758174 100644
--- a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
@@ -26,9 +26,11 @@
 using Thrift.Protocol.Entities;
 using Thrift.Transport;
 
+#pragma warning disable IDE0079 // unnecessary suppression
+#pragma warning disable IDE0066 // use switch expression
+
 namespace Thrift.Protocol
 {
-    //TODO: implementation of TProtocol
 
     // ReSharper disable once InconsistentNaming
     public class TCompactProtocol : TProtocol
@@ -805,7 +807,7 @@
                 case TType.Map:     return sizeof(byte);  // element count
                 case TType.Set:    return sizeof(byte);  // element count
                 case TType.List:    return sizeof(byte);  // element count
-                default: throw new TTransportException(TTransportException.ExceptionType.Unknown, "unrecognized type code");
+                default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
             }
         }
 
diff --git a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
index 2f1ccdb..081f42e 100644
--- a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
@@ -27,6 +27,10 @@
 using Thrift.Protocol.Utilities;
 using Thrift.Transport;
 
+#pragma warning disable IDE0079 // unnecessary suppression
+#pragma warning disable IDE0063 // simplify using
+#pragma warning disable IDE0066 // use switch expression
+
 namespace Thrift.Protocol
 {
     /// <summary>
@@ -88,7 +92,7 @@
         ///    even in cases where the protocol instance was in an undefined state due to
         ///    dangling/stale/obsolete contexts
         /// </summary>
-        private void resetContext()
+        private void ResetContext()
         {
             ContextStack.Clear();
             Context = new JSONBaseContext(this);
@@ -277,7 +281,7 @@
 
         public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
         {
-            resetContext();
+            ResetContext();
             await WriteJsonArrayStartAsync(cancellationToken);
             await WriteJsonIntegerAsync(Version, cancellationToken);
 
@@ -430,7 +434,12 @@
                     // escaped?
                     if (ch != TJSONProtocolConstants.EscSequences[0])
                     {
+#if NETSTANDARD2_0
                         await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken);
+#else
+                        var wbuf = new[] { ch };
+                        await buffer.WriteAsync(wbuf.AsMemory(0, 1), cancellationToken);
+#endif
                         continue;
                     }
 
@@ -444,7 +453,12 @@
                             throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected control char");
                         }
                         ch = TJSONProtocolConstants.EscapeCharValues[off];
+#if NETSTANDARD2_0
                         await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken);
+#else
+                        var wbuf = new[] { ch };
+                        await buffer.WriteAsync( wbuf.AsMemory(0, 1), cancellationToken);
+#endif
                         continue;
                     }
 
@@ -473,13 +487,21 @@
 
                         codeunits.Add((char) wch);
                         var tmp = Utf8Encoding.GetBytes(codeunits.ToArray());
+#if NETSTANDARD2_0
                         await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken);
+#else
+                        await buffer.WriteAsync(tmp.AsMemory(0, tmp.Length), cancellationToken);
+#endif
                         codeunits.Clear();
                     }
                     else
                     {
-                        var tmp = Utf8Encoding.GetBytes(new[] {(char) wch});
+                        var tmp = Utf8Encoding.GetBytes(new[] { (char)wch });
+#if NETSTANDARD2_0
                         await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken);
+#else
+                        await buffer.WriteAsync(tmp.AsMemory( 0, tmp.Length), cancellationToken);
+#endif
                     }
                 }
 
@@ -655,7 +677,7 @@
         {
             var message = new TMessage();
 
-            resetContext();
+            ResetContext();
             await ReadJsonArrayStartAsync(cancellationToken);
             if (await ReadJsonIntegerAsync(cancellationToken) != Version)
             {
@@ -816,7 +838,7 @@
                 case TType.Map: return 2;  // empty map
                 case TType.Set: return 2;  // empty set
                 case TType.List: return 2;  // empty list
-                default: throw new TTransportException(TTransportException.ExceptionType.Unknown, "unrecognized type code");
+                default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
             }
         }
 
diff --git a/lib/netstd/Thrift/Transport/Client/THttpTransport.cs b/lib/netstd/Thrift/Transport/Client/THttpTransport.cs
index dcd028c..51f91ce 100644
--- a/lib/netstd/Thrift/Transport/Client/THttpTransport.cs
+++ b/lib/netstd/Thrift/Transport/Client/THttpTransport.cs
@@ -25,6 +25,9 @@
 using System.Threading;
 using System.Threading.Tasks;
 
+#pragma warning disable IDE0079 // unnecessary suppression
+#pragma warning disable IDE0063 // simplify using
+
 namespace Thrift.Transport.Client
 {
     // ReSharper disable once InconsistentNaming
@@ -33,7 +36,7 @@
         private readonly X509Certificate[] _certificates;
         private readonly Uri _uri;
 
-        private int _connectTimeout = 30000; // Timeouts in milliseconds
+        private readonly int _connectTimeout = 30000; // Timeouts in milliseconds
         private HttpClient _httpClient;
         private Stream _inputStream;
         private MemoryStream _outputStream = new MemoryStream();
@@ -133,10 +136,10 @@
 
             try
             {
-#if NETSTANDARD2_1
-                var ret = await _inputStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
-#else
+#if NETSTANDARD2_0
                 var ret = await _inputStream.ReadAsync(buffer, offset, length, cancellationToken);
+#else
+                var ret = await _inputStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
 #endif
                 if (ret == -1)
                 {
@@ -156,7 +159,11 @@
         {
             cancellationToken.ThrowIfCancellationRequested();
 
+#if NETSTANDARD2_0
             await _outputStream.WriteAsync(buffer, offset, length, cancellationToken);
+#else
+            await _outputStream.WriteAsync(buffer.AsMemory(offset, length), cancellationToken);
+#endif
         }
 
         /// <summary>
@@ -224,7 +231,11 @@
                     var response = (await _httpClient.PostAsync(_uri, contentStream, cancellationToken)).EnsureSuccessStatusCode();
 
                     _inputStream?.Dispose();
+#if NETSTANDARD2_0 || NETSTANDARD2_1
                     _inputStream = await response.Content.ReadAsStreamAsync();
+#else
+                    _inputStream = await response.Content.ReadAsStreamAsync(cancellationToken);
+#endif
                     if (_inputStream.CanSeek)
                     {
                         _inputStream.Seek(0, SeekOrigin.Begin);
diff --git a/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs b/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs
index 815983e..47d1ccb 100644
--- a/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs
+++ b/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs
@@ -72,10 +72,10 @@
             }
 
             CheckReadBytesAvailable(length);
-#if NETSTANDARD2_1
-            var numRead = await PipeStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
-#else
+#if NETSTANDARD2_0
             var numRead = await PipeStream.ReadAsync(buffer, offset, length, cancellationToken);
+#else
+            var numRead = await PipeStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
 #endif
             CountConsumedMessageBytes(numRead);
             return numRead;
@@ -94,7 +94,11 @@
             var nBytes = Math.Min(15 * 4096, length); // 16 would exceed the limit
             while (nBytes > 0)
             {
+#if NETSTANDARD2_0
                 await PipeStream.WriteAsync(buffer, offset, nBytes, cancellationToken);
+#else
+                await PipeStream.WriteAsync(buffer.AsMemory(offset, nBytes), cancellationToken);
+#endif
                 offset += nBytes;
                 length -= nBytes;
                 nBytes = Math.Min(nBytes, length);
diff --git a/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs b/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs
index b397460..90794c6 100644
--- a/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs
+++ b/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs
@@ -80,10 +80,10 @@
                     "Cannot read from null inputstream");
             }
 
-#if NETSTANDARD2_1
-            return await InputStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
-#else
+#if NETSTANDARD2_0
             return await InputStream.ReadAsync(buffer, offset, length, cancellationToken);
+#else
+            return await InputStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
 #endif
         }
 
@@ -95,7 +95,11 @@
                     "Cannot write to null outputstream");
             }
 
+#if NETSTANDARD2_0
             await OutputStream.WriteAsync(buffer, offset, length, cancellationToken);
+#else
+            await OutputStream.WriteAsync(buffer.AsMemory(offset, length), cancellationToken);
+#endif
         }
 
         public override async Task FlushAsync(CancellationToken cancellationToken)
diff --git a/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs b/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs
index 5698776..67ba29f 100644
--- a/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs
+++ b/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs
@@ -279,12 +279,10 @@
                 }
 
                 CheckReadBytesAvailable(length);
-#if NET5_0
-                var numBytes = await PipeStream.ReadAsync(buffer.AsMemory(offset, length), cancellationToken);
-#elif NETSTANDARD2_1
-                var numBytes = await PipeStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
-#else
+#if NETSTANDARD2_0
                 var numBytes = await PipeStream.ReadAsync(buffer, offset, length, cancellationToken);
+#else
+                var numBytes = await PipeStream.ReadAsync(buffer.AsMemory(offset, length), cancellationToken);
 #endif
                 CountConsumedMessageBytes(numBytes);
                 return numBytes;