C#: Optimize parsing of some primitive and wrapper types
diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs
index ebd00b7..7689964 100644
--- a/csharp/src/Google.Protobuf/FieldCodec.cs
+++ b/csharp/src/Google.Protobuf/FieldCodec.cs
@@ -507,7 +507,7 @@
         {
             var nestedCodec = WrapperCodecs.GetCodec<T>();
             return new FieldCodec<T?>(
-                input => WrapperCodecs.Read<T>(input, nestedCodec),
+                WrapperCodecs.GetReader<T>(),
                 (output, value) => WrapperCodecs.Write<T>(output, value.Value, nestedCodec),
                 (CodedInputStream i, ref T? v) => v = WrapperCodecs.Read<T>(i, nestedCodec),
                 (ref T? v, T? v2) => { if (v2.HasValue) { v = v2; } return v.HasValue; },
@@ -539,6 +539,22 @@
                 { typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
             };
 
+            private static readonly Dictionary<System.Type, Func<object>> Readers = new Dictionary<System.Type, Func<object>>
+            {
+                // TODO: Provide more optimized readers.
+                { typeof(bool), null },
+                { typeof(int), null },
+                { typeof(long), () => (Func<CodedInputStream, long?>)CodedInputStream.ReadInt64Wrapper },
+                { typeof(uint), null },
+                { typeof(ulong), null },
+                { typeof(float), null },
+                { typeof(double), () => BitConverter.IsLittleEndian ?
+                    (Func<CodedInputStream, double?>)CodedInputStream.ReadDoubleWrapperLittleEndian :
+                    (Func<CodedInputStream, double?>)CodedInputStream.ReadDoubleWrapperBigEndian },
+                { typeof(string), null },
+                { typeof(ByteString), null },
+            };
+
             /// <summary>
             /// Returns a field codec which effectively wraps a value of type T in a message.
             ///
@@ -553,6 +569,23 @@
                 return (FieldCodec<T>) value;
             }
 
+            internal static Func<CodedInputStream, T?> GetReader<T>() where T : struct
+            {
+                Func<object> value;
+                if (!Readers.TryGetValue(typeof(T), out value))
+                {
+                    throw new InvalidOperationException("Invalid type argument requested for wrapper reader: " + typeof(T));
+                }
+                if (value == null)
+                {
+                    // Return default unoptimized reader for the wrapper type.
+                    var nestedCoded = GetCodec<T>();
+                    return input => Read<T>(input, nestedCoded);
+                }
+                // Return optimized read for the wrapper type.
+                return (Func<CodedInputStream, T?>)value();
+            }
+
             internal static T Read<T>(CodedInputStream input, FieldCodec<T> codec)
             {
                 int length = input.ReadLength();