Squashed 'third_party/protobuf/' content from commit e35e248

Change-Id: I6cbe123d09fe50fdcad0e51466665daeee7433c7
git-subtree-dir: third_party/protobuf
git-subtree-split: e35e24800fb8d694bdeea5fd63dc7d1b14d68723
diff --git a/csharp/src/Google.Protobuf/ByteArray.cs b/csharp/src/Google.Protobuf/ByteArray.cs
new file mode 100644
index 0000000..69b6ef8
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ByteArray.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy

+    /// </summary>

+    internal static class ByteArray

+    {

+        /// <summary>

+        /// The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy

+        /// </summary>

+        private const int CopyThreshold = 12;

+

+        /// <summary>

+        /// Determines which copy routine to use based on the number of bytes to be copied.

+        /// </summary>

+        internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)

+        {

+            if (count > CopyThreshold)

+            {

+                Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count);

+            }

+            else

+            {

+                int stop = srcOffset + count;

+                for (int i = srcOffset; i < stop; i++)

+                {

+                    dst[dstOffset++] = src[i];

+                }

+            }

+        }

+

+        /// <summary>

+        /// Reverses the order of bytes in the array

+        /// </summary>

+        internal static void Reverse(byte[] bytes)

+        {

+            for (int first = 0, last = bytes.Length - 1; first < last; first++, last--)

+            {

+                byte temp = bytes[first];

+                bytes[first] = bytes[last];

+                bytes[last] = temp;

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs
new file mode 100644
index 0000000..dd7f22d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ByteString.cs
@@ -0,0 +1,345 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+using System.Collections;

+using System.Collections.Generic;

+using System.IO;

+using System.Text;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Immutable array of bytes.

+    /// </summary>

+    public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>

+    {

+        private static readonly ByteString empty = new ByteString(new byte[0]);

+

+        private readonly byte[] bytes;

+

+        /// <summary>

+        /// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.

+        /// </summary>

+        internal static class Unsafe

+        {

+            /// <summary>

+            /// Constructs a new ByteString from the given byte array. The array is

+            /// *not* copied, and must not be modified after this constructor is called.

+            /// </summary>

+            internal static ByteString FromBytes(byte[] bytes)

+            {

+                return new ByteString(bytes);

+            }

+

+            /// <summary>

+            /// Provides direct, unrestricted access to the bytes contained in this instance.

+            /// You must not modify or resize the byte array returned by this method.

+            /// </summary>

+            internal static byte[] GetBuffer(ByteString bytes)

+            {

+                return bytes.bytes;

+            }

+        }

+

+        /// <summary>

+        /// Internal use only.  Ensure that the provided array is not mutated and belongs to this instance.

+        /// </summary>

+        internal static ByteString AttachBytes(byte[] bytes)

+        {

+            return new ByteString(bytes);

+        }

+

+        /// <summary>

+        /// Constructs a new ByteString from the given byte array. The array is

+        /// *not* copied, and must not be modified after this constructor is called.

+        /// </summary>

+        private ByteString(byte[] bytes)

+        {

+            this.bytes = bytes;

+        }

+

+        /// <summary>

+        /// Returns an empty ByteString.

+        /// </summary>

+        public static ByteString Empty

+        {

+            get { return empty; }

+        }

+

+        /// <summary>

+        /// Returns the length of this ByteString in bytes.

+        /// </summary>

+        public int Length

+        {

+            get { return bytes.Length; }

+        }

+

+        /// <summary>

+        /// Returns <c>true</c> if this byte string is empty, <c>false</c> otherwise.

+        /// </summary>

+        public bool IsEmpty

+        {

+            get { return Length == 0; }

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a byte array.

+        /// </summary>

+        /// <remarks>The data is copied - changes to the returned array will not be reflected in this <c>ByteString</c>.</remarks>

+        /// <returns>A byte array with the same data as this <c>ByteString</c>.</returns>

+        public byte[] ToByteArray()

+        {

+            return (byte[]) bytes.Clone();

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a standard base64 representation.

+        /// </summary>

+        /// <returns>A base64 representation of this <c>ByteString</c>.</returns>

+        public string ToBase64()

+        {

+            return Convert.ToBase64String(bytes);

+        }

+

+        /// <summary>

+        /// Constructs a <see cref="ByteString" /> from the Base64 Encoded String.

+        /// </summary>

+        public static ByteString FromBase64(string bytes)

+        {

+            // By handling the empty string explicitly, we not only optimize but we fix a

+            // problem on CF 2.0. See issue 61 for details.

+            return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes));

+        }

+

+        /// <summary>

+        /// Constructs a <see cref="ByteString" /> from the given array. The contents

+        /// are copied, so further modifications to the array will not

+        /// be reflected in the returned ByteString.

+        /// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form

+        /// which is primarily useful for testing.

+        /// </summary>

+        public static ByteString CopyFrom(params byte[] bytes)

+        {

+            return new ByteString((byte[]) bytes.Clone());

+        }

+

+        /// <summary>

+        /// Constructs a <see cref="ByteString" /> from a portion of a byte array.

+        /// </summary>

+        public static ByteString CopyFrom(byte[] bytes, int offset, int count)

+        {

+            byte[] portion = new byte[count];

+            ByteArray.Copy(bytes, offset, portion, 0, count);

+            return new ByteString(portion);

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="ByteString" /> by encoding the specified text with

+        /// the given encoding.

+        /// </summary>

+        public static ByteString CopyFrom(string text, Encoding encoding)

+        {

+            return new ByteString(encoding.GetBytes(text));

+        }

+

+        /// <summary>

+        /// Creates a new <see cref="ByteString" /> by encoding the specified text in UTF-8.

+        /// </summary>

+        public static ByteString CopyFromUtf8(string text)

+        {

+            return CopyFrom(text, Encoding.UTF8);

+        }

+

+        /// <summary>

+        /// Retuns the byte at the given index.

+        /// </summary>

+        public byte this[int index]

+        {

+            get { return bytes[index]; }

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a string by applying the given encoding.

+        /// </summary>

+        /// <remarks>

+        /// This method should only be used to convert binary data which was the result of encoding

+        /// text with the given encoding.

+        /// </remarks>

+        /// <param name="encoding">The encoding to use to decode the binary data into text.</param>

+        /// <returns>The result of decoding the binary data with the given decoding.</returns>

+        public string ToString(Encoding encoding)

+        {

+            return encoding.GetString(bytes, 0, bytes.Length);

+        }

+

+        /// <summary>

+        /// Converts this <see cref="ByteString"/> into a string by applying the UTF-8 encoding.

+        /// </summary>

+        /// <remarks>

+        /// This method should only be used to convert binary data which was the result of encoding

+        /// text with UTF-8.

+        /// </remarks>

+        /// <returns>The result of decoding the binary data with the given decoding.</returns>

+        public string ToStringUtf8()

+        {

+            return ToString(Encoding.UTF8);

+        }

+

+        /// <summary>

+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.

+        /// </summary>

+        /// <returns>An iterator over the bytes in this object.</returns>

+        public IEnumerator<byte> GetEnumerator()

+        {

+            return ((IEnumerable<byte>) bytes).GetEnumerator();

+        }

+

+        /// <summary>

+        /// Returns an iterator over the bytes in this <see cref="ByteString"/>.

+        /// </summary>

+        /// <returns>An iterator over the bytes in this object.</returns>

+        IEnumerator IEnumerable.GetEnumerator()

+        {

+            return GetEnumerator();

+        }

+

+        /// <summary>

+        /// Creates a CodedInputStream from this ByteString's data.

+        /// </summary>

+        public CodedInputStream CreateCodedInput()

+        {

+            // We trust CodedInputStream not to reveal the provided byte array or modify it

+            return new CodedInputStream(bytes);

+        }

+

+        /// <summary>

+        /// Compares two byte strings for equality.

+        /// </summary>

+        /// <param name="lhs">The first byte string to compare.</param>

+        /// <param name="rhs">The second byte string to compare.</param>

+        /// <returns><c>true</c> if the byte strings are equal; false otherwise.</returns>

+        public static bool operator ==(ByteString lhs, ByteString rhs)

+        {

+            if (ReferenceEquals(lhs, rhs))

+            {

+                return true;

+            }

+            if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))

+            {

+                return false;

+            }

+            if (lhs.bytes.Length != rhs.bytes.Length)

+            {

+                return false;

+            }

+            for (int i = 0; i < lhs.Length; i++)

+            {

+                if (rhs.bytes[i] != lhs.bytes[i])

+                {

+                    return false;

+                }

+            }

+            return true;

+        }

+

+        /// <summary>

+        /// Compares two byte strings for inequality.

+        /// </summary>

+        /// <param name="lhs">The first byte string to compare.</param>

+        /// <param name="rhs">The second byte string to compare.</param>

+        /// <returns><c>false</c> if the byte strings are equal; true otherwise.</returns>

+        public static bool operator !=(ByteString lhs, ByteString rhs)

+        {

+            return !(lhs == rhs);

+        }

+

+        /// <summary>

+        /// Compares this byte string with another object.

+        /// </summary>

+        /// <param name="obj">The object to compare this with.</param>

+        /// <returns><c>true</c> if <paramref name="obj"/> refers to an equal <see cref="ByteString"/>; <c>false</c> otherwise.</returns>

+        public override bool Equals(object obj)

+        {

+            return this == (obj as ByteString);

+        }

+

+        /// <summary>

+        /// Returns a hash code for this object. Two equal byte strings

+        /// will return the same hash code.

+        /// </summary>

+        /// <returns>A hash code for this object.</returns>

+        public override int GetHashCode()

+        {

+            int ret = 23;

+            foreach (byte b in bytes)

+            {

+                ret = (ret << 8) | b;

+            }

+            return ret;

+        }

+

+        /// <summary>

+        /// Compares this byte string with another.

+        /// </summary>

+        /// <param name="other">The <see cref="ByteString"/> to compare this with.</param>

+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal byte string; <c>false</c> otherwise.</returns>

+        public bool Equals(ByteString other)

+        {

+            return this == other;

+        }

+

+        /// <summary>

+        /// Used internally by CodedOutputStream to avoid creating a copy for the write

+        /// </summary>

+        internal void WriteRawBytesTo(CodedOutputStream outputStream)

+        {

+            outputStream.WriteRawBytes(bytes, 0, bytes.Length);

+        }

+

+        /// <summary>

+        /// Copies the entire byte array to the destination array provided at the offset specified.

+        /// </summary>

+        public void CopyTo(byte[] array, int position)

+        {

+            ByteArray.Copy(bytes, 0, array, position, bytes.Length);

+        }

+

+        /// <summary>

+        /// Writes the entire byte array to the provided stream

+        /// </summary>

+        public void WriteTo(Stream outputStream)

+        {

+            outputStream.Write(bytes, 0, bytes.Length);

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
new file mode 100644
index 0000000..91bed8e
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -0,0 +1,1221 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using Google.Protobuf.Collections;

+using System;

+using System.Collections.Generic;

+using System.IO;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Reads and decodes protocol message fields.

+    /// </summary>

+    /// <remarks>

+    /// <para>

+    /// This class is generally used by generated code to read appropriate

+    /// primitives from the stream. It effectively encapsulates the lowest

+    /// levels of protocol buffer format.

+    /// </para>

+    /// <para>

+    /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>

+    /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.

+    /// </para>

+    /// </remarks>

+    public sealed class CodedInputStream

+    {

+        /// <summary>

+        /// Buffer of data read from the stream or provided at construction time.

+        /// </summary>

+        private readonly byte[] buffer;

+

+        /// <summary>

+        /// The index of the buffer at which we need to refill from the stream (if there is one).

+        /// </summary>

+        private int bufferSize;

+

+        private int bufferSizeAfterLimit = 0;

+        /// <summary>

+        /// The position within the current buffer (i.e. the next byte to read)

+        /// </summary>

+        private int bufferPos = 0;

+

+        /// <summary>

+        /// The stream to read further input from, or null if the byte array buffer was provided

+        /// directly on construction, with no further data available.

+        /// </summary>

+        private readonly Stream input;

+

+        /// <summary>

+        /// The last tag we read. 0 indicates we've read to the end of the stream

+        /// (or haven't read anything yet).

+        /// </summary>

+        private uint lastTag = 0;

+

+        /// <summary>

+        /// The next tag, used to store the value read by PeekTag.

+        /// </summary>

+        private uint nextTag = 0;

+        private bool hasNextTag = false;

+

+        internal const int DefaultRecursionLimit = 64;

+        internal const int DefaultSizeLimit = 64 << 20; // 64MB

+        internal const int BufferSize = 4096;

+

+        /// <summary>

+        /// The total number of bytes read before the current buffer. The

+        /// total bytes read up to the current position can be computed as

+        /// totalBytesRetired + bufferPos.

+        /// </summary>

+        private int totalBytesRetired = 0;

+

+        /// <summary>

+        /// The absolute position of the end of the current message.

+        /// </summary> 

+        private int currentLimit = int.MaxValue;

+

+        private int recursionDepth = 0;

+

+        private readonly int recursionLimit;

+        private readonly int sizeLimit;

+

+        #region Construction

+        // Note that the checks are performed such that we don't end up checking obviously-valid things

+        // like non-null references for arrays we've just created.

+

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given byte array.

+        /// </summary>

+        public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)

+        {            

+        }

+

+        /// <summary>

+        /// Creates a new CodedInputStream that reads from the given byte array slice.

+        /// </summary>

+        public CodedInputStream(byte[] buffer, int offset, int length)

+            : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)

+        {            

+            if (offset < 0 || offset > buffer.Length)

+            {

+                throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");

+            }

+            if (length < 0 || offset + length > buffer.Length)

+            {

+                throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");

+            }

+        }

+

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given stream.

+        /// </summary>

+        public CodedInputStream(Stream input) : this(input, new byte[BufferSize], 0, 0)

+        {

+            ProtoPreconditions.CheckNotNull(input, "input");

+        }

+

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given

+        /// stream and buffer, using the default limits.

+        /// </summary>

+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize)

+        {

+            this.input = input;

+            this.buffer = buffer;

+            this.bufferPos = bufferPos;

+            this.bufferSize = bufferSize;

+            this.sizeLimit = DefaultSizeLimit;

+            this.recursionLimit = DefaultRecursionLimit;

+        }

+

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given

+        /// stream and buffer, using the specified limits.

+        /// </summary>

+        /// <remarks>

+        /// This chains to the version with the default limits instead of vice versa to avoid

+        /// having to check that the default values are valid every time.

+        /// </remarks>

+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit)

+            : this(input, buffer, bufferPos, bufferSize)

+        {

+            if (sizeLimit <= 0)

+            {

+                throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");

+            }

+            if (recursionLimit <= 0)

+            {

+                throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");

+            }

+            this.sizeLimit = sizeLimit;

+            this.recursionLimit = recursionLimit;

+        }

+        #endregion

+

+        /// <summary>

+        /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading

+        /// from an input stream.

+        /// </summary>

+        /// <remarks>

+        /// This method exists separately from the constructor to reduce the number of constructor overloads.

+        /// It is likely to be used considerably less frequently than the constructors, as the default limits

+        /// are suitable for most use cases.

+        /// </remarks>

+        /// <param name="input">The input stream to read from</param>

+        /// <param name="sizeLimit">The total limit of data to read from the stream.</param>

+        /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>

+        /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size

+        /// and recursion limits.</returns>

+        public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)

+        {

+            return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit);

+        }

+

+        /// <summary>

+        /// Returns the current position in the input stream, or the position in the input buffer

+        /// </summary>

+        public long Position 

+        {

+            get

+            {

+                if (input != null)

+                {

+                    return input.Position - ((bufferSize + bufferSizeAfterLimit) - bufferPos);

+                }

+                return bufferPos;

+            }

+        }

+

+        /// <summary>

+        /// Returns the last tag read, or 0 if no tags have been read or we've read beyond

+        /// the end of the stream.

+        /// </summary>

+        internal uint LastTag { get { return lastTag; } }

+

+        /// <summary>

+        /// Returns the size limit for this stream.

+        /// </summary>

+        /// <remarks>

+        /// This limit is applied when reading from the underlying stream, as a sanity check. It is

+        /// not applied when reading from a byte array data source without an underlying stream.

+        /// The default value is 64MB.

+        /// </remarks>

+        /// <value>

+        /// The size limit.

+        /// </value>

+        public int SizeLimit { get { return sizeLimit; } }

+

+        /// <summary>

+        /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,

+        /// to avoid maliciously-recursive data.

+        /// </summary>

+        /// <remarks>

+        /// The default limit is 64.

+        /// </remarks>

+        /// <value>

+        /// The recursion limit for this stream.

+        /// </value>

+        public int RecursionLimit { get { return recursionLimit; } }

+

+        #region Validation

+        /// <summary>

+        /// Verifies that the last call to ReadTag() returned tag 0 - in other words,

+        /// we've reached the end of the stream when we expected to.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">The 

+        /// tag read was not the one specified</exception>

+        internal void CheckReadEndOfStreamTag()

+        {

+            if (lastTag != 0)

+            {

+                throw InvalidProtocolBufferException.MoreDataAvailable();

+            }

+        }

+        #endregion

+

+        #region Reading of tags etc

+

+        /// <summary>

+        /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the

+        /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the

+        /// same value.)

+        /// </summary>

+        public uint PeekTag()

+        {

+            if (hasNextTag)

+            {

+                return nextTag;

+            }

+

+            uint savedLast = lastTag;

+            nextTag = ReadTag();

+            hasNextTag = true;

+            lastTag = savedLast; // Undo the side effect of ReadTag

+            return nextTag;

+        }

+

+        /// <summary>

+        /// Reads a field tag, returning the tag of 0 for "end of stream".

+        /// </summary>

+        /// <remarks>

+        /// If this method returns 0, it doesn't necessarily mean the end of all

+        /// the data in this CodedInputStream; it may be the end of the logical stream

+        /// for an embedded message, for example.

+        /// </remarks>

+        /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>

+        public uint ReadTag()

+        {

+            if (hasNextTag)

+            {

+                lastTag = nextTag;

+                hasNextTag = false;

+                return lastTag;

+            }

+

+            // Optimize for the incredibly common case of having at least two bytes left in the buffer,

+            // and those two bytes being enough to get the tag. This will be true for fields up to 4095.

+            if (bufferPos + 2 <= bufferSize)

+            {

+                int tmp = buffer[bufferPos++];

+                if (tmp < 128)

+                {

+                    lastTag = (uint)tmp;

+                }

+                else

+                {

+                    int result = tmp & 0x7f;

+                    if ((tmp = buffer[bufferPos++]) < 128)

+                    {

+                        result |= tmp << 7;

+                        lastTag = (uint) result;

+                    }

+                    else

+                    {

+                        // Nope, rewind and go the potentially slow route.

+                        bufferPos -= 2;

+                        lastTag = ReadRawVarint32();

+                    }

+                }

+            }

+            else

+            {

+                if (IsAtEnd)

+                {

+                    lastTag = 0;

+                    return 0; // This is the only case in which we return 0.

+                }

+

+                lastTag = ReadRawVarint32();

+            }

+            if (lastTag == 0)

+            {

+                // If we actually read zero, that's not a valid tag.

+                throw InvalidProtocolBufferException.InvalidTag();

+            }

+            return lastTag;

+        }

+

+        /// <summary>

+        /// Skips the data for the field with the tag we've just read.

+        /// This should be called directly after <see cref="ReadTag"/>, when

+        /// the caller wishes to skip an unknown field.

+        /// </summary>

+        public void SkipLastField()

+        {

+            if (lastTag == 0)

+            {

+                throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");

+            }

+            switch (WireFormat.GetTagWireType(lastTag))

+            {

+                case WireFormat.WireType.StartGroup:

+                    SkipGroup();

+                    break;

+                case WireFormat.WireType.EndGroup:

+                    // Just ignore; there's no data following the tag.

+                    break;

+                case WireFormat.WireType.Fixed32:

+                    ReadFixed32();

+                    break;

+                case WireFormat.WireType.Fixed64:

+                    ReadFixed64();

+                    break;

+                case WireFormat.WireType.LengthDelimited:

+                    var length = ReadLength();

+                    SkipRawBytes(length);

+                    break;

+                case WireFormat.WireType.Varint:

+                    ReadRawVarint32();

+                    break;

+            }

+        }

+

+        private void SkipGroup()

+        {

+            // Note: Currently we expect this to be the way that groups are read. We could put the recursion

+            // depth changes into the ReadTag method instead, potentially...

+            recursionDepth++;

+            if (recursionDepth >= recursionLimit)

+            {

+                throw InvalidProtocolBufferException.RecursionLimitExceeded();

+            }

+            uint tag;

+            do

+            {

+                tag = ReadTag();

+                if (tag == 0)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                // This recursion will allow us to handle nested groups.

+                SkipLastField();

+            } while (WireFormat.GetTagWireType(tag) != WireFormat.WireType.EndGroup);

+            recursionDepth--;

+        }

+

+        /// <summary>

+        /// Reads a double field from the stream.

+        /// </summary>

+        public double ReadDouble()

+        {

+            return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());

+        }

+

+        /// <summary>

+        /// Reads a float field from the stream.

+        /// </summary>

+        public float ReadFloat()

+        {

+            if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)

+            {

+                float ret = BitConverter.ToSingle(buffer, bufferPos);

+                bufferPos += 4;

+                return ret;

+            }

+            else

+            {

+                byte[] rawBytes = ReadRawBytes(4);

+                if (!BitConverter.IsLittleEndian)

+                {

+                    ByteArray.Reverse(rawBytes);

+                }

+                return BitConverter.ToSingle(rawBytes, 0);

+            }

+        }

+

+        /// <summary>

+        /// Reads a uint64 field from the stream.

+        /// </summary>

+        public ulong ReadUInt64()

+        {

+            return ReadRawVarint64();

+        }

+

+        /// <summary>

+        /// Reads an int64 field from the stream.

+        /// </summary>

+        public long ReadInt64()

+        {

+            return (long) ReadRawVarint64();

+        }

+

+        /// <summary>

+        /// Reads an int32 field from the stream.

+        /// </summary>

+        public int ReadInt32()

+        {

+            return (int) ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Reads a fixed64 field from the stream.

+        /// </summary>

+        public ulong ReadFixed64()

+        {

+            return ReadRawLittleEndian64();

+        }

+

+        /// <summary>

+        /// Reads a fixed32 field from the stream.

+        /// </summary>

+        public uint ReadFixed32()

+        {

+            return ReadRawLittleEndian32();

+        }

+

+        /// <summary>

+        /// Reads a bool field from the stream.

+        /// </summary>

+        public bool ReadBool()

+        {

+            return ReadRawVarint32() != 0;

+        }

+

+        /// <summary>

+        /// Reads a string field from the stream.

+        /// </summary>

+        public string ReadString()

+        {

+            int length = ReadLength();

+            // No need to read any data for an empty string.

+            if (length == 0)

+            {

+                return "";

+            }

+            if (length <= bufferSize - bufferPos)

+            {

+                // Fast path:  We already have the bytes in a contiguous buffer, so

+                //   just copy directly from it.

+                String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);

+                bufferPos += length;

+                return result;

+            }

+            // Slow path: Build a byte array first then copy it.

+            return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);

+        }

+

+        /// <summary>

+        /// Reads an embedded message field value from the stream.

+        /// </summary>   

+        public void ReadMessage(IMessage builder)

+        {

+            int length = ReadLength();

+            if (recursionDepth >= recursionLimit)

+            {

+                throw InvalidProtocolBufferException.RecursionLimitExceeded();

+            }

+            int oldLimit = PushLimit(length);

+            ++recursionDepth;

+            builder.MergeFrom(this);

+            CheckReadEndOfStreamTag();

+            // Check that we've read exactly as much data as expected.

+            if (!ReachedLimit)

+            {

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+            --recursionDepth;

+            PopLimit(oldLimit);

+        }

+

+        /// <summary>

+        /// Reads a bytes field value from the stream.

+        /// </summary>   

+        public ByteString ReadBytes()

+        {

+            int length = ReadLength();

+            if (length <= bufferSize - bufferPos && length > 0)

+            {

+                // Fast path:  We already have the bytes in a contiguous buffer, so

+                //   just copy directly from it.

+                ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);

+                bufferPos += length;

+                return result;

+            }

+            else

+            {

+                // Slow path:  Build a byte array and attach it to a new ByteString.

+                return ByteString.AttachBytes(ReadRawBytes(length));

+            }

+        }

+

+        /// <summary>

+        /// Reads a uint32 field value from the stream.

+        /// </summary>   

+        public uint ReadUInt32()

+        {

+            return ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Reads an enum field value from the stream. If the enum is valid for type T,

+        /// then the ref value is set and it returns true.  Otherwise the unknown output

+        /// value is set and this method returns false.

+        /// </summary>   

+        public int ReadEnum()

+        {

+            // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.

+            return (int) ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Reads an sfixed32 field value from the stream.

+        /// </summary>   

+        public int ReadSFixed32()

+        {

+            return (int) ReadRawLittleEndian32();

+        }

+

+        /// <summary>

+        /// Reads an sfixed64 field value from the stream.

+        /// </summary>   

+        public long ReadSFixed64()

+        {

+            return (long) ReadRawLittleEndian64();

+        }

+

+        /// <summary>

+        /// Reads an sint32 field value from the stream.

+        /// </summary>   

+        public int ReadSInt32()

+        {

+            return DecodeZigZag32(ReadRawVarint32());

+        }

+

+        /// <summary>

+        /// Reads an sint64 field value from the stream.

+        /// </summary>   

+        public long ReadSInt64()

+        {

+            return DecodeZigZag64(ReadRawVarint64());

+        }

+

+        /// <summary>

+        /// Reads a length for length-delimited data.

+        /// </summary>

+        /// <remarks>

+        /// This is internally just reading a varint, but this method exists

+        /// to make the calling code clearer.

+        /// </remarks>

+        public int ReadLength()

+        {

+            return (int) ReadRawVarint32();

+        }

+

+        /// <summary>

+        /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,

+        /// the tag is consumed and the method returns <c>true</c>; otherwise, the

+        /// stream is left in the original position and the method returns <c>false</c>.

+        /// </summary>

+        public bool MaybeConsumeTag(uint tag)

+        {

+            if (PeekTag() == tag)

+            {

+                hasNextTag = false;

+                return true;

+            }

+            return false;

+        }

+

+        #endregion

+

+        #region Underlying reading primitives

+

+        /// <summary>

+        /// Same code as ReadRawVarint32, but read each byte individually, checking for

+        /// buffer overflow.

+        /// </summary>

+        private uint SlowReadRawVarint32()

+        {

+            int tmp = ReadRawByte();

+            if (tmp < 128)

+            {

+                return (uint) tmp;

+            }

+            int result = tmp & 0x7f;

+            if ((tmp = ReadRawByte()) < 128)

+            {

+                result |= tmp << 7;

+            }

+            else

+            {

+                result |= (tmp & 0x7f) << 7;

+                if ((tmp = ReadRawByte()) < 128)

+                {

+                    result |= tmp << 14;

+                }

+                else

+                {

+                    result |= (tmp & 0x7f) << 14;

+                    if ((tmp = ReadRawByte()) < 128)

+                    {

+                        result |= tmp << 21;

+                    }

+                    else

+                    {

+                        result |= (tmp & 0x7f) << 21;

+                        result |= (tmp = ReadRawByte()) << 28;

+                        if (tmp >= 128)

+                        {

+                            // Discard upper 32 bits.

+                            for (int i = 0; i < 5; i++)

+                            {

+                                if (ReadRawByte() < 128)

+                                {

+                                    return (uint) result;

+                                }

+                            }

+                            throw InvalidProtocolBufferException.MalformedVarint();

+                        }

+                    }

+                }

+            }

+            return (uint) result;

+        }

+

+        /// <summary>

+        /// Reads a raw Varint from the stream.  If larger than 32 bits, discard the upper bits.

+        /// This method is optimised for the case where we've got lots of data in the buffer.

+        /// That means we can check the size just once, then just read directly from the buffer

+        /// without constant rechecking of the buffer length.

+        /// </summary>

+        internal uint ReadRawVarint32()

+        {

+            if (bufferPos + 5 > bufferSize)

+            {

+                return SlowReadRawVarint32();

+            }

+

+            int tmp = buffer[bufferPos++];

+            if (tmp < 128)

+            {

+                return (uint) tmp;

+            }

+            int result = tmp & 0x7f;

+            if ((tmp = buffer[bufferPos++]) < 128)

+            {

+                result |= tmp << 7;

+            }

+            else

+            {

+                result |= (tmp & 0x7f) << 7;

+                if ((tmp = buffer[bufferPos++]) < 128)

+                {

+                    result |= tmp << 14;

+                }

+                else

+                {

+                    result |= (tmp & 0x7f) << 14;

+                    if ((tmp = buffer[bufferPos++]) < 128)

+                    {

+                        result |= tmp << 21;

+                    }

+                    else

+                    {

+                        result |= (tmp & 0x7f) << 21;

+                        result |= (tmp = buffer[bufferPos++]) << 28;

+                        if (tmp >= 128)

+                        {

+                            // Discard upper 32 bits.

+                            // Note that this has to use ReadRawByte() as we only ensure we've

+                            // got at least 5 bytes at the start of the method. This lets us

+                            // use the fast path in more cases, and we rarely hit this section of code.

+                            for (int i = 0; i < 5; i++)

+                            {

+                                if (ReadRawByte() < 128)

+                                {

+                                    return (uint) result;

+                                }

+                            }

+                            throw InvalidProtocolBufferException.MalformedVarint();

+                        }

+                    }

+                }

+            }

+            return (uint) result;

+        }

+

+        /// <summary>

+        /// Reads a varint from the input one byte at a time, so that it does not

+        /// read any bytes after the end of the varint. If you simply wrapped the

+        /// stream in a CodedInputStream and used ReadRawVarint32(Stream)

+        /// then you would probably end up reading past the end of the varint since

+        /// CodedInputStream buffers its input.

+        /// </summary>

+        /// <param name="input"></param>

+        /// <returns></returns>

+        internal static uint ReadRawVarint32(Stream input)

+        {

+            int result = 0;

+            int offset = 0;

+            for (; offset < 32; offset += 7)

+            {

+                int b = input.ReadByte();

+                if (b == -1)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                result |= (b & 0x7f) << offset;

+                if ((b & 0x80) == 0)

+                {

+                    return (uint) result;

+                }

+            }

+            // Keep reading up to 64 bits.

+            for (; offset < 64; offset += 7)

+            {

+                int b = input.ReadByte();

+                if (b == -1)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                if ((b & 0x80) == 0)

+                {

+                    return (uint) result;

+                }

+            }

+            throw InvalidProtocolBufferException.MalformedVarint();

+        }

+

+        /// <summary>

+        /// Reads a raw varint from the stream.

+        /// </summary>

+        internal ulong ReadRawVarint64()

+        {

+            int shift = 0;

+            ulong result = 0;

+            while (shift < 64)

+            {

+                byte b = ReadRawByte();

+                result |= (ulong) (b & 0x7F) << shift;

+                if ((b & 0x80) == 0)

+                {

+                    return result;

+                }

+                shift += 7;

+            }

+            throw InvalidProtocolBufferException.MalformedVarint();

+        }

+

+        /// <summary>

+        /// Reads a 32-bit little-endian integer from the stream.

+        /// </summary>

+        internal uint ReadRawLittleEndian32()

+        {

+            uint b1 = ReadRawByte();

+            uint b2 = ReadRawByte();

+            uint b3 = ReadRawByte();

+            uint b4 = ReadRawByte();

+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);

+        }

+

+        /// <summary>

+        /// Reads a 64-bit little-endian integer from the stream.

+        /// </summary>

+        internal ulong ReadRawLittleEndian64()

+        {

+            ulong b1 = ReadRawByte();

+            ulong b2 = ReadRawByte();

+            ulong b3 = ReadRawByte();

+            ulong b4 = ReadRawByte();

+            ulong b5 = ReadRawByte();

+            ulong b6 = ReadRawByte();

+            ulong b7 = ReadRawByte();

+            ulong b8 = ReadRawByte();

+            return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)

+                   | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);

+        }

+

+        /// <summary>

+        /// Decode a 32-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static int DecodeZigZag32(uint n)

+        {

+            return (int)(n >> 1) ^ -(int)(n & 1);

+        }

+

+        /// <summary>

+        /// Decode a 32-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static long DecodeZigZag64(ulong n)

+        {

+            return (long)(n >> 1) ^ -(long)(n & 1);

+        }

+        #endregion

+

+        #region Internal reading and buffer management

+

+        /// <summary>

+        /// Sets currentLimit to (current position) + byteLimit. This is called

+        /// when descending into a length-delimited embedded message. The previous

+        /// limit is returned.

+        /// </summary>

+        /// <returns>The old limit.</returns>

+        internal int PushLimit(int byteLimit)

+        {

+            if (byteLimit < 0)

+            {

+                throw InvalidProtocolBufferException.NegativeSize();

+            }

+            byteLimit += totalBytesRetired + bufferPos;

+            int oldLimit = currentLimit;

+            if (byteLimit > oldLimit)

+            {

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+            currentLimit = byteLimit;

+

+            RecomputeBufferSizeAfterLimit();

+

+            return oldLimit;

+        }

+

+        private void RecomputeBufferSizeAfterLimit()

+        {

+            bufferSize += bufferSizeAfterLimit;

+            int bufferEnd = totalBytesRetired + bufferSize;

+            if (bufferEnd > currentLimit)

+            {

+                // Limit is in current buffer.

+                bufferSizeAfterLimit = bufferEnd - currentLimit;

+                bufferSize -= bufferSizeAfterLimit;

+            }

+            else

+            {

+                bufferSizeAfterLimit = 0;

+            }

+        }

+

+        /// <summary>

+        /// Discards the current limit, returning the previous limit.

+        /// </summary>

+        internal void PopLimit(int oldLimit)

+        {

+            currentLimit = oldLimit;

+            RecomputeBufferSizeAfterLimit();

+        }

+

+        /// <summary>

+        /// Returns whether or not all the data before the limit has been read.

+        /// </summary>

+        /// <returns></returns>

+        internal bool ReachedLimit

+        {

+            get

+            {

+                if (currentLimit == int.MaxValue)

+                {

+                    return false;

+                }

+                int currentAbsolutePosition = totalBytesRetired + bufferPos;

+                return currentAbsolutePosition >= currentLimit;

+            }

+        }

+

+        /// <summary>

+        /// Returns true if the stream has reached the end of the input. This is the

+        /// case if either the end of the underlying input source has been reached or

+        /// the stream has reached a limit created using PushLimit.

+        /// </summary>

+        public bool IsAtEnd

+        {

+            get { return bufferPos == bufferSize && !RefillBuffer(false); }

+        }

+

+        /// <summary>

+        /// Called when buffer is empty to read more bytes from the

+        /// input.  If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that

+        /// either there will be at least one byte in the buffer when it returns

+        /// or it will throw an exception.  If <paramref name="mustSucceed"/> is false,

+        /// RefillBuffer() returns false if no more bytes were available.

+        /// </summary>

+        /// <param name="mustSucceed"></param>

+        /// <returns></returns>

+        private bool RefillBuffer(bool mustSucceed)

+        {

+            if (bufferPos < bufferSize)

+            {

+                throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");

+            }

+

+            if (totalBytesRetired + bufferSize == currentLimit)

+            {

+                // Oops, we hit a limit.

+                if (mustSucceed)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                else

+                {

+                    return false;

+                }

+            }

+

+            totalBytesRetired += bufferSize;

+

+            bufferPos = 0;

+            bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);

+            if (bufferSize < 0)

+            {

+                throw new InvalidOperationException("Stream.Read returned a negative count");

+            }

+            if (bufferSize == 0)

+            {

+                if (mustSucceed)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+                else

+                {

+                    return false;

+                }

+            }

+            else

+            {

+                RecomputeBufferSizeAfterLimit();

+                int totalBytesRead =

+                    totalBytesRetired + bufferSize + bufferSizeAfterLimit;

+                if (totalBytesRead > sizeLimit || totalBytesRead < 0)

+                {

+                    throw InvalidProtocolBufferException.SizeLimitExceeded();

+                }

+                return true;

+            }

+        }

+

+        /// <summary>

+        /// Read one byte from the input.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">

+        /// the end of the stream or the current limit was reached

+        /// </exception>

+        internal byte ReadRawByte()

+        {

+            if (bufferPos == bufferSize)

+            {

+                RefillBuffer(true);

+            }

+            return buffer[bufferPos++];

+        }

+

+        /// <summary>

+        /// Reads a fixed size of bytes from the input.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">

+        /// the end of the stream or the current limit was reached

+        /// </exception>

+        internal byte[] ReadRawBytes(int size)

+        {

+            if (size < 0)

+            {

+                throw InvalidProtocolBufferException.NegativeSize();

+            }

+

+            if (totalBytesRetired + bufferPos + size > currentLimit)

+            {

+                // Read to the end of the stream (up to the current limit) anyway.

+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);

+                // Then fail.

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+

+            if (size <= bufferSize - bufferPos)

+            {

+                // We have all the bytes we need already.

+                byte[] bytes = new byte[size];

+                ByteArray.Copy(buffer, bufferPos, bytes, 0, size);

+                bufferPos += size;

+                return bytes;

+            }

+            else if (size < buffer.Length)

+            {

+                // Reading more bytes than are in the buffer, but not an excessive number

+                // of bytes.  We can safely allocate the resulting array ahead of time.

+

+                // First copy what we have.

+                byte[] bytes = new byte[size];

+                int pos = bufferSize - bufferPos;

+                ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);

+                bufferPos = bufferSize;

+

+                // We want to use RefillBuffer() and then copy from the buffer into our

+                // byte array rather than reading directly into our byte array because

+                // the input may be unbuffered.

+                RefillBuffer(true);

+

+                while (size - pos > bufferSize)

+                {

+                    Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);

+                    pos += bufferSize;

+                    bufferPos = bufferSize;

+                    RefillBuffer(true);

+                }

+

+                ByteArray.Copy(buffer, 0, bytes, pos, size - pos);

+                bufferPos = size - pos;

+

+                return bytes;

+            }

+            else

+            {

+                // The size is very large.  For security reasons, we can't allocate the

+                // entire byte array yet.  The size comes directly from the input, so a

+                // maliciously-crafted message could provide a bogus very large size in

+                // order to trick the app into allocating a lot of memory.  We avoid this

+                // by allocating and reading only a small chunk at a time, so that the

+                // malicious message must actually *be* extremely large to cause

+                // problems.  Meanwhile, we limit the allowed size of a message elsewhere.

+

+                // Remember the buffer markers since we'll have to copy the bytes out of

+                // it later.

+                int originalBufferPos = bufferPos;

+                int originalBufferSize = bufferSize;

+

+                // Mark the current buffer consumed.

+                totalBytesRetired += bufferSize;

+                bufferPos = 0;

+                bufferSize = 0;

+

+                // Read all the rest of the bytes we need.

+                int sizeLeft = size - (originalBufferSize - originalBufferPos);

+                List<byte[]> chunks = new List<byte[]>();

+

+                while (sizeLeft > 0)

+                {

+                    byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)];

+                    int pos = 0;

+                    while (pos < chunk.Length)

+                    {

+                        int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);

+                        if (n <= 0)

+                        {

+                            throw InvalidProtocolBufferException.TruncatedMessage();

+                        }

+                        totalBytesRetired += n;

+                        pos += n;

+                    }

+                    sizeLeft -= chunk.Length;

+                    chunks.Add(chunk);

+                }

+

+                // OK, got everything.  Now concatenate it all into one buffer.

+                byte[] bytes = new byte[size];

+

+                // Start by copying the leftover bytes from this.buffer.

+                int newPos = originalBufferSize - originalBufferPos;

+                ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);

+

+                // And now all the chunks.

+                foreach (byte[] chunk in chunks)

+                {

+                    Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);

+                    newPos += chunk.Length;

+                }

+

+                // Done.

+                return bytes;

+            }

+        }

+

+        /// <summary>

+        /// Reads and discards <paramref name="size"/> bytes.

+        /// </summary>

+        /// <exception cref="InvalidProtocolBufferException">the end of the stream

+        /// or the current limit was reached</exception>

+        private void SkipRawBytes(int size)

+        {

+            if (size < 0)

+            {

+                throw InvalidProtocolBufferException.NegativeSize();

+            }

+

+            if (totalBytesRetired + bufferPos + size > currentLimit)

+            {

+                // Read to the end of the stream anyway.

+                SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);

+                // Then fail.

+                throw InvalidProtocolBufferException.TruncatedMessage();

+            }

+

+            if (size <= bufferSize - bufferPos)

+            {

+                // We have all the bytes we need already.

+                bufferPos += size;

+            }

+            else

+            {

+                // Skipping more bytes than are in the buffer.  First skip what we have.

+                int pos = bufferSize - bufferPos;

+

+                // ROK 5/7/2013 Issue #54: should retire all bytes in buffer (bufferSize)

+                // totalBytesRetired += pos;

+                totalBytesRetired += bufferSize;

+                

+                bufferPos = 0;

+                bufferSize = 0;

+

+                // Then skip directly from the InputStream for the rest.

+                if (pos < size)

+                {

+                    if (input == null)

+                    {

+                        throw InvalidProtocolBufferException.TruncatedMessage();

+                    }

+                    SkipImpl(size - pos);

+                    totalBytesRetired += size - pos;

+                }

+            }

+        }

+

+        /// <summary>

+        /// Abstraction of skipping to cope with streams which can't really skip.

+        /// </summary>

+        private void SkipImpl(int amountToSkip)

+        {

+            if (input.CanSeek)

+            {

+                long previousPosition = input.Position;

+                input.Position += amountToSkip;

+                if (input.Position != previousPosition + amountToSkip)

+                {

+                    throw InvalidProtocolBufferException.TruncatedMessage();

+                }

+            }

+            else

+            {

+                byte[] skipBuffer = new byte[Math.Min(1024, amountToSkip)];

+                while (amountToSkip > 0)

+                {

+                    int bytesRead = input.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, amountToSkip));

+                    if (bytesRead <= 0)

+                    {

+                        throw InvalidProtocolBufferException.TruncatedMessage();

+                    }

+                    amountToSkip -= bytesRead;

+                }

+            }

+        }

+

+        #endregion

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs
new file mode 100644
index 0000000..bf221c9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs
@@ -0,0 +1,304 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+

+namespace Google.Protobuf

+{

+    // This part of CodedOutputStream provides all the static entry points that are used

+    // by generated code and internally to compute the size of messages prior to being

+    // written to an instance of CodedOutputStream.

+    public sealed partial class CodedOutputStream

+    {

+        private const int LittleEndian64Size = 8;

+        private const int LittleEndian32Size = 4;        

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// double field, including the tag.

+        /// </summary>

+        public static int ComputeDoubleSize(double value)

+        {

+            return LittleEndian64Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// float field, including the tag.

+        /// </summary>

+        public static int ComputeFloatSize(float value)

+        {

+            return LittleEndian32Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// uint64 field, including the tag.

+        /// </summary>

+        public static int ComputeUInt64Size(ulong value)

+        {

+            return ComputeRawVarint64Size(value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// int64 field, including the tag.

+        /// </summary>

+        public static int ComputeInt64Size(long value)

+        {

+            return ComputeRawVarint64Size((ulong) value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// int32 field, including the tag.

+        /// </summary>

+        public static int ComputeInt32Size(int value)

+        {

+            if (value >= 0)

+            {

+                return ComputeRawVarint32Size((uint) value);

+            }

+            else

+            {

+                // Must sign-extend.

+                return 10;

+            }

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// fixed64 field, including the tag.

+        /// </summary>

+        public static int ComputeFixed64Size(ulong value)

+        {

+            return LittleEndian64Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// fixed32 field, including the tag.

+        /// </summary>

+        public static int ComputeFixed32Size(uint value)

+        {

+            return LittleEndian32Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// bool field, including the tag.

+        /// </summary>

+        public static int ComputeBoolSize(bool value)

+        {

+            return 1;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// string field, including the tag.

+        /// </summary>

+        public static int ComputeStringSize(String value)

+        {

+            int byteArraySize = Utf8Encoding.GetByteCount(value);

+            return ComputeLengthSize(byteArraySize) + byteArraySize;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// group field, including the tag.

+        /// </summary>

+        public static int ComputeGroupSize(IMessage value)

+        {

+            return value.CalculateSize();

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// embedded message field, including the tag.

+        /// </summary>

+        public static int ComputeMessageSize(IMessage value)

+        {

+            int size = value.CalculateSize();

+            return ComputeLengthSize(size) + size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// bytes field, including the tag.

+        /// </summary>

+        public static int ComputeBytesSize(ByteString value)

+        {

+            return ComputeLengthSize(value.Length) + value.Length;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// uint32 field, including the tag.

+        /// </summary>

+        public static int ComputeUInt32Size(uint value)

+        {

+            return ComputeRawVarint32Size(value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a

+        /// enum field, including the tag. The caller is responsible for

+        /// converting the enum value to its numeric value.

+        /// </summary>

+        public static int ComputeEnumSize(int value)

+        {

+            // Currently just a pass-through, but it's nice to separate it logically.

+            return ComputeInt32Size(value);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sfixed32 field, including the tag.

+        /// </summary>

+        public static int ComputeSFixed32Size(int value)

+        {

+            return LittleEndian32Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sfixed64 field, including the tag.

+        /// </summary>

+        public static int ComputeSFixed64Size(long value)

+        {

+            return LittleEndian64Size;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sint32 field, including the tag.

+        /// </summary>

+        public static int ComputeSInt32Size(int value)

+        {

+            return ComputeRawVarint32Size(EncodeZigZag32(value));

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode an

+        /// sint64 field, including the tag.

+        /// </summary>

+        public static int ComputeSInt64Size(long value)

+        {

+            return ComputeRawVarint64Size(EncodeZigZag64(value));

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a length,

+        /// as written by <see cref="WriteLength"/>.

+        /// </summary>

+        public static int ComputeLengthSize(int length)

+        {

+            return ComputeRawVarint32Size((uint) length);

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a varint.

+        /// </summary>

+        public static int ComputeRawVarint32Size(uint value)

+        {

+            if ((value & (0xffffffff << 7)) == 0)

+            {

+                return 1;

+            }

+            if ((value & (0xffffffff << 14)) == 0)

+            {

+                return 2;

+            }

+            if ((value & (0xffffffff << 21)) == 0)

+            {

+                return 3;

+            }

+            if ((value & (0xffffffff << 28)) == 0)

+            {

+                return 4;

+            }

+            return 5;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a varint.

+        /// </summary>

+        public static int ComputeRawVarint64Size(ulong value)

+        {

+            if ((value & (0xffffffffffffffffL << 7)) == 0)

+            {

+                return 1;

+            }

+            if ((value & (0xffffffffffffffffL << 14)) == 0)

+            {

+                return 2;

+            }

+            if ((value & (0xffffffffffffffffL << 21)) == 0)

+            {

+                return 3;

+            }

+            if ((value & (0xffffffffffffffffL << 28)) == 0)

+            {

+                return 4;

+            }

+            if ((value & (0xffffffffffffffffL << 35)) == 0)

+            {

+                return 5;

+            }

+            if ((value & (0xffffffffffffffffL << 42)) == 0)

+            {

+                return 6;

+            }

+            if ((value & (0xffffffffffffffffL << 49)) == 0)

+            {

+                return 7;

+            }

+            if ((value & (0xffffffffffffffffL << 56)) == 0)

+            {

+                return 8;

+            }

+            if ((value & (0xffffffffffffffffL << 63)) == 0)

+            {

+                return 9;

+            }

+            return 10;

+        }

+

+        /// <summary>

+        /// Computes the number of bytes that would be needed to encode a tag.

+        /// </summary>

+        public static int ComputeTagSize(int fieldNumber)

+        {

+            return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.cs b/csharp/src/Google.Protobuf/CodedOutputStream.cs
new file mode 100644
index 0000000..d6355f0
--- /dev/null
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs
@@ -0,0 +1,708 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using Google.Protobuf.Collections;

+using System;

+using System.IO;

+using System.Text;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Encodes and writes protocol message fields.

+    /// </summary>

+    /// <remarks>

+    /// <para>

+    /// This class is generally used by generated code to write appropriate

+    /// primitives to the stream. It effectively encapsulates the lowest

+    /// levels of protocol buffer format. Unlike some other implementations,

+    /// this does not include combined "write tag and value" methods. Generated

+    /// code knows the exact byte representations of the tags they're going to write,

+    /// so there's no need to re-encode them each time. Manually-written code calling

+    /// this class should just call one of the <c>WriteTag</c> overloads before each value.

+    /// </para>

+    /// <para>

+    /// Repeated fields and map fields are not handled by this class; use <c>RepeatedField&lt;T&gt;</c>

+    /// and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.

+    /// </para>

+    /// </remarks>

+    public sealed partial class CodedOutputStream

+    {

+        // "Local" copy of Encoding.UTF8, for efficiency. (Yes, it makes a difference.)

+        internal static readonly Encoding Utf8Encoding = Encoding.UTF8;

+

+        /// <summary>

+        /// The buffer size used by CreateInstance(Stream).

+        /// </summary>

+        public static readonly int DefaultBufferSize = 4096;

+

+        private readonly byte[] buffer;

+        private readonly int limit;

+        private int position;

+        private readonly Stream output;

+

+        #region Construction

+        /// <summary>

+        /// Creates a new CodedOutputStream that writes directly to the given

+        /// byte array. If more bytes are written than fit in the array,

+        /// OutOfSpaceException will be thrown.

+        /// </summary>

+        public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream that writes directly to the given

+        /// byte array slice. If more bytes are written than fit in the array,

+        /// OutOfSpaceException will be thrown.

+        /// </summary>

+        private CodedOutputStream(byte[] buffer, int offset, int length)

+        {

+            this.output = null;

+            this.buffer = buffer;

+            this.position = offset;

+            this.limit = offset + length;

+        }

+

+        private CodedOutputStream(Stream output, byte[] buffer)

+        {

+            this.output = output;

+            this.buffer = buffer;

+            this.position = 0;

+            this.limit = buffer.Length;

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream which write to the given stream.

+        /// </summary>

+        public CodedOutputStream(Stream output) : this(output, DefaultBufferSize)

+        {

+        }

+

+        /// <summary>

+        /// Creates a new CodedOutputStream which write to the given stream and uses

+        /// the specified buffer size.

+        /// </summary>

+        public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize])

+        {

+        }    

+        #endregion

+

+        /// <summary>

+        /// Returns the current position in the stream, or the position in the output buffer

+        /// </summary>

+        public long Position

+        {

+            get

+            {

+                if (output != null)

+                {

+                    return output.Position + position;

+                }

+                return position;

+            }

+        }

+

+        #region Writing of values (not including tags)

+

+        /// <summary>

+        /// Writes a double field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteDouble(double value)

+        {

+            WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));

+        }

+

+        /// <summary>

+        /// Writes a float field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteFloat(float value)

+        {

+            byte[] rawBytes = BitConverter.GetBytes(value);

+            if (!BitConverter.IsLittleEndian)

+            {

+                ByteArray.Reverse(rawBytes);

+            }

+

+            if (limit - position >= 4)

+            {

+                buffer[position++] = rawBytes[0];

+                buffer[position++] = rawBytes[1];

+                buffer[position++] = rawBytes[2];

+                buffer[position++] = rawBytes[3];

+            }

+            else

+            {

+                WriteRawBytes(rawBytes, 0, 4);

+            }

+        }

+

+        /// <summary>

+        /// Writes a uint64 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteUInt64(ulong value)

+        {

+            WriteRawVarint64(value);

+        }

+

+        /// <summary>

+        /// Writes an int64 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteInt64(long value)

+        {

+            WriteRawVarint64((ulong) value);

+        }

+

+        /// <summary>

+        /// Writes an int32 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteInt32(int value)

+        {

+            if (value >= 0)

+            {

+                WriteRawVarint32((uint) value);

+            }

+            else

+            {

+                // Must sign-extend.

+                WriteRawVarint64((ulong) value);

+            }

+        }

+

+        /// <summary>

+        /// Writes a fixed64 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteFixed64(ulong value)

+        {

+            WriteRawLittleEndian64(value);

+        }

+

+        /// <summary>

+        /// Writes a fixed32 field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteFixed32(uint value)

+        {

+            WriteRawLittleEndian32(value);

+        }

+

+        /// <summary>

+        /// Writes a bool field value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteBool(bool value)

+        {

+            WriteRawByte(value ? (byte) 1 : (byte) 0);

+        }

+

+        /// <summary>

+        /// Writes a string field value, without a tag, to the stream.

+        /// The data is length-prefixed.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteString(string value)

+        {

+            // Optimise the case where we have enough space to write

+            // the string directly to the buffer, which should be common.

+            int length = Utf8Encoding.GetByteCount(value);

+            WriteLength(length);

+            if (limit - position >= length)

+            {

+                if (length == value.Length) // Must be all ASCII...

+                {

+                    for (int i = 0; i < length; i++)

+                    {

+                        buffer[position + i] = (byte)value[i];

+                    }

+                }

+                else

+                {

+                    Utf8Encoding.GetBytes(value, 0, value.Length, buffer, position);

+                }

+                position += length;

+            }

+            else

+            {

+                byte[] bytes = Utf8Encoding.GetBytes(value);

+                WriteRawBytes(bytes);

+            }

+        }

+

+        /// <summary>

+        /// Writes a message, without a tag, to the stream.

+        /// The data is length-prefixed.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteMessage(IMessage value)

+        {

+            WriteLength(value.CalculateSize());

+            value.WriteTo(this);

+        }

+

+        /// <summary>

+        /// Write a byte string, without a tag, to the stream.

+        /// The data is length-prefixed.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteBytes(ByteString value)

+        {

+            WriteLength(value.Length);

+            value.WriteRawBytesTo(this);

+        }

+

+        /// <summary>

+        /// Writes a uint32 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteUInt32(uint value)

+        {

+            WriteRawVarint32(value);

+        }

+

+        /// <summary>

+        /// Writes an enum value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteEnum(int value)

+        {

+            WriteInt32(value);

+        }

+

+        /// <summary>

+        /// Writes an sfixed32 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write.</param>

+        public void WriteSFixed32(int value)

+        {

+            WriteRawLittleEndian32((uint) value);

+        }

+

+        /// <summary>

+        /// Writes an sfixed64 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteSFixed64(long value)

+        {

+            WriteRawLittleEndian64((ulong) value);

+        }

+

+        /// <summary>

+        /// Writes an sint32 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteSInt32(int value)

+        {

+            WriteRawVarint32(EncodeZigZag32(value));

+        }

+

+        /// <summary>

+        /// Writes an sint64 value, without a tag, to the stream.

+        /// </summary>

+        /// <param name="value">The value to write</param>

+        public void WriteSInt64(long value)

+        {

+            WriteRawVarint64(EncodeZigZag64(value));

+        }

+

+        /// <summary>

+        /// Writes a length (in bytes) for length-delimited data.

+        /// </summary>

+        /// <remarks>

+        /// This method simply writes a rawint, but exists for clarity in calling code.

+        /// </remarks>

+        /// <param name="length">Length value, in bytes.</param>

+        public void WriteLength(int length)

+        {

+            WriteRawVarint32((uint) length);

+        }

+

+        #endregion

+

+        #region Raw tag writing

+        /// <summary>

+        /// Encodes and writes a tag.

+        /// </summary>

+        /// <param name="fieldNumber">The number of the field to write the tag for</param>

+        /// <param name="type">The wire format type of the tag to write</param>

+        public void WriteTag(int fieldNumber, WireFormat.WireType type)

+        {

+            WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));

+        }

+

+        /// <summary>

+        /// Writes an already-encoded tag.

+        /// </summary>

+        /// <param name="tag">The encoded tag</param>

+        public void WriteTag(uint tag)

+        {

+            WriteRawVarint32(tag);

+        }

+

+        /// <summary>

+        /// Writes the given single-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The encoded tag</param>

+        public void WriteRawTag(byte b1)

+        {

+            WriteRawByte(b1);

+        }

+

+        /// <summary>

+        /// Writes the given two-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+        }

+

+        /// <summary>

+        /// Writes the given three-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        /// <param name="b3">The third byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2, byte b3)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+            WriteRawByte(b3);

+        }

+

+        /// <summary>

+        /// Writes the given four-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        /// <param name="b3">The third byte of the encoded tag</param>

+        /// <param name="b4">The fourth byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+            WriteRawByte(b3);

+            WriteRawByte(b4);

+        }

+

+        /// <summary>

+        /// Writes the given five-byte tag directly to the stream.

+        /// </summary>

+        /// <param name="b1">The first byte of the encoded tag</param>

+        /// <param name="b2">The second byte of the encoded tag</param>

+        /// <param name="b3">The third byte of the encoded tag</param>

+        /// <param name="b4">The fourth byte of the encoded tag</param>

+        /// <param name="b5">The fifth byte of the encoded tag</param>

+        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)

+        {

+            WriteRawByte(b1);

+            WriteRawByte(b2);

+            WriteRawByte(b3);

+            WriteRawByte(b4);

+            WriteRawByte(b5);

+        }

+        #endregion

+

+        #region Underlying writing primitives

+        /// <summary>

+        /// Writes a 32 bit value as a varint. The fast route is taken when

+        /// there's enough buffer space left to whizz through without checking

+        /// for each byte; otherwise, we resort to calling WriteRawByte each time.

+        /// </summary>

+        internal void WriteRawVarint32(uint value)

+        {

+            // Optimize for the common case of a single byte value

+            if (value < 128 && position < limit)

+            {

+                buffer[position++] = (byte)value;

+                return;

+            }

+

+            while (value > 127 && position < limit)

+            {

+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);

+                value >>= 7;

+            }

+            while (value > 127)

+            {

+                WriteRawByte((byte) ((value & 0x7F) | 0x80));

+                value >>= 7;

+            }

+            if (position < limit)

+            {

+                buffer[position++] = (byte) value;

+            }

+            else

+            {

+                WriteRawByte((byte) value);

+            }

+        }

+

+        internal void WriteRawVarint64(ulong value)

+        {

+            while (value > 127 && position < limit)

+            {

+                buffer[position++] = (byte) ((value & 0x7F) | 0x80);

+                value >>= 7;

+            }

+            while (value > 127)

+            {

+                WriteRawByte((byte) ((value & 0x7F) | 0x80));

+                value >>= 7;

+            }

+            if (position < limit)

+            {

+                buffer[position++] = (byte) value;

+            }

+            else

+            {

+                WriteRawByte((byte) value);

+            }

+        }

+

+        internal void WriteRawLittleEndian32(uint value)

+        {

+            if (position + 4 > limit)

+            {

+                WriteRawByte((byte) value);

+                WriteRawByte((byte) (value >> 8));

+                WriteRawByte((byte) (value >> 16));

+                WriteRawByte((byte) (value >> 24));

+            }

+            else

+            {

+                buffer[position++] = ((byte) value);

+                buffer[position++] = ((byte) (value >> 8));

+                buffer[position++] = ((byte) (value >> 16));

+                buffer[position++] = ((byte) (value >> 24));

+            }

+        }

+

+        internal void WriteRawLittleEndian64(ulong value)

+        {

+            if (position + 8 > limit)

+            {

+                WriteRawByte((byte) value);

+                WriteRawByte((byte) (value >> 8));

+                WriteRawByte((byte) (value >> 16));

+                WriteRawByte((byte) (value >> 24));

+                WriteRawByte((byte) (value >> 32));

+                WriteRawByte((byte) (value >> 40));

+                WriteRawByte((byte) (value >> 48));

+                WriteRawByte((byte) (value >> 56));

+            }

+            else

+            {

+                buffer[position++] = ((byte) value);

+                buffer[position++] = ((byte) (value >> 8));

+                buffer[position++] = ((byte) (value >> 16));

+                buffer[position++] = ((byte) (value >> 24));

+                buffer[position++] = ((byte) (value >> 32));

+                buffer[position++] = ((byte) (value >> 40));

+                buffer[position++] = ((byte) (value >> 48));

+                buffer[position++] = ((byte) (value >> 56));

+            }

+        }

+

+        internal void WriteRawByte(byte value)

+        {

+            if (position == limit)

+            {

+                RefreshBuffer();

+            }

+

+            buffer[position++] = value;

+        }

+

+        internal void WriteRawByte(uint value)

+        {

+            WriteRawByte((byte) value);

+        }

+

+        /// <summary>

+        /// Writes out an array of bytes.

+        /// </summary>

+        internal void WriteRawBytes(byte[] value)

+        {

+            WriteRawBytes(value, 0, value.Length);

+        }

+

+        /// <summary>

+        /// Writes out part of an array of bytes.

+        /// </summary>

+        internal void WriteRawBytes(byte[] value, int offset, int length)

+        {

+            if (limit - position >= length)

+            {

+                ByteArray.Copy(value, offset, buffer, position, length);

+                // We have room in the current buffer.

+                position += length;

+            }

+            else

+            {

+                // Write extends past current buffer.  Fill the rest of this buffer and

+                // flush.

+                int bytesWritten = limit - position;

+                ByteArray.Copy(value, offset, buffer, position, bytesWritten);

+                offset += bytesWritten;

+                length -= bytesWritten;

+                position = limit;

+                RefreshBuffer();

+

+                // Now deal with the rest.

+                // Since we have an output stream, this is our buffer

+                // and buffer offset == 0

+                if (length <= limit)

+                {

+                    // Fits in new buffer.

+                    ByteArray.Copy(value, offset, buffer, 0, length);

+                    position = length;

+                }

+                else

+                {

+                    // Write is very big.  Let's do it all at once.

+                    output.Write(value, offset, length);

+                }

+            }

+        }

+

+        #endregion

+

+        /// <summary>

+        /// Encode a 32-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static uint EncodeZigZag32(int n)

+        {

+            // Note:  the right-shift must be arithmetic

+            return (uint) ((n << 1) ^ (n >> 31));

+        }

+

+        /// <summary>

+        /// Encode a 64-bit value with ZigZag encoding.

+        /// </summary>

+        /// <remarks>

+        /// ZigZag encodes signed integers into values that can be efficiently

+        /// encoded with varint.  (Otherwise, negative values must be 

+        /// sign-extended to 64 bits to be varint encoded, thus always taking

+        /// 10 bytes on the wire.)

+        /// </remarks>

+        internal static ulong EncodeZigZag64(long n)

+        {

+            return (ulong) ((n << 1) ^ (n >> 63));

+        }

+

+        private void RefreshBuffer()

+        {

+            if (output == null)

+            {

+                // We're writing to a single buffer.

+                throw new OutOfSpaceException();

+            }

+

+            // Since we have an output stream, this is our buffer

+            // and buffer offset == 0

+            output.Write(buffer, 0, position);

+            position = 0;

+        }

+

+        /// <summary>

+        /// Indicates that a CodedOutputStream wrapping a flat byte array

+        /// ran out of space.

+        /// </summary>

+        public sealed class OutOfSpaceException : IOException

+        {

+            internal OutOfSpaceException()

+                : base("CodedOutputStream was writing to a flat byte array and ran out of space.")

+            {

+            }

+        }

+

+        /// <summary>

+        /// Flushes any buffered data to the underlying stream (if there is one).

+        /// </summary>

+        public void Flush()

+        {

+            if (output != null)

+            {

+                RefreshBuffer();

+            }

+        }

+

+        /// <summary>

+        /// Verifies that SpaceLeft returns zero. It's common to create a byte array

+        /// that is exactly big enough to hold a message, then write to it with

+        /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that

+        /// the message was actually as big as expected, which can help bugs.

+        /// </summary>

+        public void CheckNoSpaceLeft()

+        {

+            if (SpaceLeft != 0)

+            {

+                throw new InvalidOperationException("Did not write as much data as expected.");

+            }

+        }

+

+        /// <summary>

+        /// If writing to a flat array, returns the space left in the array. Otherwise,

+        /// throws an InvalidOperationException.

+        /// </summary>

+        public int SpaceLeft

+        {

+            get

+            {

+                if (output == null)

+                {

+                    return limit - position;

+                }

+                else

+                {

+                    throw new InvalidOperationException(

+                        "SpaceLeft can only be called on CodedOutputStreams that are " +

+                        "writing to a flat array.");

+                }

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
new file mode 100644
index 0000000..90a5ff1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -0,0 +1,759 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Reflection;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// Representation of a map field in a Protocol Buffer message.
+    /// </summary>
+    /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
+    /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
+    /// <remarks>
+    /// <para>
+    /// This implementation preserves insertion order for simplicity of testing
+    /// code using maps fields. Overwriting an existing entry does not change the
+    /// position of that entry within the map. Equality is not order-sensitive.
+    /// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
+    /// </para>
+    /// <para>
+    /// Null values are not permitted in the map, either for wrapper types or regular messages.
+    /// If a map is deserialized from a data stream and the value is missing from an entry, a default value
+    /// is created instead. For primitive types, that is the regular default value (0, the empty string and so
+    /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
+    /// encoded value for the field.
+    /// </para>
+    /// <para>
+    /// This implementation does not generally prohibit the use of key/value types which are not
+    /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
+    /// that all operations will work in such cases.
+    /// </para>
+    /// </remarks>
+    public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
+    {
+        // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
+        private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
+            new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
+        private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
+
+        /// <summary>
+        /// Creates a deep clone of this object.
+        /// </summary>
+        /// <returns>
+        /// A deep clone of this object.
+        /// </returns>
+        public MapField<TKey, TValue> Clone()
+        {
+            var clone = new MapField<TKey, TValue>();
+            // Keys are never cloneable. Values might be.
+            if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
+            {
+                foreach (var pair in list)
+                {
+                    clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());
+                }
+            }
+            else
+            {
+                // Nothing is cloneable, so we don't need to worry.
+                clone.Add(this);
+            }
+            return clone;
+        }
+
+        /// <summary>
+        /// Adds the specified key/value pair to the map.
+        /// </summary>
+        /// <remarks>
+        /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer.
+        /// </remarks>
+        /// <param name="key">The key to add</param>
+        /// <param name="value">The value to add.</param>
+        /// <exception cref="System.ArgumentException">The given key already exists in map.</exception>
+        public void Add(TKey key, TValue value)
+        {
+            // Validation of arguments happens in ContainsKey and the indexer
+            if (ContainsKey(key))
+            {
+                throw new ArgumentException("Key already exists in map", "key");
+            }
+            this[key] = value;
+        }
+
+        /// <summary>
+        /// Determines whether the specified key is present in the map.
+        /// </summary>
+        /// <param name="key">The key to check.</param>
+        /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
+        public bool ContainsKey(TKey key)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+            return map.ContainsKey(key);
+        }
+
+        private bool ContainsValue(TValue value)
+        {
+            var comparer = EqualityComparer<TValue>.Default;
+            return list.Any(pair => comparer.Equals(pair.Value, value));
+        }
+
+        /// <summary>
+        /// Removes the entry identified by the given key from the map.
+        /// </summary>
+        /// <param name="key">The key indicating the entry to remove from the map.</param>
+        /// <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>
+        public bool Remove(TKey key)
+        {
+            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(key, out node))
+            {
+                map.Remove(key);
+                node.List.Remove(node);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets the value associated with the specified key.
+        /// </summary>
+        /// <param name="key">The key whose value to get.</param>
+        /// <param name="value">When this method returns, the value associated with the specified key, if the key is found;
+        /// otherwise, the default value for the type of the <paramref name="value"/> parameter.
+        /// This parameter is passed uninitialized.</param>
+        /// <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>
+        public bool TryGetValue(TKey key, out TValue value)
+        {
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(key, out node))
+            {
+                value = node.Value.Value;
+                return true;
+            }
+            else
+            {
+                value = default(TValue);
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the value associated with the specified key.
+        /// </summary>
+        /// <param name="key">The key of the value to get or set.</param>
+        /// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
+        /// <returns>The value associated with the specified key. If the specified key is not found,
+        /// a get operation throws a <see cref="KeyNotFoundException"/>, and a set operation creates a new element with the specified key.</returns>
+        public TValue this[TKey key]
+        {
+            get
+            {
+                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+                TValue value;
+                if (TryGetValue(key, out value))
+                {
+                    return value;
+                }
+                throw new KeyNotFoundException();
+            }
+            set
+            {
+                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+                // value == null check here is redundant, but avoids boxing.
+                if (value == null)
+                {
+                    ProtoPreconditions.CheckNotNullUnconstrained(value, "value");
+                }
+                LinkedListNode<KeyValuePair<TKey, TValue>> node;
+                var pair = new KeyValuePair<TKey, TValue>(key, value);
+                if (map.TryGetValue(key, out node))
+                {
+                    node.Value = pair;
+                }
+                else
+                {
+                    node = list.AddLast(pair);
+                    map[key] = node;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a collection containing the keys in the map.
+        /// </summary>
+        public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } }
+
+        /// <summary>
+        /// Gets a collection containing the values in the map.
+        /// </summary>
+        public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
+
+        /// <summary>
+        /// Adds the specified entries to the map. The keys and values are not automatically cloned.
+        /// </summary>
+        /// <param name="entries">The entries to add to the map.</param>
+        public void Add(IDictionary<TKey, TValue> entries)
+        {
+            ProtoPreconditions.CheckNotNull(entries, "entries");
+            foreach (var pair in entries)
+            {
+                Add(pair.Key, pair.Value);
+            }
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the collection.
+        /// </summary>
+        /// <returns>
+        /// An enumerator that can be used to iterate through the collection.
+        /// </returns>
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+        {
+            return list.GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
+        /// </returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Adds the specified item to the map.
+        /// </summary>
+        /// <param name="item">The item to add to the map.</param>
+        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
+        {
+            Add(item.Key, item.Value);
+        }
+
+        /// <summary>
+        /// Removes all items from the map.
+        /// </summary>
+        public void Clear()
+        {
+            list.Clear();
+            map.Clear();
+        }
+
+        /// <summary>
+        /// Determines whether map contains an entry equivalent to the given key/value pair.
+        /// </summary>
+        /// <param name="item">The key/value pair to find.</param>
+        /// <returns></returns>
+        bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+        {
+            TValue value;
+            return TryGetValue(item.Key, out value)
+                && EqualityComparer<TValue>.Default.Equals(item.Value, value);
+        }
+
+        /// <summary>
+        /// Copies the key/value pairs in this map to an array.
+        /// </summary>
+        /// <param name="array">The array to copy the entries into.</param>
+        /// <param name="arrayIndex">The index of the array at which to start copying values.</param>
+        void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+        {
+            list.CopyTo(array, arrayIndex);
+        }
+
+        /// <summary>
+        /// Removes the specified key/value pair from the map.
+        /// </summary>
+        /// <remarks>Both the key and the value must be found for the entry to be removed.</remarks>
+        /// <param name="item">The key/value pair to remove.</param>
+        /// <returns><c>true</c> if the key/value pair was found and removed; <c>false</c> otherwise.</returns>
+        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
+        {
+            if (item.Key == null)
+            {
+                throw new ArgumentException("Key is null", "item");
+            }
+            LinkedListNode<KeyValuePair<TKey, TValue>> node;
+            if (map.TryGetValue(item.Key, out node) &&
+                EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.Value))
+            {
+                map.Remove(item.Key);
+                node.List.Remove(node);
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// Gets the number of elements contained in the map.
+        /// </summary>
+        public int Count { get { return list.Count; } }
+
+        /// <summary>
+        /// Gets a value indicating whether the map is read-only.
+        /// </summary>
+        public bool IsReadOnly { get { return false; } }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
+        /// </summary>
+        /// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>
+        /// <returns>
+        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object other)
+        {
+            return Equals(other as MapField<TKey, TValue>);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            var valueComparer = EqualityComparer<TValue>.Default;
+            int hash = 0;
+            foreach (var pair in list)
+            {
+                hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value);
+            }
+            return hash;
+        }
+
+        /// <summary>
+        /// Compares this map with another for equality.
+        /// </summary>
+        /// <remarks>
+        /// The order of the key/value pairs in the maps is not deemed significant in this comparison.
+        /// </remarks>
+        /// <param name="other">The map to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
+        public bool Equals(MapField<TKey, TValue> other)
+        {
+            if (other == null)
+            {
+                return false;
+            }
+            if (other == this)
+            {
+                return true;
+            }
+            if (other.Count != this.Count)
+            {
+                return false;
+            }
+            var valueComparer = EqualityComparer<TValue>.Default;
+            foreach (var pair in this)
+            {
+                TValue value;
+                if (!other.TryGetValue(pair.Key, out value))
+                {
+                    return false;
+                }
+                if (!valueComparer.Equals(value, pair.Value))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Adds entries to the map from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// It is assumed that the stream is initially positioned after the tag specified by the codec.
+        /// This method will continue reading entries from the stream until the end is reached, or
+        /// a different tag is encountered.
+        /// </remarks>
+        /// <param name="input">Stream to read from</param>
+        /// <param name="codec">Codec describing how the key/value pairs are encoded</param>
+        public void AddEntriesFrom(CodedInputStream input, Codec codec)
+        {
+            var adapter = new Codec.MessageAdapter(codec);
+            do
+            {
+                adapter.Reset();
+                input.ReadMessage(adapter);
+                this[adapter.Key] = adapter.Value;
+            } while (input.MaybeConsumeTag(codec.MapTag));
+        }
+
+        /// <summary>
+        /// Writes the contents of this map to the given coded output stream, using the specified codec
+        /// to encode each entry.
+        /// </summary>
+        /// <param name="output">The output stream to write to.</param>
+        /// <param name="codec">The codec to use for each entry.</param>
+        public void WriteTo(CodedOutputStream output, Codec codec)
+        {
+            var message = new Codec.MessageAdapter(codec);
+            foreach (var entry in list)
+            {
+                message.Key = entry.Key;
+                message.Value = entry.Value;
+                output.WriteTag(codec.MapTag);
+                output.WriteMessage(message);
+            }
+        }
+
+        /// <summary>
+        /// Calculates the size of this map based on the given entry codec.
+        /// </summary>
+        /// <param name="codec">The codec to use to encode each entry.</param>
+        /// <returns></returns>
+        public int CalculateSize(Codec codec)
+        {
+            if (Count == 0)
+            {
+                return 0;
+            }
+            var message = new Codec.MessageAdapter(codec);
+            int size = 0;
+            foreach (var entry in list)
+            {
+                message.Key = entry.Key;
+                message.Value = entry.Value;
+                size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
+                size += CodedOutputStream.ComputeMessageSize(message);
+            }
+            return size;
+        }
+
+        /// <summary>
+        /// Returns a string representation of this repeated field, in the same
+        /// way as it would be represented by the default JSON formatter.
+        /// </summary>
+        public override string ToString()
+        {
+            var builder = new StringBuilder();
+            JsonFormatter.Default.WriteDictionary(builder, this);
+            return builder.ToString();
+        }
+
+        #region IDictionary explicit interface implementation
+        void IDictionary.Add(object key, object value)
+        {
+            Add((TKey)key, (TValue)value);
+        }
+
+        bool IDictionary.Contains(object key)
+        {
+            if (!(key is TKey))
+            {
+                return false;
+            }
+            return ContainsKey((TKey)key);
+        }
+
+        IDictionaryEnumerator IDictionary.GetEnumerator()
+        {
+            return new DictionaryEnumerator(GetEnumerator());
+        }
+
+        void IDictionary.Remove(object key)
+        {
+            ProtoPreconditions.CheckNotNull(key, "key");
+            if (!(key is TKey))
+            {
+                return;
+            }
+            Remove((TKey)key);
+        }
+
+        void ICollection.CopyTo(Array array, int index)
+        {
+            // This is ugly and slow as heck, but with any luck it will never be used anyway.
+            ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
+            temp.CopyTo(array, index);
+        }
+
+        bool IDictionary.IsFixedSize { get { return false; } }
+
+        ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
+
+        ICollection IDictionary.Values { get { return (ICollection)Values; } }
+
+        bool ICollection.IsSynchronized { get { return false; } }
+
+        object ICollection.SyncRoot { get { return this; } }
+
+        object IDictionary.this[object key]
+        {
+            get
+            {
+                ProtoPreconditions.CheckNotNull(key, "key");
+                if (!(key is TKey))
+                {
+                    return null;
+                }
+                TValue value;
+                TryGetValue((TKey)key, out value);
+                return value;
+            }
+
+            set
+            {
+                this[(TKey)key] = (TValue)value;
+            }
+        }
+        #endregion
+
+        private class DictionaryEnumerator : IDictionaryEnumerator
+        {
+            private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
+
+            internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
+            {
+                this.enumerator = enumerator;
+            }
+
+            public bool MoveNext()
+            {
+                return enumerator.MoveNext();
+            }
+
+            public void Reset()
+            {
+                enumerator.Reset();
+            }
+
+            public object Current { get { return Entry; } }
+            public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
+            public object Key { get { return enumerator.Current.Key; } }
+            public object Value { get { return enumerator.Current.Value; } }
+        }
+
+        /// <summary>
+        /// A codec for a specific map field. This contains all the information required to encode and
+        /// decode the nested messages.
+        /// </summary>
+        public sealed class Codec
+        {
+            private readonly FieldCodec<TKey> keyCodec;
+            private readonly FieldCodec<TValue> valueCodec;
+            private readonly uint mapTag;
+
+            /// <summary>
+            /// Creates a new entry codec based on a separate key codec and value codec,
+            /// and the tag to use for each map entry.
+            /// </summary>
+            /// <param name="keyCodec">The key codec.</param>
+            /// <param name="valueCodec">The value codec.</param>
+            /// <param name="mapTag">The map tag to use to introduce each map entry.</param>
+            public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCodec, uint mapTag)
+            {
+                this.keyCodec = keyCodec;
+                this.valueCodec = valueCodec;
+                this.mapTag = mapTag;
+            }
+
+            /// <summary>
+            /// The tag used in the enclosing message to indicate map entries.
+            /// </summary>
+            internal uint MapTag { get { return mapTag; } }
+
+            /// <summary>
+            /// A mutable message class, used for parsing and serializing. This
+            /// delegates the work to a codec, but implements the <see cref="IMessage"/> interface
+            /// for interop with <see cref="CodedInputStream"/> and <see cref="CodedOutputStream"/>.
+            /// This is nested inside Codec as it's tightly coupled to the associated codec,
+            /// and it's simpler if it has direct access to all its fields.
+            /// </summary>
+            internal class MessageAdapter : IMessage
+            {
+                private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 };
+
+                private readonly Codec codec;
+                internal TKey Key { get; set; }
+                internal TValue Value { get; set; }
+
+                internal MessageAdapter(Codec codec)
+                {
+                    this.codec = codec;
+                }
+
+                internal void Reset()
+                {
+                    Key = codec.keyCodec.DefaultValue;
+                    Value = codec.valueCodec.DefaultValue;
+                }
+
+                public void MergeFrom(CodedInputStream input)
+                {
+                    uint tag;
+                    while ((tag = input.ReadTag()) != 0)
+                    {
+                        if (tag == codec.keyCodec.Tag)
+                        {
+                            Key = codec.keyCodec.Read(input);
+                        }
+                        else if (tag == codec.valueCodec.Tag)
+                        {
+                            Value = codec.valueCodec.Read(input);
+                        }
+                        else 
+                        {
+                            input.SkipLastField();
+                        }
+                    }
+
+                    // Corner case: a map entry with a key but no value, where the value type is a message.
+                    // Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
+                    if (Value == null)
+                    {
+                        Value = codec.valueCodec.Read(new CodedInputStream(ZeroLengthMessageStreamData));
+                    }
+                }
+
+                public void WriteTo(CodedOutputStream output)
+                {
+                    codec.keyCodec.WriteTagAndValue(output, Key);
+                    codec.valueCodec.WriteTagAndValue(output, Value);
+                }
+
+                public int CalculateSize()
+                {
+                    return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valueCodec.CalculateSizeWithTag(Value);
+                }
+
+                MessageDescriptor IMessage.Descriptor { get { return null; } }
+            }
+        }
+
+        private class MapView<T> : ICollection<T>, ICollection
+        {
+            private readonly MapField<TKey, TValue> parent;
+            private readonly Func<KeyValuePair<TKey, TValue>, T> projection;
+            private readonly Func<T, bool> containsCheck;
+
+            internal MapView(
+                MapField<TKey, TValue> parent,
+                Func<KeyValuePair<TKey, TValue>, T> projection,
+                Func<T, bool> containsCheck)
+            {
+                this.parent = parent;
+                this.projection = projection;
+                this.containsCheck = containsCheck;
+            }
+
+            public int Count { get { return parent.Count; } }
+
+            public bool IsReadOnly { get { return true; } }
+
+            public bool IsSynchronized { get { return false; } }
+
+            public object SyncRoot { get { return parent; } }
+
+            public void Add(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            public void Clear()
+            {
+                throw new NotSupportedException();
+            }
+
+            public bool Contains(T item)
+            {
+                return containsCheck(item);
+            }
+
+            public void CopyTo(T[] array, int arrayIndex)
+            {
+                if (arrayIndex < 0)
+                {
+                    throw new ArgumentOutOfRangeException("arrayIndex");
+                }
+                if (arrayIndex + Count  >= array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", "array");
+                }
+                foreach (var item in this)
+                {
+                    array[arrayIndex++] = item;
+                }
+            }
+
+            public IEnumerator<T> GetEnumerator()
+            {
+                return parent.list.Select(projection).GetEnumerator();
+            }
+
+            public bool Remove(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                return GetEnumerator();
+            }
+
+            public void CopyTo(Array array, int index)
+            {
+                if (index < 0)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                if (index + Count >= array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", "array");
+                }
+                foreach (var item in this)
+                {
+                    array.SetValue(item, index++);
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs b/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs
new file mode 100644
index 0000000..8436066
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs
@@ -0,0 +1,147 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+using System.Collections;

+using System.Collections.Generic;

+

+namespace Google.Protobuf.Collections

+{

+    /// <summary>

+    /// Read-only wrapper around another dictionary.

+    /// </summary>

+    internal sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>

+    {

+        private readonly IDictionary<TKey, TValue> wrapped;

+

+        public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped)

+        {

+            this.wrapped = wrapped;

+        }

+

+        public void Add(TKey key, TValue value)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public bool ContainsKey(TKey key)

+        {

+            return wrapped.ContainsKey(key);

+        }

+

+        public ICollection<TKey> Keys

+        {

+            get { return wrapped.Keys; }

+        }

+

+        public bool Remove(TKey key)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public bool TryGetValue(TKey key, out TValue value)

+        {

+            return wrapped.TryGetValue(key, out value);

+        }

+

+        public ICollection<TValue> Values

+        {

+            get { return wrapped.Values; }

+        }

+

+        public TValue this[TKey key]

+        {

+            get { return wrapped[key]; }

+            set { throw new InvalidOperationException(); }

+        }

+

+        public void Add(KeyValuePair<TKey, TValue> item)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public void Clear()

+        {

+            throw new InvalidOperationException();

+        }

+

+        public bool Contains(KeyValuePair<TKey, TValue> item)

+        {

+            return wrapped.Contains(item);

+        }

+

+        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)

+        {

+            wrapped.CopyTo(array, arrayIndex);

+        }

+

+        public int Count

+        {

+            get { return wrapped.Count; }

+        }

+

+        public bool IsReadOnly

+        {

+            get { return true; }

+        }

+

+        public bool Remove(KeyValuePair<TKey, TValue> item)

+        {

+            throw new InvalidOperationException();

+        }

+

+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()

+        {

+            return wrapped.GetEnumerator();

+        }

+

+        IEnumerator IEnumerable.GetEnumerator()

+        {

+            return ((IEnumerable) wrapped).GetEnumerator();

+        }

+

+        public override bool Equals(object obj)

+        {

+            return wrapped.Equals(obj);

+        }

+

+        public override int GetHashCode()

+        {

+            return wrapped.GetHashCode();

+        }

+

+        public override string ToString()

+        {

+            return wrapped.ToString();

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
new file mode 100644
index 0000000..1cde03b
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -0,0 +1,567 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.Protobuf.Collections
+{
+    /// <summary>
+    /// The contents of a repeated field: essentially, a collection with some extra
+    /// restrictions (no null values) and capabilities (deep cloning).
+    /// </summary>
+    /// <remarks>
+    /// This implementation does not generally prohibit the use of types which are not
+    /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
+    /// </remarks>
+    /// <typeparam name="T">The element type of the repeated field.</typeparam>
+    public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>
+    {
+        private static readonly T[] EmptyArray = new T[0];
+        private const int MinArraySize = 8;
+
+        private T[] array = EmptyArray;
+        private int count = 0;
+
+        /// <summary>
+        /// Creates a deep clone of this repeated field.
+        /// </summary>
+        /// <remarks>
+        /// If the field type is
+        /// a message type, each element is also cloned; otherwise, it is
+        /// assumed that the field type is primitive (including string and
+        /// bytes, both of which are immutable) and so a simple copy is
+        /// equivalent to a deep clone.
+        /// </remarks>
+        /// <returns>A deep clone of this repeated field.</returns>
+        public RepeatedField<T> Clone()
+        {
+            RepeatedField<T> clone = new RepeatedField<T>();
+            if (array != EmptyArray)
+            {
+                clone.array = (T[])array.Clone();
+                IDeepCloneable<T>[] cloneableArray = clone.array as IDeepCloneable<T>[];
+                if (cloneableArray != null)
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        clone.array[i] = cloneableArray[i].Clone();
+                    }
+                }
+            }
+            clone.count = count;
+            return clone;
+        }
+
+        /// <summary>
+        /// Adds the entries from the given input stream, decoding them with the specified codec.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <param name="codec">The codec to use in order to read each entry.</param>
+        public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
+        {
+            // TODO: Inline some of the Add code, so we can avoid checking the size on every
+            // iteration.
+            uint tag = input.LastTag;
+            var reader = codec.ValueReader;
+            // Non-nullable value types can be packed or not.
+            if (FieldCodec<T>.IsPackedRepeatedField(tag))
+            {
+                int length = input.ReadLength();
+                if (length > 0)
+                {
+                    int oldLimit = input.PushLimit(length);
+                    while (!input.ReachedLimit)
+                    {
+                        Add(reader(input));
+                    }
+                    input.PopLimit(oldLimit);
+                }
+                // Empty packed field. Odd, but valid - just ignore.
+            }
+            else
+            {
+                // Not packed... (possibly not packable)
+                do
+                {
+                    Add(reader(input));
+                } while (input.MaybeConsumeTag(tag));
+            }
+        }
+
+        /// <summary>
+        /// Calculates the size of this collection based on the given codec.
+        /// </summary>
+        /// <param name="codec">The codec to use when encoding each field.</param>
+        /// <returns>The number of bytes that would be written to a <see cref="CodedOutputStream"/> by <see cref="WriteTo"/>,
+        /// using the same codec.</returns>
+        public int CalculateSize(FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return 0;
+            }
+            uint tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                int dataSize = CalculatePackedDataSize(codec);
+                return CodedOutputStream.ComputeRawVarint32Size(tag) +
+                    CodedOutputStream.ComputeLengthSize(dataSize) +
+                    dataSize;
+            }
+            else
+            {
+                var sizeCalculator = codec.ValueSizeCalculator;
+                int size = count * CodedOutputStream.ComputeRawVarint32Size(tag);
+                for (int i = 0; i < count; i++)
+                {
+                    size += sizeCalculator(array[i]);
+                }
+                return size;
+            }
+        }
+
+        private int CalculatePackedDataSize(FieldCodec<T> codec)
+        {
+            int fixedSize = codec.FixedSize;
+            if (fixedSize == 0)
+            {
+                var calculator = codec.ValueSizeCalculator;
+                int tmp = 0;
+                for (int i = 0; i < count; i++)
+                {
+                    tmp += calculator(array[i]);
+                }
+                return tmp;
+            }
+            else
+            {
+                return fixedSize * Count;
+            }
+        }
+
+        /// <summary>
+        /// Writes the contents of this collection to the given <see cref="CodedOutputStream"/>,
+        /// encoding each value using the specified codec.
+        /// </summary>
+        /// <param name="output">The output stream to write to.</param>
+        /// <param name="codec">The codec to use when encoding each value.</param>
+        public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
+        {
+            if (count == 0)
+            {
+                return;
+            }
+            var writer = codec.ValueWriter;
+            var tag = codec.Tag;
+            if (codec.PackedRepeatedField)
+            {
+                // Packed primitive type
+                uint size = (uint)CalculatePackedDataSize(codec);
+                output.WriteTag(tag);
+                output.WriteRawVarint32(size);
+                for (int i = 0; i < count; i++)
+                {
+                    writer(output, array[i]);
+                }
+            }
+            else
+            {
+                // Not packed: a simple tag/value pair for each value.
+                // Can't use codec.WriteTagAndValue, as that omits default values.
+                for (int i = 0; i < count; i++)
+                {
+                    output.WriteTag(tag);
+                    writer(output, array[i]);
+                }
+            }
+        }
+
+        private void EnsureSize(int size)
+        {
+            if (array.Length < size)
+            {
+                size = Math.Max(size, MinArraySize);
+                int newSize = Math.Max(array.Length * 2, size);
+                var tmp = new T[newSize];
+                Array.Copy(array, 0, tmp, 0, array.Length);
+                array = tmp;
+            }
+        }
+
+        /// <summary>
+        /// Adds the specified item to the collection.
+        /// </summary>
+        /// <param name="item">The item to add.</param>
+        public void Add(T item)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+            EnsureSize(count + 1);
+            array[count++] = item;
+        }
+
+        /// <summary>
+        /// Removes all items from the collection.
+        /// </summary>
+        public void Clear()
+        {
+            array = EmptyArray;
+            count = 0;
+        }
+
+        /// <summary>
+        /// Determines whether this collection contains the given item.
+        /// </summary>
+        /// <param name="item">The item to find.</param>
+        /// <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
+        public bool Contains(T item)
+        {
+            return IndexOf(item) != -1;
+        }
+
+        /// <summary>
+        /// Copies this collection to the given array.
+        /// </summary>
+        /// <param name="array">The array to copy to.</param>
+        /// <param name="arrayIndex">The first index of the array to copy to.</param>
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            Array.Copy(this.array, 0, array, arrayIndex, count);
+        }
+
+        /// <summary>
+        /// Removes the specified item from the collection
+        /// </summary>
+        /// <param name="item">The item to remove.</param>
+        /// <returns><c>true</c> if the item was found and removed; <c>false</c> otherwise.</returns>
+        public bool Remove(T item)
+        {
+            int index = IndexOf(item);
+            if (index == -1)
+            {
+                return false;
+            }            
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+            return true;
+        }
+
+        /// <summary>
+        /// Gets the number of elements contained in the collection.
+        /// </summary>
+        public int Count { get { return count; } }
+
+        /// <summary>
+        /// Gets a value indicating whether the collection is read-only.
+        /// </summary>
+        public bool IsReadOnly { get { return false; } }
+
+        // TODO: Remove this overload and just handle it in the one below, at execution time?
+
+        /// <summary>
+        /// Adds all of the specified values into this collection.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void Add(RepeatedField<T> values)
+        {
+            if (values == null)
+            {
+                throw new ArgumentNullException("values");
+            }
+            EnsureSize(count + values.count);
+            // We know that all the values will be valid, because it's a RepeatedField.
+            Array.Copy(values.array, 0, array, count, values.count);
+            count += values.count;
+        }
+
+        /// <summary>
+        /// Adds all of the specified values into this collection.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void Add(IEnumerable<T> values)
+        {
+            if (values == null)
+            {
+                throw new ArgumentNullException("values");
+            }
+            // TODO: Check for ICollection and get the Count, to optimize?
+            foreach (T item in values)
+            {
+                Add(item);
+            }
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the collection.
+        /// </summary>
+        /// <returns>
+        /// An enumerator that can be used to iterate through the collection.
+        /// </returns>
+        public IEnumerator<T> GetEnumerator()
+        {
+            for (int i = 0; i < count; i++)
+            {
+                yield return array[i];
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
+        /// </summary>
+        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
+        /// <returns>
+        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as RepeatedField<T>);
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
+        /// </returns>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public override int GetHashCode()
+        {
+            int hash = 0;
+            for (int i = 0; i < count; i++)
+            {
+                hash = hash * 31 + array[i].GetHashCode();
+            }
+            return hash;
+        }
+
+        /// <summary>
+        /// Compares this repeated field with another for equality.
+        /// </summary>
+        /// <param name="other">The repeated field to compare this with.</param>
+        /// <returns><c>true</c> if <paramref name="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
+        public bool Equals(RepeatedField<T> other)
+        {
+            if (ReferenceEquals(other, null))
+            {
+                return false;
+            }
+            if (ReferenceEquals(other, this))
+            {
+                return true;
+            }
+            if (other.Count != this.Count)
+            {
+                return false;
+            }
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (!comparer.Equals(array[i], other.array[i]))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns the index of the given item within the collection, or -1 if the item is not
+        /// present.
+        /// </summary>
+        /// <param name="item">The item to find in the collection.</param>
+        /// <returns>The zero-based index of the item, or -1 if it is not found.</returns>
+        public int IndexOf(T item)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
+            for (int i = 0; i < count; i++)
+            {
+                if (comparer.Equals(array[i], item))
+                {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /// <summary>
+        /// Inserts the given item at the specified index.
+        /// </summary>
+        /// <param name="index">The index at which to insert the item.</param>
+        /// <param name="item">The item to insert.</param>
+        public void Insert(int index, T item)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+            if (index < 0 || index > count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            EnsureSize(count + 1);
+            Array.Copy(array, index, array, index + 1, count - index);
+            array[index] = item;
+            count++;
+        }
+
+        /// <summary>
+        /// Removes the item at the given index.
+        /// </summary>
+        /// <param name="index">The zero-based index of the item to remove.</param>
+        public void RemoveAt(int index)
+        {
+            if (index < 0 || index >= count)
+            {
+                throw new ArgumentOutOfRangeException("index");
+            }
+            Array.Copy(array, index + 1, array, index, count - index - 1);
+            count--;
+            array[count] = default(T);
+        }
+
+        /// <summary>
+        /// Returns a string representation of this repeated field, in the same
+        /// way as it would be represented by the default JSON formatter.
+        /// </summary>
+        public override string ToString()
+        {
+            var builder = new StringBuilder();
+            JsonFormatter.Default.WriteList(builder, this);
+            return builder.ToString();
+        }
+
+        /// <summary>
+        /// Gets or sets the item at the specified index.
+        /// </summary>
+        /// <value>
+        /// The element at the specified index.
+        /// </value>
+        /// <param name="index">The zero-based index of the element to get or set.</param>
+        /// <returns>The item at the specified index.</returns>
+        public T this[int index]
+        {
+            get
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                return array[index];
+            }
+            set
+            {
+                if (index < 0 || index >= count)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                if (value == null)
+                {
+                    throw new ArgumentNullException("value");
+                }
+                array[index] = value;
+            }
+        }
+
+        #region Explicit interface implementation for IList and ICollection.
+        bool IList.IsFixedSize { get { return false; } }
+
+        void ICollection.CopyTo(Array array, int index)
+        {
+            Array.Copy(this.array, 0, array, index, count);
+        }
+
+        bool ICollection.IsSynchronized { get { return false; } }
+
+        object ICollection.SyncRoot { get { return this; } }
+
+        object IList.this[int index]
+        {
+            get { return this[index]; }
+            set { this[index] = (T)value; }
+        }
+
+        int IList.Add(object value)
+        {
+            Add((T) value);
+            return count - 1;
+        }
+
+        bool IList.Contains(object value)
+        {
+            return (value is T && Contains((T)value));
+        }
+
+        int IList.IndexOf(object value)
+        {
+            if (!(value is T))
+            {
+                return -1;
+            }
+            return IndexOf((T)value);
+        }
+
+        void IList.Insert(int index, object value)
+        {
+            Insert(index, (T) value);
+        }
+
+        void IList.Remove(object value)
+        {
+            if (!(value is T))
+            {
+                return;
+            }
+            Remove((T)value);
+        }
+        #endregion        
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
new file mode 100644
index 0000000..8a6fefa
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Extension methods for <see cref="PropertyInfo"/>, effectively providing
+    /// the familiar members from previous desktop framework versions while
+    /// targeting the newer releases, .NET Core etc.
+    /// </summary>
+    internal static class PropertyInfoExtensions
+    {
+        /// <summary>
+        /// Returns the public getter of a property, or null if there is no such getter
+        /// (either because it's read-only, or the getter isn't public).
+        /// </summary>
+        internal static MethodInfo GetGetMethod(this PropertyInfo target)
+        {
+            var method = target.GetMethod;
+            return method != null && method.IsPublic ? method : null;
+        }
+
+        /// <summary>
+        /// Returns the public setter of a property, or null if there is no such setter
+        /// (either because it's write-only, or the setter isn't public).
+        /// </summary>
+        internal static MethodInfo GetSetMethod(this PropertyInfo target)
+        {
+            var method = target.SetMethod;
+            return method != null && method.IsPublic ? method : null;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
new file mode 100644
index 0000000..762a29e
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
@@ -0,0 +1,113 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+
+namespace Google.Protobuf.Compatibility
+{
+    /// <summary>
+    /// Provides extension methods on Type that just proxy to TypeInfo.
+    /// These are used to support the new type system from .NET 4.5, without
+    /// having calls to GetTypeInfo all over the place. While the methods here are meant to be
+    /// broadly compatible with the desktop framework, there are some subtle differences in behaviour - but
+    /// they're not expected to affect our use cases. While the class is internal, that should be fine: we can
+    /// evaluate each new use appropriately.
+    /// </summary>
+    internal static class TypeExtensions
+    {
+        /// <summary>
+        /// Returns true if the target type is a value type, including a nullable value type or an enum, or false
+        /// if it's a reference type (class, delegate, interface - including System.ValueType and System.Enum).
+        /// </summary>
+        internal static bool IsValueType(this Type target)
+        {
+            return target.GetTypeInfo().IsValueType;
+        }
+
+        /// <summary>
+        /// See https://msdn.microsoft.com/en-us/library/system.type.isassignablefrom
+        /// </summary>
+        internal static bool IsAssignableFrom(this Type target, Type c)
+        {
+            return target.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo());
+        }
+
+        /// <summary>
+        /// Returns a representation of the public property associated with the given name in the given type,
+        /// including inherited properties or null if there is no such public property.
+        /// Here, "public property" means a property where either the getter, or the setter, or both, is public.
+        /// </summary>
+        internal static PropertyInfo GetProperty(this Type target, string name)
+        {
+            // GetDeclaredProperty only returns properties declared in the given type, so we need to recurse.
+            while (target != null)
+            {
+                var typeInfo = target.GetTypeInfo();
+                var ret = typeInfo.GetDeclaredProperty(name);
+                if (ret != null && ((ret.CanRead && ret.GetMethod.IsPublic) || (ret.CanWrite && ret.SetMethod.IsPublic)))
+                {
+                    return ret;
+                }
+                target = typeInfo.BaseType;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Returns a representation of the public method associated with the given name in the given type,
+        /// including inherited methods.
+        /// </summary>
+        /// <remarks>
+        /// This has a few differences compared with Type.GetMethod in the desktop framework. It will throw
+        /// if there is an ambiguous match even between a private method and a public one, but it *won't* throw
+        /// if there are two overloads at different levels in the type hierarchy (e.g. class Base declares public void Foo(int) and
+        /// class Child : Base declares public void Foo(long)).
+        /// </remarks>
+        /// <exception cref="AmbiguousMatchException">One type in the hierarchy declared more than one method with the same name</exception>
+        internal static MethodInfo GetMethod(this Type target, string name)
+        {
+            // GetDeclaredMethod only returns methods declared in the given type, so we need to recurse.
+            while (target != null)
+            {
+                var typeInfo = target.GetTypeInfo();
+                var ret = typeInfo.GetDeclaredMethod(name);
+                if (ret != null && ret.IsPublic)
+                {
+                    return ret;
+                }
+                target = typeInfo.BaseType;
+            }
+            return null;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs
new file mode 100644
index 0000000..9831308
--- /dev/null
+++ b/csharp/src/Google.Protobuf/FieldCodec.cs
@@ -0,0 +1,473 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Compatibility;
+using Google.Protobuf.WellKnownTypes;
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Factory methods for <see cref="FieldCodec{T}"/>.
+    /// </summary>
+    public static class FieldCodec
+    {
+        // TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
+
+        /// <summary>
+        /// Retrieves a codec suitable for a string field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<string> ForString(uint tag)
+        {
+            return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bytes field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ByteString> ForBytes(uint tag)
+        {
+            return new FieldCodec<ByteString>(input => input.ReadBytes(), (output, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bool field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<bool> ForBool(uint tag)
+        {
+            return new FieldCodec<bool>(input => input.ReadBool(), (output, value) => output.WriteBool(value), CodedOutputStream.ComputeBoolSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadInt32(), (output, value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSInt32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSInt32(), (output, value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForFixed32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSFixed32(uint tag)
+        {
+            return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), 4, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForUInt32(uint tag)
+        {
+            return new FieldCodec<uint>(input => input.ReadUInt32(), (output, value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadInt64(), (output, value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSInt64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSInt64(), (output, value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForFixed64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSFixed64(uint tag)
+        {
+            return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForUInt64(uint tag)
+        {
+            return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a float field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<float> ForFloat(uint tag)
+        {
+            return new FieldCodec<float>(input => input.ReadFloat(), (output, value) => output.WriteFloat(value), CodedOutputStream.ComputeFloatSize, tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a double field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<double> ForDouble(uint tag)
+        {
+            return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.ComputeDoubleSize, tag);
+        }
+
+        // Enums are tricky. We can probably use expression trees to build these delegates automatically,
+        // but it's easy to generate the code for it.
+
+        /// <summary>
+        /// Retrieves a codec suitable for an enum field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
+        /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
+        {
+            return new FieldCodec<T>(input => fromInt32(
+                input.ReadEnum()),
+                (output, value) => output.WriteEnum(toInt32(value)),
+                value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a message field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="parser">A parser to use for the message type.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : IMessage<T>
+        {
+            return new FieldCodec<T>(input => { T message = parser.CreateTemplate(); input.ReadMessage(message); return message; },
+                (output, value) => output.WriteMessage(value), message => CodedOutputStream.ComputeMessageSize(message), tag);
+        }
+
+        /// <summary>
+        /// Creates a codec for a wrapper type of a class - which must be string or ByteString.
+        /// </summary>
+        public static FieldCodec<T> ForClassWrapper<T>(uint tag) where T : class
+        {
+            var nestedCodec = WrapperCodecs.GetCodec<T>();
+            return new FieldCodec<T>(
+                input => WrapperCodecs.Read<T>(input, nestedCodec),
+                (output, value) => WrapperCodecs.Write<T>(output, value, nestedCodec),
+                value => WrapperCodecs.CalculateSize<T>(value, nestedCodec),
+                tag,
+                null); // Default value for the wrapper
+        }
+
+        /// <summary>
+        /// Creates a codec for a wrapper type of a struct - which must be Int32, Int64, UInt32, UInt64,
+        /// Bool, Single or Double.
+        /// </summary>
+        public static FieldCodec<T?> ForStructWrapper<T>(uint tag) where T : struct
+        {
+            var nestedCodec = WrapperCodecs.GetCodec<T>();
+            return new FieldCodec<T?>(
+                input => WrapperCodecs.Read<T>(input, nestedCodec),
+                (output, value) => WrapperCodecs.Write<T>(output, value.Value, nestedCodec),
+                value => value == null ? 0 : WrapperCodecs.CalculateSize<T>(value.Value, nestedCodec),
+                tag,
+                null); // Default value for the wrapper
+        }
+
+        /// <summary>
+        /// Helper code to create codecs for wrapper types.
+        /// </summary>
+        /// <remarks>
+        /// Somewhat ugly with all the static methods, but the conversions involved to/from nullable types make it
+        /// slightly tricky to improve. So long as we keep the public API (ForClassWrapper, ForStructWrapper) in place,
+        /// we can refactor later if we come up with something cleaner.
+        /// </remarks>
+        private static class WrapperCodecs
+        {
+            private static readonly Dictionary<System.Type, object> Codecs = new Dictionary<System.Type, object>
+            {
+                { typeof(bool), ForBool(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(int), ForInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(long), ForInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(uint), ForUInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(ulong), ForUInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(float), ForFloat(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) },
+                { typeof(double), ForDouble(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) },
+                { typeof(string), ForString(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) },
+                { typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
+            };
+
+            /// <summary>
+            /// Returns a field codec which effectively wraps a value of type T in a message.
+            /// 
+            /// </summary>
+            internal static FieldCodec<T> GetCodec<T>()
+            {
+                object value;
+                if (!Codecs.TryGetValue(typeof(T), out value))
+                {
+                    throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T));
+                }
+                return (FieldCodec<T>) value;
+            }
+
+            internal static T Read<T>(CodedInputStream input, FieldCodec<T> codec)
+            {
+                int length = input.ReadLength();
+                int oldLimit = input.PushLimit(length);
+
+                uint tag;
+                T value = codec.DefaultValue;
+                while ((tag = input.ReadTag()) != 0)
+                {
+                    if (tag == codec.Tag)
+                    {
+                        value = codec.Read(input);
+                    }
+                    else
+                    {
+                        input.SkipLastField();
+                    }
+
+                }
+                input.CheckReadEndOfStreamTag();
+                input.PopLimit(oldLimit);
+
+                return value;
+            }
+
+            internal static void Write<T>(CodedOutputStream output, T value, FieldCodec<T> codec)
+            {
+                output.WriteLength(codec.CalculateSizeWithTag(value));
+                codec.WriteTagAndValue(output, value);
+            }
+
+            internal  static int CalculateSize<T>(T value, FieldCodec<T> codec)
+            {
+                int fieldLength = codec.CalculateSizeWithTag(value);
+                return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldLength;
+            }
+        }
+    }
+
+    /// <summary>
+    /// <para>
+    /// An encode/decode pair for a single field. This effectively encapsulates
+    /// all the information needed to read or write the field value from/to a coded
+    /// stream.
+    /// </para>
+    /// <para>
+    /// This class is public and has to be as it is used by generated code, but its public
+    /// API is very limited - just what the generated code needs to call directly.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// This never writes default values to the stream, and does not address "packedness"
+    /// in repeated fields itself, other than to know whether or not the field *should* be packed.
+    /// </remarks>
+    public sealed class FieldCodec<T>
+    {
+        private static readonly T DefaultDefault;
+        private static readonly bool TypeSupportsPacking = typeof(T).IsValueType() && Nullable.GetUnderlyingType(typeof(T)) == null;
+
+        static FieldCodec()
+        {
+            if (typeof(T) == typeof(string))
+            {
+                DefaultDefault = (T)(object)"";
+            }
+            else if (typeof(T) == typeof(ByteString))
+            {
+                DefaultDefault = (T)(object)ByteString.Empty;
+            }
+            // Otherwise it's the default value of the CLR type
+        }
+
+        internal static bool IsPackedRepeatedField(uint tag) =>
+            TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited;
+
+        internal bool PackedRepeatedField { get; }
+
+        /// <summary>
+        /// Returns a delegate to write a value (unconditionally) to a coded output stream.
+        /// </summary>
+        internal Action<CodedOutputStream, T> ValueWriter { get; }
+
+        /// <summary>
+        /// Returns the size calculator for just a value.
+        /// </summary>
+        internal Func<T, int> ValueSizeCalculator { get; }
+
+        /// <summary>
+        /// Returns a delegate to read a value from a coded input stream. It is assumed that
+        /// the stream is already positioned on the appropriate tag.
+        /// </summary>
+        internal Func<CodedInputStream, T> ValueReader { get; }
+
+        /// <summary>
+        /// Returns the fixed size for an entry, or 0 if sizes vary.
+        /// </summary>
+        internal int FixedSize { get; }
+
+        /// <summary>
+        /// Gets the tag of the codec.
+        /// </summary>
+        /// <value>
+        /// The tag of the codec.
+        /// </value>
+        internal uint Tag { get; }
+
+        /// <summary>
+        /// Default value for this codec. Usually the same for every instance of the same type, but
+        /// for string/ByteString wrapper fields the codec's default value is null, whereas for
+        /// other string/ByteString fields it's "" or ByteString.Empty.
+        /// </summary>
+        /// <value>
+        /// The default value of the codec's type.
+        /// </value>
+        internal T DefaultValue { get; }
+
+        private readonly int tagSize;
+        
+        internal FieldCodec(
+                Func<CodedInputStream, T> reader,
+                Action<CodedOutputStream, T> writer,
+                int fixedSize,
+                uint tag) : this(reader, writer, _ => fixedSize, tag)
+        {
+            FixedSize = fixedSize;
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault)
+        {
+        }
+
+        internal FieldCodec(
+            Func<CodedInputStream, T> reader,
+            Action<CodedOutputStream, T> writer,
+            Func<T, int> sizeCalculator,
+            uint tag,
+            T defaultValue)
+        {
+            ValueReader = reader;
+            ValueWriter = writer;
+            ValueSizeCalculator = sizeCalculator;
+            FixedSize = 0;
+            Tag = tag;
+            DefaultValue = defaultValue;
+            tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
+            // Detect packed-ness once, so we can check for it within RepeatedField<T>.
+            PackedRepeatedField = IsPackedRepeatedField(tag);
+        }
+
+        /// <summary>
+        /// Write a tag and the given value, *if* the value is not the default.
+        /// </summary>
+        public void WriteTagAndValue(CodedOutputStream output, T value)
+        {
+            if (!IsDefault(value))
+            {
+                output.WriteTag(Tag);
+                ValueWriter(output, value);
+            }
+        }
+
+        /// <summary>
+        /// Reads a value of the codec type from the given <see cref="CodedInputStream"/>.
+        /// </summary>
+        /// <param name="input">The input stream to read from.</param>
+        /// <returns>The value read from the stream.</returns>
+        public T Read(CodedInputStream input) => ValueReader(input);
+
+        /// <summary>
+        /// Calculates the size required to write the given value, with a tag,
+        /// if the value is not the default.
+        /// </summary>
+        public int CalculateSizeWithTag(T value) => IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize;
+
+        private bool IsDefault(T value) => EqualityComparer<T>.Default.Equals(value, DefaultValue);
+    }
+}
diff --git a/csharp/src/Google.Protobuf/FrameworkPortability.cs b/csharp/src/Google.Protobuf/FrameworkPortability.cs
new file mode 100644
index 0000000..9498dbe
--- /dev/null
+++ b/csharp/src/Google.Protobuf/FrameworkPortability.cs
@@ -0,0 +1,49 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+using System.Text.RegularExpressions;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Class containing helpful workarounds for various platform compatibility

+    /// </summary>

+    internal static class FrameworkPortability

+    {

+        // The value of RegexOptions.Compiled is 8. We can test for the presence at

+        // execution time using Enum.IsDefined, so a single build will do the right thing

+        // on each platform. (RegexOptions.Compiled isn't supported by PCLs.)

+        internal static readonly RegexOptions CompiledRegexWhereAvailable =

+            Enum.IsDefined(typeof(RegexOptions), 8) ? (RegexOptions)8 : RegexOptions.None;

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
new file mode 100644
index 0000000..ef524ba
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <PropertyGroup>

+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

+    <ProductVersion>9.0.30729</ProductVersion>

+    <SchemaVersion>2.0</SchemaVersion>

+    <ProjectGuid>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</ProjectGuid>

+    <OutputType>Library</OutputType>

+    <AppDesignerFolder>Properties</AppDesignerFolder>

+    <RootNamespace>Google.Protobuf</RootNamespace>

+    <AssemblyName>Google.Protobuf</AssemblyName>

+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

+    <TargetFrameworkProfile>Profile259</TargetFrameworkProfile>

+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

+    <FileAlignment>512</FileAlignment>

+    <OldToolsVersion>3.5</OldToolsVersion>

+    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>

+    <NuGetPackageImportStamp>

+    </NuGetPackageImportStamp>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

+    <DebugSymbols>true</DebugSymbols>

+    <DebugType>full</DebugType>

+    <Optimize>false</Optimize>

+    <OutputPath>bin\Debug</OutputPath>

+    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

+    <DocumentationFile>bin\Debug\Google.Protobuf.xml</DocumentationFile>

+    <NoWarn>

+    </NoWarn>

+    <DefineConstants>DEBUG;TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\Release</OutputPath>

+    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

+    <DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>

+    <NoWarn>

+    </NoWarn>

+    <DefineConstants>TRACE</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

+  </PropertyGroup>

+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">

+    <DebugType>pdbonly</DebugType>

+    <Optimize>true</Optimize>

+    <OutputPath>bin\ReleaseSigned</OutputPath>

+    <IntermediateOutputPath>obj\ReleaseSigned\</IntermediateOutputPath>

+    <DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>

+    <NoWarn>

+    </NoWarn>

+    <DefineConstants>TRACE;SIGNED</DefineConstants>

+    <ErrorReport>prompt</ErrorReport>

+    <WarningLevel>4</WarningLevel>

+    <NoStdLib>true</NoStdLib>

+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

+    <SignAssembly>True</SignAssembly>

+    <AssemblyOriginatorKeyFile>..\..\keys\Google.Protobuf.snk</AssemblyOriginatorKeyFile>

+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

+  </PropertyGroup>

+  <ItemGroup>

+    <Reference Include="mscorlib" />

+    <Reference Include="System" />

+    <Reference Include="System.Xml" />

+  </ItemGroup>

+  <ItemGroup>

+    <Compile Include="ByteArray.cs" />

+    <Compile Include="ByteString.cs" />

+    <Compile Include="CodedOutputStream.ComputeSize.cs" />

+    <Compile Include="CodedInputStream.cs" />

+    <Compile Include="CodedOutputStream.cs" />

+    <Compile Include="Collections\MapField.cs" />

+    <Compile Include="Collections\ReadOnlyDictionary.cs" />

+    <Compile Include="Collections\RepeatedField.cs" />

+    <Compile Include="Compatibility\PropertyInfoExtensions.cs" />

+    <Compile Include="Compatibility\TypeExtensions.cs" />

+    <Compile Include="FieldCodec.cs" />

+    <Compile Include="FrameworkPortability.cs" />

+    <Compile Include="ICustomDiagnosticMessage.cs" />

+    <Compile Include="IDeepCloneable.cs" />

+    <Compile Include="InvalidJsonException.cs" />

+    <Compile Include="JsonFormatter.cs" />

+    <Compile Include="JsonParser.cs" />

+    <Compile Include="JsonToken.cs" />

+    <Compile Include="JsonTokenizer.cs" />

+    <Compile Include="MessageExtensions.cs" />

+    <Compile Include="IMessage.cs" />

+    <Compile Include="InvalidProtocolBufferException.cs" />

+    <Compile Include="LimitedInputStream.cs" />

+    <Compile Include="MessageParser.cs" />

+    <Compile Include="Properties\AssemblyInfo.cs" />

+    <Compile Include="Reflection\Descriptor.cs" />

+    <Compile Include="Reflection\DescriptorBase.cs" />

+    <Compile Include="Reflection\DescriptorPool.cs" />

+    <Compile Include="Reflection\DescriptorUtil.cs" />

+    <Compile Include="Reflection\DescriptorValidationException.cs" />

+    <Compile Include="Reflection\EnumDescriptor.cs" />

+    <Compile Include="Reflection\EnumValueDescriptor.cs" />

+    <Compile Include="Reflection\FieldAccessorBase.cs" />

+    <Compile Include="Reflection\FieldDescriptor.cs" />

+    <Compile Include="Reflection\FieldType.cs" />

+    <Compile Include="Reflection\FileDescriptor.cs" />

+    <Compile Include="Reflection\GeneratedClrTypeInfo.cs" />

+    <Compile Include="Reflection\IDescriptor.cs" />

+    <Compile Include="Reflection\IFieldAccessor.cs" />

+    <Compile Include="Reflection\MapFieldAccessor.cs" />

+    <Compile Include="Reflection\MessageDescriptor.cs" />

+    <Compile Include="Reflection\MethodDescriptor.cs" />

+    <Compile Include="Reflection\OneofAccessor.cs" />

+    <Compile Include="Reflection\OneofDescriptor.cs" />

+    <Compile Include="Reflection\PackageDescriptor.cs" />

+    <Compile Include="Reflection\PartialClasses.cs" />

+    <Compile Include="Reflection\ReflectionUtil.cs" />

+    <Compile Include="Reflection\RepeatedFieldAccessor.cs" />

+    <Compile Include="Reflection\ServiceDescriptor.cs" />

+    <Compile Include="Reflection\SingleFieldAccessor.cs" />

+    <Compile Include="ProtoPreconditions.cs" />

+    <Compile Include="Reflection\TypeRegistry.cs" />

+    <Compile Include="WellKnownTypes\Any.cs" />

+    <Compile Include="WellKnownTypes\AnyPartial.cs" />

+    <Compile Include="WellKnownTypes\Api.cs" />

+    <Compile Include="WellKnownTypes\Duration.cs" />

+    <Compile Include="WellKnownTypes\DurationPartial.cs" />

+    <Compile Include="WellKnownTypes\Empty.cs" />

+    <Compile Include="WellKnownTypes\FieldMask.cs" />

+    <Compile Include="WellKnownTypes\FieldMaskPartial.cs" />

+    <Compile Include="WellKnownTypes\SourceContext.cs" />

+    <Compile Include="WellKnownTypes\Struct.cs" />

+    <Compile Include="WellKnownTypes\TimeExtensions.cs" />

+    <Compile Include="WellKnownTypes\Timestamp.cs" />

+    <Compile Include="WellKnownTypes\TimestampPartial.cs" />

+    <Compile Include="WellKnownTypes\Type.cs" />

+    <Compile Include="WellKnownTypes\ValuePartial.cs" />

+    <Compile Include="WellKnownTypes\Wrappers.cs" />

+    <Compile Include="WellKnownTypes\WrappersPartial.cs" />

+    <Compile Include="WireFormat.cs" />

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="Google.Protobuf.nuspec" />

+    <None Include="packages.config" />

+  </ItemGroup>

+  <ItemGroup />

+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />

+  <Import Project="..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets" Condition="Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" />

+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

+    <PropertyGroup>

+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>

+    </PropertyGroup>

+    <Error Condition="!Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets'))" />

+  </Target>

+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+       Other similar extension points exist, see Microsoft.Common.targets.

+  <Target Name="BeforeBuild">

+  </Target>

+  <Target Name="AfterBuild">

+  </Target>

+  -->

+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
new file mode 100644
index 0000000..d530254
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+  <metadata>
+    <id>Google.Protobuf</id>
+    <title>Google Protocol Buffers C#</title>
+    <summary>C# runtime library for Protocol Buffers - Google's data interchange format.</summary>
+    <description>See project site for more info.</description>
+    <version>3.0.0-beta2</version>
+    <authors>Google Inc.</authors>
+    <owners>protobuf-packages</owners>
+    <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
+    <projectUrl>https://github.com/google/protobuf</projectUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <releaseNotes>C# proto3 support</releaseNotes>
+    <copyright>Copyright 2015, Google Inc.</copyright>
+    <tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags>
+    <dependencies>
+      <!-- Dependencies for older, monolithic-assembly platforms -->
+      <group targetFramework="net45" />
+      <group targetFramework="wp8" />
+      <group targetFramework="win8" />
+      <group targetFramework="wpa81" />
+      <group targetFramework="xamarin.ios" />
+      <group targetFramework="monotouch" />
+      <group targetFramework="monoandroid" />
+
+      <!-- Dependencies for newer, more granular platforms (.NET Core etc) -->
+      <group targetFramework="dotnet">
+        <dependency id="System.Collections" version="4.0.0" />
+        <dependency id="System.Diagnostics.Debug" version="4.0.0" />
+        <dependency id="System.Globalization" version="4.0.0" />
+        <dependency id="System.IO" version="4.0.0" />
+        <dependency id="System.Linq" version="4.0.0" />
+        <dependency id="System.Linq.Expressions" version="4.0.0" />
+        <dependency id="System.ObjectModel" version="4.0.0" />
+        <dependency id="System.Reflection" version="4.0.0" />
+        <dependency id="System.Runtime" version="4.0.0" />
+        <dependency id="System.Runtime.Extensions" version="4.0.0" />
+        <dependency id="System.Text.Encoding" version="4.0.0" />
+        <dependency id="System.Text.RegularExpressions" version="4.0.0" />
+      </group>
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/dotnet" />
+    <file src="**\*.cs" target="src" />
+    <file src="..\..\..\cmake\Release\protoc.exe" target="tools" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
+  </files>
+</package>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs b/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs
new file mode 100644
index 0000000..a009056
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs
@@ -0,0 +1,69 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A message type that has a custom string format for diagnostic purposes.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Calling <see cref="object.ToString"/> on a generated message type normally
+    /// returns the JSON representation. If a message type implements this interface,
+    /// then the <see cref="ToDiagnosticString"/> method will be called instead of the regular
+    /// JSON formatting code, but only when <c>ToString()</c> is called either on the message itself
+    /// or on another message which contains it. This does not affect the normal JSON formatting of
+    /// the message.
+    /// </para>
+    /// <para>
+    /// For example, if you create a proto message representing a GUID, the internal
+    /// representation may be a <c>bytes</c> field or four <c>fixed32</c> fields. However, when debugging
+    /// it may be more convenient to see a result in the same format as <see cref="System.Guid"/> provides.
+    /// </para>
+    /// <para>This interface extends <see cref="IMessage"/> to avoid it accidentally being implemented
+    /// on types other than messages, where it would not be used by anything in the framework.</para>
+    /// </remarks>
+    public interface ICustomDiagnosticMessage : IMessage
+    {
+        /// <summary>
+        /// Returns a string representation of this object, for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// This method is called when a message is formatted as part of a <see cref="object.ToString"/>
+        /// call. It does not affect the JSON representation used by <see cref="JsonFormatter"/> other than
+        /// in calls to <see cref="JsonFormatter.ToDiagnosticString(IMessage)"/>. While it is recommended
+        /// that the result is valid JSON, this is never assumed by the Protobuf library.
+        /// </remarks>
+        /// <returns>A string representation of this object, for diagnostic purposes.</returns>
+        string ToDiagnosticString();
+    }
+}
diff --git a/csharp/src/Google.Protobuf/IDeepCloneable.cs b/csharp/src/Google.Protobuf/IDeepCloneable.cs
new file mode 100644
index 0000000..c9c71bb
--- /dev/null
+++ b/csharp/src/Google.Protobuf/IDeepCloneable.cs
@@ -0,0 +1,54 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Generic interface for a deeply cloneable type.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// All generated messages implement this interface, but so do some non-message types.
+    /// Additionally, due to the type constraint on <c>T</c> in <see cref="IMessage{T}"/>,
+    /// it is simpler to keep this as a separate interface.
+    /// </para>
+    /// </remarks>
+    /// <typeparam name="T">The type itself, returned by the <see cref="Clone"/> method.</typeparam>
+    public interface IDeepCloneable<T>
+    {
+        /// <summary>
+        /// Creates a deep clone of this object.
+        /// </summary>
+        /// <returns>A deep clone of this object.</returns>
+        T Clone();
+    }
+}
diff --git a/csharp/src/Google.Protobuf/IMessage.cs b/csharp/src/Google.Protobuf/IMessage.cs
new file mode 100644
index 0000000..d089f94
--- /dev/null
+++ b/csharp/src/Google.Protobuf/IMessage.cs
@@ -0,0 +1,87 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+using Google.Protobuf.Reflection;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Interface for a Protocol Buffers message, supporting

+    /// basic operations required for serialization.

+    /// </summary>

+    public interface IMessage

+    {

+        /// <summary>

+        /// Merges the data from the specified coded input stream with the current message.

+        /// </summary>

+        /// <remarks>See the user guide for precise merge semantics.</remarks>

+        /// <param name="input"></param>

+        void MergeFrom(CodedInputStream input);

+

+        /// <summary>

+        /// Writes the data to the given coded output stream.

+        /// </summary>

+        /// <param name="output">Coded output stream to write the data to. Must not be null.</param>

+        void WriteTo(CodedOutputStream output);

+

+        /// <summary>

+        /// Calculates the size of this message in Protocol Buffer wire format, in bytes.

+        /// </summary>

+        /// <returns>The number of bytes required to write this message

+        /// to a coded output stream.</returns>

+        int CalculateSize();

+

+        /// <summary>

+        /// Descriptor for this message. All instances are expected to return the same descriptor,

+        /// and for generated types this will be an explicitly-implemented member, returning the

+        /// same value as the static property declared on the type.

+        /// </summary>

+        MessageDescriptor Descriptor { get; }

+    }

+

+    /// <summary>

+    /// Generic interface for a Protocol Buffers message,

+    /// where the type parameter is expected to be the same type as

+    /// the implementation class.

+    /// </summary>

+    /// <typeparam name="T">The message type.</typeparam>

+    public interface IMessage<T> : IMessage, IEquatable<T>, IDeepCloneable<T> where T : IMessage<T>

+    {

+        /// <summary>

+        /// Merges the given message into this one.

+        /// </summary>

+        /// <remarks>See the user guide for precise merge semantics.</remarks>

+        /// <param name="message">The message to merge with this one. Must not be null.</param>

+        void MergeFrom(T message);

+    }

+}

diff --git a/csharp/src/Google.Protobuf/InvalidJsonException.cs b/csharp/src/Google.Protobuf/InvalidJsonException.cs
new file mode 100644
index 0000000..b543420
--- /dev/null
+++ b/csharp/src/Google.Protobuf/InvalidJsonException.cs
@@ -0,0 +1,53 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Thrown when an attempt is made to parse invalid JSON, e.g. using
+    /// a non-string property key, or including a redundant comma. Parsing a protocol buffer
+    /// message represented in JSON using <see cref="JsonParser"/> can throw both this
+    /// exception and <see cref="InvalidProtocolBufferException"/> depending on the situation. This
+    /// exception is only thrown for "pure JSON" errors, whereas <c>InvalidProtocolBufferException</c>
+    /// is thrown when the JSON may be valid in and of itself, but cannot be parsed as a protocol buffer
+    /// message.
+    /// </summary>
+    public sealed class InvalidJsonException : IOException
+    {
+        internal InvalidJsonException(string message)
+            : base(message)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
new file mode 100644
index 0000000..eeb0f13
--- /dev/null
+++ b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
@@ -0,0 +1,129 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System;

+using System.IO;

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// Thrown when a protocol message being parsed is invalid in some way,

+    /// e.g. it contains a malformed varint or a negative byte length.

+    /// </summary>

+    public sealed class InvalidProtocolBufferException : IOException

+    {

+        internal InvalidProtocolBufferException(string message)

+            : base(message)

+        {

+        }

+

+        internal InvalidProtocolBufferException(string message, Exception innerException)

+            : base(message, innerException)

+        {

+        }

+

+        internal static InvalidProtocolBufferException MoreDataAvailable()

+        {

+            return new InvalidProtocolBufferException(

+                "Completed reading a message while more data was available in the stream.");

+        }

+

+        internal static InvalidProtocolBufferException TruncatedMessage()

+        {

+            return new InvalidProtocolBufferException(

+                "While parsing a protocol message, the input ended unexpectedly " +

+                "in the middle of a field.  This could mean either than the " +

+                "input has been truncated or that an embedded message " +

+                "misreported its own length.");

+        }

+

+        internal static InvalidProtocolBufferException NegativeSize()

+        {

+            return new InvalidProtocolBufferException(

+                "CodedInputStream encountered an embedded string or message " +

+                "which claimed to have negative size.");

+        }

+

+        internal static InvalidProtocolBufferException MalformedVarint()

+        {

+            return new InvalidProtocolBufferException(

+                "CodedInputStream encountered a malformed varint.");

+        }

+

+        /// <summary>

+        /// Creates an exception for an error condition of an invalid tag being encountered.

+        /// </summary>

+        internal static InvalidProtocolBufferException InvalidTag()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message contained an invalid tag (zero).");

+        }

+

+        internal static InvalidProtocolBufferException InvalidBase64(Exception innerException)

+        {

+            return new InvalidProtocolBufferException("Invalid base64 data", innerException);

+        }

+

+        internal static InvalidProtocolBufferException InvalidEndTag()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message end-group tag did not match expected tag.");

+        }

+

+        internal static InvalidProtocolBufferException RecursionLimitExceeded()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message had too many levels of nesting.  May be malicious.  " +

+                "Use CodedInputStream.SetRecursionLimit() to increase the depth limit.");

+        }

+

+        internal static InvalidProtocolBufferException JsonRecursionLimitExceeded()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message had too many levels of nesting.  May be malicious.  " +

+                "Use JsonParser.Settings to increase the depth limit.");

+        }

+

+        internal static InvalidProtocolBufferException SizeLimitExceeded()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message was too large.  May be malicious.  " +

+                "Use CodedInputStream.SetSizeLimit() to increase the size limit.");

+        }

+

+        internal static InvalidProtocolBufferException InvalidMessageStreamTag()

+        {

+            return new InvalidProtocolBufferException(

+                "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.");

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
new file mode 100644
index 0000000..60f61fc
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -0,0 +1,865 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Text;
+using Google.Protobuf.Reflection;
+using Google.Protobuf.WellKnownTypes;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Reflection-based converter from messages to JSON.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Instances of this class are thread-safe, with no mutable state.
+    /// </para>
+    /// <para>
+    /// This is a simple start to get JSON formatting working. As it's reflection-based,
+    /// it's not as quick as baking calls into generated messages - but is a simpler implementation.
+    /// (This code is generally not heavily optimized.)
+    /// </para>
+    /// </remarks>
+    public sealed class JsonFormatter
+    {
+        internal const string AnyTypeUrlField = "@type";
+        internal const string AnyDiagnosticValueField = "@value";
+        internal const string AnyWellKnownTypeValueField = "value";
+        private const string TypeUrlPrefix = "type.googleapis.com";
+        private const string NameValueSeparator = ": ";
+        private const string PropertySeparator = ", ";
+
+        /// <summary>
+        /// Returns a formatter using the default settings.
+        /// </summary>
+        public static JsonFormatter Default { get; } = new JsonFormatter(Settings.Default);
+
+        // A JSON formatter which *only* exists 
+        private static readonly JsonFormatter diagnosticFormatter = new JsonFormatter(Settings.Default);
+
+        /// <summary>
+        /// The JSON representation of the first 160 characters of Unicode.
+        /// Empty strings are replaced by the static constructor.
+        /// </summary>
+        private static readonly string[] CommonRepresentations = {
+            // C0 (ASCII and derivatives) control characters
+            "\\u0000", "\\u0001", "\\u0002", "\\u0003",  // 0x00
+          "\\u0004", "\\u0005", "\\u0006", "\\u0007",
+          "\\b",     "\\t",     "\\n",     "\\u000b",
+          "\\f",     "\\r",     "\\u000e", "\\u000f",
+          "\\u0010", "\\u0011", "\\u0012", "\\u0013",  // 0x10
+          "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+          "\\u0018", "\\u0019", "\\u001a", "\\u001b",
+          "\\u001c", "\\u001d", "\\u001e", "\\u001f",
+            // Escaping of " and \ are required by www.json.org string definition.
+            // Escaping of < and > are required for HTML security.
+            "", "", "\\\"", "", "",        "", "",        "",  // 0x20
+          "", "", "",     "", "",        "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x30
+          "", "", "",     "", "\\u003c", "", "\\u003e", "",
+          "", "", "",     "", "",        "", "",        "",  // 0x40
+          "", "", "",     "", "",        "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x50
+          "", "", "",     "", "\\\\",    "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x60
+          "", "", "",     "", "",        "", "",        "",
+          "", "", "",     "", "",        "", "",        "",  // 0x70
+          "", "", "",     "", "",        "", "",        "\\u007f",
+            // C1 (ISO 8859 and Unicode) extended control characters
+            "\\u0080", "\\u0081", "\\u0082", "\\u0083",  // 0x80
+          "\\u0084", "\\u0085", "\\u0086", "\\u0087",
+          "\\u0088", "\\u0089", "\\u008a", "\\u008b",
+          "\\u008c", "\\u008d", "\\u008e", "\\u008f",
+          "\\u0090", "\\u0091", "\\u0092", "\\u0093",  // 0x90
+          "\\u0094", "\\u0095", "\\u0096", "\\u0097",
+          "\\u0098", "\\u0099", "\\u009a", "\\u009b",
+          "\\u009c", "\\u009d", "\\u009e", "\\u009f"
+        };
+
+        static JsonFormatter()
+        {
+            for (int i = 0; i < CommonRepresentations.Length; i++)
+            {
+                if (CommonRepresentations[i] == "")
+                {
+                    CommonRepresentations[i] = ((char) i).ToString();
+                }
+            }
+        }
+
+        private readonly Settings settings;
+
+        private bool DiagnosticOnly => ReferenceEquals(this, diagnosticFormatter);
+
+        /// <summary>
+        /// Creates a new formatted with the given settings.
+        /// </summary>
+        /// <param name="settings">The settings.</param>
+        public JsonFormatter(Settings settings)
+        {
+            this.settings = settings;
+        }
+
+        /// <summary>
+        /// Formats the specified message as JSON.
+        /// </summary>
+        /// <param name="message">The message to format.</param>
+        /// <returns>The formatted message.</returns>
+        public string Format(IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            StringBuilder builder = new StringBuilder();
+            if (message.Descriptor.IsWellKnownType)
+            {
+                WriteWellKnownTypeValue(builder, message.Descriptor, message);
+            }
+            else
+            {
+                WriteMessage(builder, message);
+            }
+            return builder.ToString();
+        }
+
+        /// <summary>
+        /// Converts a message to JSON for diagnostic purposes with no extra context.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// This differs from calling <see cref="Format(IMessage)"/> on the default JSON
+        /// formatter in its handling of <see cref="Any"/>. As no type registry is available
+        /// in <see cref="object.ToString"/> calls, the normal way of resolving the type of
+        /// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
+        /// is included with the base64 data from the <see cref="Any.Value"/> property of the message.
+        /// </para>
+        /// <para>The value returned by this method is only designed to be used for diagnostic
+        /// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
+        /// by other Protocol Buffer implementations.</para>
+        /// </remarks>
+        /// <param name="message">The message to format for diagnostic purposes.</param>
+        /// <returns>The diagnostic-only JSON representation of the message</returns>
+        public static string ToDiagnosticString(IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            return diagnosticFormatter.Format(message);
+        }
+
+        private void WriteMessage(StringBuilder builder, IMessage message)
+        {
+            if (message == null)
+            {
+                WriteNull(builder);
+                return;
+            }
+            if (DiagnosticOnly)
+            {
+                ICustomDiagnosticMessage customDiagnosticMessage = message as ICustomDiagnosticMessage;
+                if (customDiagnosticMessage != null)
+                {
+                    builder.Append(customDiagnosticMessage.ToDiagnosticString());
+                    return;
+                }
+            }
+            builder.Append("{ ");
+            bool writtenFields = WriteMessageFields(builder, message, false);
+            builder.Append(writtenFields ? " }" : "}");
+        }
+
+        private bool WriteMessageFields(StringBuilder builder, IMessage message, bool assumeFirstFieldWritten)
+        {
+            var fields = message.Descriptor.Fields;
+            bool first = !assumeFirstFieldWritten;
+            // First non-oneof fields
+            foreach (var field in fields.InFieldNumberOrder())
+            {
+                var accessor = field.Accessor;
+                if (field.ContainingOneof != null && field.ContainingOneof.Accessor.GetCaseFieldDescriptor(message) != field)
+                {
+                    continue;
+                }
+                // Omit default values unless we're asked to format them, or they're oneofs (where the default
+                // value is still formatted regardless, because that's how we preserve the oneof case).
+                object value = accessor.GetValue(message);
+                if (field.ContainingOneof == null && !settings.FormatDefaultValues && IsDefaultValue(accessor, value))
+                {
+                    continue;
+                }
+
+                // Okay, all tests complete: let's write the field value...
+                if (!first)
+                {
+                    builder.Append(PropertySeparator);
+                }
+                WriteString(builder, ToCamelCase(accessor.Descriptor.Name));
+                builder.Append(NameValueSeparator);
+                WriteValue(builder, value);
+                first = false;
+            }            
+            return !first;
+        }
+
+        /// <summary>
+        /// Camel-case converter with added strictness for field mask formatting.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
+        private static string ToCamelCaseForFieldMask(string input)
+        {
+            for (int i = 0; i < input.Length; i++)
+            {
+                char c = input[i];
+                if (c >= 'A' && c <= 'Z')
+                {
+                    throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
+                }
+                if (c == '_' && i < input.Length - 1)
+                {
+                    char next = input[i + 1];
+                    if (next < 'a' || next > 'z')
+                    {
+                        throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
+                    }
+                }
+            }
+            return ToCamelCase(input);
+        }
+
+        // Converted from src/google/protobuf/util/internal/utility.cc ToCamelCase
+        // TODO: Use the new field in FieldDescriptor.
+        internal static string ToCamelCase(string input)
+        {
+            bool capitalizeNext = false;
+            bool wasCap = true;
+            bool isCap = false;
+            bool firstWord = true;
+            StringBuilder result = new StringBuilder(input.Length);
+
+            for (int i = 0; i < input.Length; i++, wasCap = isCap)
+            {
+                isCap = char.IsUpper(input[i]);
+                if (input[i] == '_')
+                {
+                    capitalizeNext = true;
+                    if (result.Length != 0)
+                    {
+                        firstWord = false;
+                    }
+                    continue;
+                }
+                else if (firstWord)
+                {
+                    // Consider when the current character B is capitalized,
+                    // first word ends when:
+                    // 1) following a lowercase:   "...aB..."
+                    // 2) followed by a lowercase: "...ABc..."
+                    if (result.Length != 0 && isCap &&
+                        (!wasCap || (i + 1 < input.Length && char.IsLower(input[i + 1]))))
+                    {
+                        firstWord = false;
+                    }
+                    else
+                    {
+                        result.Append(char.ToLowerInvariant(input[i]));
+                        continue;
+                    }
+                }
+                else if (capitalizeNext)
+                {
+                    capitalizeNext = false;
+                    if (char.IsLower(input[i]))
+                    {
+                        result.Append(char.ToUpperInvariant(input[i]));
+                        continue;
+                    }
+                }
+                result.Append(input[i]);
+            }
+            return result.ToString();
+        }
+        
+        private static void WriteNull(StringBuilder builder)
+        {
+            builder.Append("null");
+        }
+
+        private static bool IsDefaultValue(IFieldAccessor accessor, object value)
+        {
+            if (accessor.Descriptor.IsMap)
+            {
+                IDictionary dictionary = (IDictionary) value;
+                return dictionary.Count == 0;
+            }
+            if (accessor.Descriptor.IsRepeated)
+            {
+                IList list = (IList) value;
+                return list.Count == 0;
+            }
+            switch (accessor.Descriptor.FieldType)
+            {
+                case FieldType.Bool:
+                    return (bool) value == false;
+                case FieldType.Bytes:
+                    return (ByteString) value == ByteString.Empty;
+                case FieldType.String:
+                    return (string) value == "";
+                case FieldType.Double:
+                    return (double) value == 0.0;
+                case FieldType.SInt32:
+                case FieldType.Int32:
+                case FieldType.SFixed32:
+                case FieldType.Enum:
+                    return (int) value == 0;
+                case FieldType.Fixed32:
+                case FieldType.UInt32:
+                    return (uint) value == 0;
+                case FieldType.Fixed64:
+                case FieldType.UInt64:
+                    return (ulong) value == 0;
+                case FieldType.SFixed64:
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                    return (long) value == 0;
+                case FieldType.Float:
+                    return (float) value == 0f;
+                case FieldType.Message:
+                case FieldType.Group: // Never expect to get this, but...
+                    return value == null;
+                default:
+                    throw new ArgumentException("Invalid field type");
+            }
+        }
+        
+        private void WriteValue(StringBuilder builder, object value)
+        {
+            if (value == null)
+            {
+                WriteNull(builder);
+            }
+            else if (value is bool)
+            {
+                builder.Append((bool) value ? "true" : "false");
+            }
+            else if (value is ByteString)
+            {
+                // Nothing in Base64 needs escaping
+                builder.Append('"');
+                builder.Append(((ByteString) value).ToBase64());
+                builder.Append('"');
+            }
+            else if (value is string)
+            {
+                WriteString(builder, (string) value);
+            }
+            else if (value is IDictionary)
+            {
+                WriteDictionary(builder, (IDictionary) value);
+            }
+            else if (value is IList)
+            {
+                WriteList(builder, (IList) value);
+            }
+            else if (value is int || value is uint)
+            {
+                IFormattable formattable = (IFormattable) value;
+                builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
+            }
+            else if (value is long || value is ulong)
+            {
+                builder.Append('"');
+                IFormattable formattable = (IFormattable) value;
+                builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
+                builder.Append('"');
+            }
+            else if (value is System.Enum)
+            {
+                if (System.Enum.IsDefined(value.GetType(), value))
+                {
+                    WriteString(builder, value.ToString());
+                }
+                else
+                {
+                    WriteValue(builder, (int) value);
+                }
+            }
+            else if (value is float || value is double)
+            {
+                string text = ((IFormattable) value).ToString("r", CultureInfo.InvariantCulture);
+                if (text == "NaN" || text == "Infinity" || text == "-Infinity")
+                {
+                    builder.Append('"');
+                    builder.Append(text);
+                    builder.Append('"');
+                }
+                else
+                {
+                    builder.Append(text);
+                }
+            }
+            else if (value is IMessage)
+            {
+                IMessage message = (IMessage) value;
+                if (message.Descriptor.IsWellKnownType)
+                {
+                    WriteWellKnownTypeValue(builder, message.Descriptor, value);
+                }
+                else
+                {
+                    WriteMessage(builder, (IMessage) value);
+                }
+            }
+            else
+            {
+                throw new ArgumentException("Unable to format value of type " + value.GetType());
+            }
+        }
+
+        /// <summary>
+        /// Central interception point for well-known type formatting. Any well-known types which
+        /// don't need special handling can fall back to WriteMessage. We avoid assuming that the
+        /// values are using the embedded well-known types, in order to allow for dynamic messages
+        /// in the future.
+        /// </summary>
+        private void WriteWellKnownTypeValue(StringBuilder builder, MessageDescriptor descriptor, object value)
+        {
+            // Currently, we can never actually get here, because null values are always handled by the caller. But if we *could*,
+            // this would do the right thing.
+            if (value == null)
+            {
+                WriteNull(builder);
+                return;
+            }
+            // For wrapper types, the value will either be the (possibly boxed) "native" value,
+            // or the message itself if we're formatting it at the top level (e.g. just calling ToString on the object itself).
+            // If it's the message form, we can extract the value first, which *will* be the (possibly boxed) native value,
+            // and then proceed, writing it as if we were definitely in a field. (We never need to wrap it in an extra string...
+            // WriteValue will do the right thing.)
+            if (descriptor.IsWrapperType)
+            {
+                if (value is IMessage)
+                {
+                    var message = (IMessage) value;
+                    value = message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.GetValue(message);
+                }
+                WriteValue(builder, value);
+                return;
+            }
+            if (descriptor.FullName == Timestamp.Descriptor.FullName)
+            {
+                WriteTimestamp(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == Duration.Descriptor.FullName)
+            {
+                WriteDuration(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == FieldMask.Descriptor.FullName)
+            {
+                WriteFieldMask(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == Struct.Descriptor.FullName)
+            {
+                WriteStruct(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == ListValue.Descriptor.FullName)
+            {
+                var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
+                WriteList(builder, (IList) fieldAccessor.GetValue((IMessage) value));
+                return;
+            }
+            if (descriptor.FullName == Value.Descriptor.FullName)
+            {
+                WriteStructFieldValue(builder, (IMessage) value);
+                return;
+            }
+            if (descriptor.FullName == Any.Descriptor.FullName)
+            {
+                WriteAny(builder, (IMessage) value);
+                return;
+            }
+            WriteMessage(builder, (IMessage) value);
+        }
+
+        private void WriteTimestamp(StringBuilder builder, IMessage value)
+        {
+            // TODO: In the common case where this *is* using the built-in Timestamp type, we could
+            // avoid all the reflection at this point, by casting to Timestamp. In the interests of
+            // avoiding subtle bugs, don't do that until we've implemented DynamicMessage so that we can prove
+            // it still works in that case.
+            int nanos = (int) value.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.GetValue(value);
+            long seconds = (long) value.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.GetValue(value);
+            builder.Append(Timestamp.ToJson(seconds, nanos, DiagnosticOnly));
+        }
+
+        private void WriteDuration(StringBuilder builder, IMessage value)
+        {
+            // TODO: Same as for WriteTimestamp
+            int nanos = (int) value.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.GetValue(value);
+            long seconds = (long) value.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.GetValue(value);
+            builder.Append(Duration.ToJson(seconds, nanos, DiagnosticOnly));
+        }
+
+        private void WriteFieldMask(StringBuilder builder, IMessage value)
+        {
+            var paths = (IList<string>) value.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(value);
+            builder.Append(FieldMask.ToJson(paths, DiagnosticOnly));
+        }
+
+        private void WriteAny(StringBuilder builder, IMessage value)
+        {
+            if (DiagnosticOnly)
+            {
+                WriteDiagnosticOnlyAny(builder, value);
+                return;
+            }
+
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            string typeName = GetTypeName(typeUrl);
+            MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
+            if (descriptor == null)
+            {
+                throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
+            }
+            IMessage message = descriptor.Parser.ParseFrom(data);
+            builder.Append("{ ");
+            WriteString(builder, AnyTypeUrlField);
+            builder.Append(NameValueSeparator);
+            WriteString(builder, typeUrl);
+
+            if (descriptor.IsWellKnownType)
+            {
+                builder.Append(PropertySeparator);
+                WriteString(builder, AnyWellKnownTypeValueField);
+                builder.Append(NameValueSeparator);
+                WriteWellKnownTypeValue(builder, descriptor, message);
+            }
+            else
+            {
+                WriteMessageFields(builder, message, true);
+            }
+            builder.Append(" }");
+        }
+
+        private void WriteDiagnosticOnlyAny(StringBuilder builder, IMessage value)
+        {
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            builder.Append("{ ");
+            WriteString(builder, AnyTypeUrlField);
+            builder.Append(NameValueSeparator);
+            WriteString(builder, typeUrl);
+            builder.Append(PropertySeparator);
+            WriteString(builder, AnyDiagnosticValueField);
+            builder.Append(NameValueSeparator);
+            builder.Append('"');
+            builder.Append(data.ToBase64());
+            builder.Append('"');
+            builder.Append(" }");
+        }
+
+        internal static string GetTypeName(String typeUrl)
+        {
+            string[] parts = typeUrl.Split('/');
+            if (parts.Length != 2 || parts[0] != TypeUrlPrefix)
+            {
+                throw new InvalidProtocolBufferException($"Invalid type url: {typeUrl}");
+            }
+            return parts[1];
+        }
+
+        private void WriteStruct(StringBuilder builder, IMessage message)
+        {
+            builder.Append("{ ");
+            IDictionary fields = (IDictionary) message.Descriptor.Fields[Struct.FieldsFieldNumber].Accessor.GetValue(message);
+            bool first = true;
+            foreach (DictionaryEntry entry in fields)
+            {
+                string key = (string) entry.Key;
+                IMessage value = (IMessage) entry.Value;
+                if (string.IsNullOrEmpty(key) || value == null)
+                {
+                    throw new InvalidOperationException("Struct fields cannot have an empty key or a null value.");
+                }
+
+                if (!first)
+                {
+                    builder.Append(PropertySeparator);
+                }
+                WriteString(builder, key);
+                builder.Append(NameValueSeparator);
+                WriteStructFieldValue(builder, value);
+                first = false;
+            }
+            builder.Append(first ? "}" : " }");
+        }
+
+        private void WriteStructFieldValue(StringBuilder builder, IMessage message)
+        {
+            var specifiedField = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message);
+            if (specifiedField == null)
+            {
+                throw new InvalidOperationException("Value message must contain a value for the oneof.");
+            }
+
+            object value = specifiedField.Accessor.GetValue(message);
+            
+            switch (specifiedField.FieldNumber)
+            {
+                case Value.BoolValueFieldNumber:
+                case Value.StringValueFieldNumber:
+                case Value.NumberValueFieldNumber:
+                    WriteValue(builder, value);
+                    return;
+                case Value.StructValueFieldNumber:
+                case Value.ListValueFieldNumber:
+                    // Structs and ListValues are nested messages, and already well-known types.
+                    var nestedMessage = (IMessage) specifiedField.Accessor.GetValue(message);
+                    WriteWellKnownTypeValue(builder, nestedMessage.Descriptor, nestedMessage);
+                    return;
+                case Value.NullValueFieldNumber:
+                    WriteNull(builder);
+                    return;
+                default:
+                    throw new InvalidOperationException("Unexpected case in struct field: " + specifiedField.FieldNumber);
+            }
+        }
+
+        internal void WriteList(StringBuilder builder, IList list)
+        {
+            builder.Append("[ ");
+            bool first = true;
+            foreach (var value in list)
+            {
+                if (!first)
+                {
+                    builder.Append(PropertySeparator);
+                }
+                WriteValue(builder, value);
+                first = false;
+            }
+            builder.Append(first ? "]" : " ]");
+        }
+
+        internal void WriteDictionary(StringBuilder builder, IDictionary dictionary)
+        {
+            builder.Append("{ ");
+            bool first = true;
+            // This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
+            foreach (DictionaryEntry pair in dictionary)
+            {
+                if (!first)
+                {
+                    builder.Append(PropertySeparator);
+                }
+                string keyText;
+                if (pair.Key is string)
+                {
+                    keyText = (string) pair.Key;
+                }
+                else if (pair.Key is bool)
+                {
+                    keyText = (bool) pair.Key ? "true" : "false";
+                }
+                else if (pair.Key is int || pair.Key is uint | pair.Key is long || pair.Key is ulong)
+                {
+                    keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
+                }
+                else
+                {
+                    if (pair.Key == null)
+                    {
+                        throw new ArgumentException("Dictionary has entry with null key");
+                    }
+                    throw new ArgumentException("Unhandled dictionary key type: " + pair.Key.GetType());
+                }
+                WriteString(builder, keyText);
+                builder.Append(NameValueSeparator);
+                WriteValue(builder, pair.Value);
+                first = false;
+            }
+            builder.Append(first ? "}" : " }");
+        }
+
+        /// <summary>
+        /// Returns whether or not a singular value can be represented in JSON.
+        /// Currently only relevant for enums, where unknown values can't be represented.
+        /// For repeated/map fields, this always returns true.
+        /// </summary>
+        private bool CanWriteSingleValue(object value)
+        {
+            if (value is System.Enum)
+            {
+                return System.Enum.IsDefined(value.GetType(), value);
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Writes a string (including leading and trailing double quotes) to a builder, escaping as required.
+        /// </summary>
+        /// <remarks>
+        /// Other than surrogate pair handling, this code is mostly taken from src/google/protobuf/util/internal/json_escaping.cc.
+        /// </remarks>
+        internal static void WriteString(StringBuilder builder, string text)
+        {
+            builder.Append('"');
+            for (int i = 0; i < text.Length; i++)
+            {
+                char c = text[i];
+                if (c < 0xa0)
+                {
+                    builder.Append(CommonRepresentations[c]);
+                    continue;
+                }
+                if (char.IsHighSurrogate(c))
+                {
+                    // Encountered first part of a surrogate pair.
+                    // Check that we have the whole pair, and encode both parts as hex.
+                    i++;
+                    if (i == text.Length || !char.IsLowSurrogate(text[i]))
+                    {
+                        throw new ArgumentException("String contains low surrogate not followed by high surrogate");
+                    }
+                    HexEncodeUtf16CodeUnit(builder, c);
+                    HexEncodeUtf16CodeUnit(builder, text[i]);
+                    continue;
+                }
+                else if (char.IsLowSurrogate(c))
+                {
+                    throw new ArgumentException("String contains high surrogate not preceded by low surrogate");
+                }
+                switch ((uint) c)
+                {
+                    // These are not required by json spec
+                    // but used to prevent security bugs in javascript.
+                    case 0xfeff:  // Zero width no-break space
+                    case 0xfff9:  // Interlinear annotation anchor
+                    case 0xfffa:  // Interlinear annotation separator
+                    case 0xfffb:  // Interlinear annotation terminator
+
+                    case 0x00ad:  // Soft-hyphen
+                    case 0x06dd:  // Arabic end of ayah
+                    case 0x070f:  // Syriac abbreviation mark
+                    case 0x17b4:  // Khmer vowel inherent Aq
+                    case 0x17b5:  // Khmer vowel inherent Aa
+                        HexEncodeUtf16CodeUnit(builder, c);
+                        break;
+
+                    default:
+                        if ((c >= 0x0600 && c <= 0x0603) ||  // Arabic signs
+                            (c >= 0x200b && c <= 0x200f) ||  // Zero width etc.
+                            (c >= 0x2028 && c <= 0x202e) ||  // Separators etc.
+                            (c >= 0x2060 && c <= 0x2064) ||  // Invisible etc.
+                            (c >= 0x206a && c <= 0x206f))
+                        {
+                            HexEncodeUtf16CodeUnit(builder, c);
+                        }
+                        else
+                        {
+                            // No handling of surrogates here - that's done earlier
+                            builder.Append(c);
+                        }
+                        break;
+                }
+            }
+            builder.Append('"');
+        }
+
+        private const string Hex = "0123456789abcdef";
+        private static void HexEncodeUtf16CodeUnit(StringBuilder builder, char c)
+        {
+            builder.Append("\\u");
+            builder.Append(Hex[(c >> 12) & 0xf]);
+            builder.Append(Hex[(c >> 8) & 0xf]);
+            builder.Append(Hex[(c >> 4) & 0xf]);
+            builder.Append(Hex[(c >> 0) & 0xf]);
+        }
+
+        /// <summary>
+        /// Settings controlling JSON formatting.
+        /// </summary>
+        public sealed class Settings
+        {
+            /// <summary>
+            /// Default settings, as used by <see cref="JsonFormatter.Default"/>
+            /// </summary>
+            public static Settings Default { get; }
+
+            // Workaround for the Mono compiler complaining about XML comments not being on
+            // valid language elements.
+            static Settings()
+            {
+                Default = new Settings(false);
+            }
+
+            /// <summary>
+            /// Whether fields whose values are the default for the field type (e.g. 0 for integers)
+            /// should be formatted (true) or omitted (false).
+            /// </summary>
+            public bool FormatDefaultValues { get; }
+
+            /// <summary>
+            /// The type registry used to format <see cref="Any"/> messages.
+            /// </summary>
+            public TypeRegistry TypeRegistry { get; }
+
+            // TODO: Work out how we're going to scale this to multiple settings. "WithXyz" methods?
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified formatting of default values
+            /// and an empty type registry.
+            /// </summary>
+            /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
+            public Settings(bool formatDefaultValues) : this(formatDefaultValues, TypeRegistry.Empty)
+            {
+            }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified formatting of default values
+            /// and type registry.
+            /// </summary>
+            /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
+            /// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
+            public Settings(bool formatDefaultValues, TypeRegistry typeRegistry)
+            {
+                FormatDefaultValues = formatDefaultValues;
+                TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs
new file mode 100644
index 0000000..80d3013
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonParser.cs
@@ -0,0 +1,1018 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Reflection;
+using Google.Protobuf.WellKnownTypes;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Reflection-based converter from JSON to messages.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Instances of this class are thread-safe, with no mutable state.
+    /// </para>
+    /// <para>
+    /// This is a simple start to get JSON parsing working. As it's reflection-based,
+    /// it's not as quick as baking calls into generated messages - but is a simpler implementation.
+    /// (This code is generally not heavily optimized.)
+    /// </para>
+    /// </remarks>
+    public sealed class JsonParser
+    {
+        // Note: using 0-9 instead of \d to ensure no non-ASCII digits.
+        // This regex isn't a complete validator, but will remove *most* invalid input. We rely on parsing to do the rest.
+        private static readonly Regex TimestampRegex = new Regex(@"^(?<datetime>[0-9]{4}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9])(?<subseconds>\.[0-9]{1,9})?(?<offset>(Z|[+-][0-1][0-9]:[0-5][0-9]))$", FrameworkPortability.CompiledRegexWhereAvailable);
+        private static readonly Regex DurationRegex = new Regex(@"^(?<sign>-)?(?<int>[0-9]{1,12})(?<subseconds>\.[0-9]{1,9})?s$", FrameworkPortability.CompiledRegexWhereAvailable);
+        private static readonly int[] SubsecondScalingFactors = { 0, 100000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
+        private static readonly char[] FieldMaskPathSeparators = new[] { ',' };
+
+        private static readonly JsonParser defaultInstance = new JsonParser(Settings.Default);
+
+        // TODO: Consider introducing a class containing parse state of the parser, tokenizer and depth. That would simplify these handlers
+        // and the signatures of various methods.
+        private static readonly Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
+            WellKnownTypeHandlers = new Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
+        {
+            { Timestamp.Descriptor.FullName, (parser, message, tokenizer) => MergeTimestamp(message, tokenizer.Next()) },
+            { Duration.Descriptor.FullName, (parser, message, tokenizer) => MergeDuration(message, tokenizer.Next()) },
+            { Value.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeStructValue(message, tokenizer) },
+            { ListValue.Descriptor.FullName, (parser, message, tokenizer) =>
+                parser.MergeRepeatedField(message, message.Descriptor.Fields[ListValue.ValuesFieldNumber], tokenizer) },
+            { Struct.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeStruct(message, tokenizer) },
+            { Any.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeAny(message, tokenizer) },
+            { FieldMask.Descriptor.FullName, (parser, message, tokenizer) => MergeFieldMask(message, tokenizer.Next()) },
+            { Int32Value.Descriptor.FullName, MergeWrapperField },
+            { Int64Value.Descriptor.FullName, MergeWrapperField },
+            { UInt32Value.Descriptor.FullName, MergeWrapperField },
+            { UInt64Value.Descriptor.FullName, MergeWrapperField },
+            { FloatValue.Descriptor.FullName, MergeWrapperField },
+            { DoubleValue.Descriptor.FullName, MergeWrapperField },
+            { BytesValue.Descriptor.FullName, MergeWrapperField },
+            { StringValue.Descriptor.FullName, MergeWrapperField }
+        };
+
+        // Convenience method to avoid having to repeat the same code multiple times in the above
+        // dictionary initialization.
+        private static void MergeWrapperField(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
+        {
+            parser.MergeField(message, message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber], tokenizer);
+        }
+
+        /// <summary>
+        /// Returns a formatter using the default settings.
+        /// </summary>
+        public static JsonParser Default { get { return defaultInstance; } }
+
+        private readonly Settings settings;
+
+        /// <summary>
+        /// Creates a new formatted with the given settings.
+        /// </summary>
+        /// <param name="settings">The settings.</param>
+        public JsonParser(Settings settings)
+        {
+            this.settings = settings;
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> and merges the information into the given message.
+        /// </summary>
+        /// <param name="message">The message to merge the JSON information into.</param>
+        /// <param name="json">The JSON to parse.</param>
+        internal void Merge(IMessage message, string json)
+        {
+            Merge(message, new StringReader(json));
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> and merges the information into the given message.
+        /// </summary>
+        /// <param name="message">The message to merge the JSON information into.</param>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        internal void Merge(IMessage message, TextReader jsonReader)
+        {
+            var tokenizer = JsonTokenizer.FromTextReader(jsonReader);
+            Merge(message, tokenizer);
+            var lastToken = tokenizer.Next();
+            if (lastToken != JsonToken.EndDocument)
+            {
+                throw new InvalidProtocolBufferException("Expected end of JSON after object");
+            }
+        }
+
+        /// <summary>
+        /// Merges the given message using data from the given tokenizer. In most cases, the next
+        /// token should be a "start object" token, but wrapper types and nullity can invalidate
+        /// that assumption. This is implemented as an LL(1) recursive descent parser over the stream
+        /// of tokens provided by the tokenizer. This token stream is assumed to be valid JSON, with the
+        /// tokenizer performing that validation - but not every token stream is valid "protobuf JSON".
+        /// </summary>
+        private void Merge(IMessage message, JsonTokenizer tokenizer)
+        {
+            if (tokenizer.ObjectDepth > settings.RecursionLimit)
+            {
+                throw InvalidProtocolBufferException.JsonRecursionLimitExceeded();
+            }
+            if (message.Descriptor.IsWellKnownType)
+            {
+                Action<JsonParser, IMessage, JsonTokenizer> handler;
+                if (WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, out handler))
+                {
+                    handler(this, message, tokenizer);
+                    return;
+                }
+                // Well-known types with no special handling continue in the normal way.
+            }
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected an object");
+            }
+            var descriptor = message.Descriptor;
+            var jsonFieldMap = descriptor.Fields.ByJsonName();
+            // All the oneof fields we've already accounted for - we can only see each of them once.
+            // The set is created lazily to avoid the overhead of creating a set for every message
+            // we parsed, when oneofs are relatively rare.
+            HashSet<OneofDescriptor> seenOneofs = null;
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndObject)
+                {
+                    return;
+                }
+                if (token.Type != JsonToken.TokenType.Name)
+                {
+                    throw new InvalidOperationException("Unexpected token type " + token.Type);
+                }
+                string name = token.StringValue;
+                FieldDescriptor field;
+                if (jsonFieldMap.TryGetValue(name, out field))
+                {
+                    if (field.ContainingOneof != null)
+                    {
+                        if (seenOneofs == null)
+                        {
+                            seenOneofs = new HashSet<OneofDescriptor>();
+                        }
+                        if (!seenOneofs.Add(field.ContainingOneof))
+                        {
+                            throw new InvalidProtocolBufferException($"Multiple values specified for oneof {field.ContainingOneof.Name}");
+                        }
+                    }
+                    MergeField(message, field, tokenizer);
+                }
+                else
+                {
+                    // TODO: Is this what we want to do? If not, we'll need to skip the value,
+                    // which may be an object or array. (We might want to put code in the tokenizer
+                    // to do that.)
+                    throw new InvalidProtocolBufferException("Unknown field: " + name);
+                }
+            }
+        }
+
+        private void MergeField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type == JsonToken.TokenType.Null)
+            {
+                // Clear the field if we see a null token, unless it's for a singular field of type
+                // google.protobuf.Value.
+                // Note: different from Java API, which just ignores it.
+                // TODO: Bring it more in line? Discuss...
+                if (field.IsMap || field.IsRepeated || !IsGoogleProtobufValueField(field))
+                {
+                    field.Accessor.Clear(message);
+                    return;
+                }
+            }
+            tokenizer.PushBack(token);
+
+            if (field.IsMap)
+            {
+                MergeMapField(message, field, tokenizer);
+            }
+            else if (field.IsRepeated)
+            {
+                MergeRepeatedField(message, field, tokenizer);
+            }
+            else
+            {
+                var value = ParseSingleValue(field, tokenizer);
+                field.Accessor.SetValue(message, value);
+            }
+        }
+
+        private void MergeRepeatedField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartArray)
+            {
+                throw new InvalidProtocolBufferException("Repeated field value was not an array. Token type: " + token.Type);
+            }
+
+            IList list = (IList) field.Accessor.GetValue(message);
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndArray)
+                {
+                    return;
+                }
+                tokenizer.PushBack(token);
+                if (token.Type == JsonToken.TokenType.Null)
+                {
+                    throw new InvalidProtocolBufferException("Repeated field elements cannot be null");
+                }
+                list.Add(ParseSingleValue(field, tokenizer));
+            }
+        }
+
+        private void MergeMapField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            // Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those.
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected an object to populate a map");
+            }
+
+            var type = field.MessageType;
+            var keyField = type.FindFieldByNumber(1);
+            var valueField = type.FindFieldByNumber(2);
+            if (keyField == null || valueField == null)
+            {
+                throw new InvalidProtocolBufferException("Invalid map field: " + field.FullName);
+            }
+            IDictionary dictionary = (IDictionary) field.Accessor.GetValue(message);
+
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndObject)
+                {
+                    return;
+                }
+                object key = ParseMapKey(keyField, token.StringValue);
+                object value = ParseSingleValue(valueField, tokenizer);
+                if (value == null)
+                {
+                    throw new InvalidProtocolBufferException("Map values must not be null");
+                }
+                dictionary[key] = value;
+            }
+        }
+
+        private static bool IsGoogleProtobufValueField(FieldDescriptor field)
+        {
+            return field.FieldType == FieldType.Message &&
+                field.MessageType.FullName == Value.Descriptor.FullName;
+        }
+
+        private object ParseSingleValue(FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type == JsonToken.TokenType.Null)
+            {
+                // TODO: In order to support dynamic messages, we should really build this up
+                // dynamically.
+                if (IsGoogleProtobufValueField(field))
+                {
+                    return Value.ForNull();
+                }
+                return null;
+            }
+
+            var fieldType = field.FieldType;
+            if (fieldType == FieldType.Message)
+            {
+                // Parse wrapper types as their constituent types.
+                // TODO: What does this mean for null?
+                if (field.MessageType.IsWrapperType)
+                {
+                    field = field.MessageType.Fields[WrappersReflection.WrapperValueFieldNumber];
+                    fieldType = field.FieldType;
+                }
+                else
+                {
+                    // TODO: Merge the current value in message? (Public API currently doesn't make this relevant as we don't expose merging.)
+                    tokenizer.PushBack(token);
+                    IMessage subMessage = NewMessageForField(field);
+                    Merge(subMessage, tokenizer);
+                    return subMessage;
+                }
+            }
+
+            switch (token.Type)
+            {
+                case JsonToken.TokenType.True:
+                case JsonToken.TokenType.False:
+                    if (fieldType == FieldType.Bool)
+                    {
+                        return token.Type == JsonToken.TokenType.True;
+                    }
+                    // Fall through to "we don't support this type for this case"; could duplicate the behaviour of the default
+                    // case instead, but this way we'd only need to change one place.
+                    goto default;
+                case JsonToken.TokenType.StringValue:
+                    return ParseSingleStringValue(field, token.StringValue);
+                // Note: not passing the number value itself here, as we may end up storing the string value in the token too.
+                case JsonToken.TokenType.Number:
+                    return ParseSingleNumberValue(field, token);
+                case JsonToken.TokenType.Null:
+                    throw new NotImplementedException("Haven't worked out what to do for null yet");
+                default:
+                    throw new InvalidProtocolBufferException("Unsupported JSON token type " + token.Type + " for field type " + fieldType);
+            }
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> into a new message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to create.</typeparam>
+        /// <param name="json">The JSON to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public T Parse<T>(string json) where T : IMessage, new()
+        {
+            ProtoPreconditions.CheckNotNull(json, nameof(json));
+            return Parse<T>(new StringReader(json));
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> into a new message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to create.</typeparam>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public T Parse<T>(TextReader jsonReader) where T : IMessage, new()
+        {
+            ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
+            T message = new T();
+            Merge(message, jsonReader);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> into a new message.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <param name="descriptor">Descriptor of message type to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage Parse(string json, MessageDescriptor descriptor)
+        {
+            ProtoPreconditions.CheckNotNull(json, nameof(json));
+            ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
+            return Parse(new StringReader(json), descriptor);
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> into a new message.
+        /// </summary>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        /// <param name="descriptor">Descriptor of message type to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage Parse(TextReader jsonReader, MessageDescriptor descriptor)
+        {
+            ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
+            ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
+            IMessage message = descriptor.Parser.CreateTemplate();
+            Merge(message, jsonReader);
+            return message;
+        }
+
+        private void MergeStructValue(IMessage message, JsonTokenizer tokenizer)
+        {
+            var firstToken = tokenizer.Next();
+            var fields = message.Descriptor.Fields;
+            switch (firstToken.Type)
+            {
+                case JsonToken.TokenType.Null:
+                    fields[Value.NullValueFieldNumber].Accessor.SetValue(message, 0);
+                    return;
+                case JsonToken.TokenType.StringValue:
+                    fields[Value.StringValueFieldNumber].Accessor.SetValue(message, firstToken.StringValue);
+                    return;
+                case JsonToken.TokenType.Number:
+                    fields[Value.NumberValueFieldNumber].Accessor.SetValue(message, firstToken.NumberValue);
+                    return;
+                case JsonToken.TokenType.False:
+                case JsonToken.TokenType.True:
+                    fields[Value.BoolValueFieldNumber].Accessor.SetValue(message, firstToken.Type == JsonToken.TokenType.True);
+                    return;
+                case JsonToken.TokenType.StartObject:
+                    {
+                        var field = fields[Value.StructValueFieldNumber];
+                        var structMessage = NewMessageForField(field);
+                        tokenizer.PushBack(firstToken);
+                        Merge(structMessage, tokenizer);
+                        field.Accessor.SetValue(message, structMessage);
+                        return;
+                    }
+                case JsonToken.TokenType.StartArray:
+                    {
+                        var field = fields[Value.ListValueFieldNumber];
+                        var list = NewMessageForField(field);
+                        tokenizer.PushBack(firstToken);
+                        Merge(list, tokenizer);
+                        field.Accessor.SetValue(message, list);
+                        return;
+                    }
+                default:
+                    throw new InvalidOperationException("Unexpected token type: " + firstToken.Type);
+            }
+        }
+
+        private void MergeStruct(IMessage message, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected object value for Struct");
+            }
+            tokenizer.PushBack(token);
+
+            var field = message.Descriptor.Fields[Struct.FieldsFieldNumber];
+            MergeMapField(message, field, tokenizer);
+        }
+
+        private void MergeAny(IMessage message, JsonTokenizer tokenizer)
+        {
+            // Record the token stream until we see the @type property. At that point, we can take the value, consult
+            // the type registry for the relevant message, and replay the stream, omitting the @type property.
+            var tokens = new List<JsonToken>();
+
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected object value for Any");
+            }
+            int typeUrlObjectDepth = tokenizer.ObjectDepth;
+
+            // The check for the property depth protects us from nested Any values which occur before the type URL
+            // for *this* Any.
+            while (token.Type != JsonToken.TokenType.Name ||
+                token.StringValue != JsonFormatter.AnyTypeUrlField ||
+                tokenizer.ObjectDepth != typeUrlObjectDepth)
+            {
+                tokens.Add(token);
+                token = tokenizer.Next();
+
+                if (tokenizer.ObjectDepth < typeUrlObjectDepth)
+                {
+                    throw new InvalidProtocolBufferException("Any message with no @type");
+                }
+            }
+
+            // Don't add the @type property or its value to the recorded token list
+            token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Any.@type");
+            }
+            string typeUrl = token.StringValue;
+            string typeName = JsonFormatter.GetTypeName(typeUrl);
+
+            MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
+            if (descriptor == null)
+            {
+                throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
+            }
+
+            // Now replay the token stream we've already read and anything that remains of the object, just parsing it
+            // as normal. Our original tokenizer should end up at the end of the object.
+            var replay = JsonTokenizer.FromReplayedTokens(tokens, tokenizer);
+            var body = descriptor.Parser.CreateTemplate();
+            if (descriptor.IsWellKnownType)
+            {
+                MergeWellKnownTypeAnyBody(body, replay);
+            }
+            else
+            {
+                Merge(body, replay);
+            }
+            var data = body.ToByteString();
+
+            // Now that we have the message data, we can pack it into an Any (the message received as a parameter).
+            message.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.SetValue(message, typeUrl);
+            message.Descriptor.Fields[Any.ValueFieldNumber].Accessor.SetValue(message, data);
+        }
+
+        // Well-known types end up in a property called "value" in the JSON. As there's no longer a @type property
+        // in the given JSON token stream, we should *only* have tokens of start-object, name("value"), the value
+        // itself, and then end-object.
+        private void MergeWellKnownTypeAnyBody(IMessage body, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next(); // Definitely start-object; checked in previous method
+            token = tokenizer.Next();
+            // TODO: What about an absent Int32Value, for example?
+            if (token.Type != JsonToken.TokenType.Name || token.StringValue != JsonFormatter.AnyWellKnownTypeValueField)
+            {
+                throw new InvalidProtocolBufferException($"Expected '{JsonFormatter.AnyWellKnownTypeValueField}' property for well-known type Any body");
+            }
+            Merge(body, tokenizer);
+            token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.EndObject)
+            {
+                throw new InvalidProtocolBufferException($"Expected end-object token after @type/value for well-known type");
+            }
+        }
+
+        #region Utility methods which don't depend on the state (or settings) of the parser.
+        private static object ParseMapKey(FieldDescriptor field, string keyText)
+        {
+            switch (field.FieldType)
+            {
+                case FieldType.Bool:
+                    if (keyText == "true")
+                    {
+                        return true;
+                    }
+                    if (keyText == "false")
+                    {
+                        return false;
+                    }
+                    throw new InvalidProtocolBufferException("Invalid string for bool map key: " + keyText);
+                case FieldType.String:
+                    return keyText;
+                case FieldType.Int32:
+                case FieldType.SInt32:
+                case FieldType.SFixed32:
+                    return ParseNumericString(keyText, int.Parse);
+                case FieldType.UInt32:
+                case FieldType.Fixed32:
+                    return ParseNumericString(keyText, uint.Parse);
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                case FieldType.SFixed64:
+                    return ParseNumericString(keyText, long.Parse);
+                case FieldType.UInt64:
+                case FieldType.Fixed64:
+                    return ParseNumericString(keyText, ulong.Parse);
+                default:
+                    throw new InvalidProtocolBufferException("Invalid field type for map: " + field.FieldType);
+            }
+        }
+
+        private static object ParseSingleNumberValue(FieldDescriptor field, JsonToken token)
+        {
+            double value = token.NumberValue;
+            checked
+            {
+                try
+                {
+                    switch (field.FieldType)
+                    {
+                        case FieldType.Int32:
+                        case FieldType.SInt32:
+                        case FieldType.SFixed32:
+                            CheckInteger(value);
+                            return (int) value;
+                        case FieldType.UInt32:
+                        case FieldType.Fixed32:
+                            CheckInteger(value);
+                            return (uint) value;
+                        case FieldType.Int64:
+                        case FieldType.SInt64:
+                        case FieldType.SFixed64:
+                            CheckInteger(value);
+                            return (long) value;
+                        case FieldType.UInt64:
+                        case FieldType.Fixed64:
+                            CheckInteger(value);
+                            return (ulong) value;
+                        case FieldType.Double:
+                            return value;
+                        case FieldType.Float:
+                            if (double.IsNaN(value))
+                            {
+                                return float.NaN;
+                            }
+                            if (value > float.MaxValue || value < float.MinValue)
+                            {
+                                if (double.IsPositiveInfinity(value))
+                                {
+                                    return float.PositiveInfinity;
+                                }
+                                if (double.IsNegativeInfinity(value))
+                                {
+                                    return float.NegativeInfinity;
+                                }
+                                throw new InvalidProtocolBufferException($"Value out of range: {value}");
+                            }
+                            return (float) value;
+                        case FieldType.Enum:
+                            CheckInteger(value);
+                            // Just return it as an int, and let the CLR convert it.
+                            // Note that we deliberately don't check that it's a known value.
+                            return (int) value;
+                        default:
+                            throw new InvalidProtocolBufferException($"Unsupported conversion from JSON number for field type {field.FieldType}");
+                    }
+                }
+                catch (OverflowException)
+                {
+                    throw new InvalidProtocolBufferException($"Value out of range: {value}");
+                }
+            }
+        }
+
+        private static void CheckInteger(double value)
+        {
+            if (double.IsInfinity(value) || double.IsNaN(value))
+            {
+                throw new InvalidProtocolBufferException($"Value not an integer: {value}");
+            }
+            if (value != Math.Floor(value))
+            {
+                throw new InvalidProtocolBufferException($"Value not an integer: {value}");
+            }            
+        }
+
+        private static object ParseSingleStringValue(FieldDescriptor field, string text)
+        {
+            switch (field.FieldType)
+            {
+                case FieldType.String:
+                    return text;
+                case FieldType.Bytes:
+                    try
+                    {
+                        return ByteString.FromBase64(text);
+                    }
+                    catch (FormatException e)
+                    {
+                        throw InvalidProtocolBufferException.InvalidBase64(e);
+                    }
+                case FieldType.Int32:
+                case FieldType.SInt32:
+                case FieldType.SFixed32:
+                    return ParseNumericString(text, int.Parse);
+                case FieldType.UInt32:
+                case FieldType.Fixed32:
+                    return ParseNumericString(text, uint.Parse);
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                case FieldType.SFixed64:
+                    return ParseNumericString(text, long.Parse);
+                case FieldType.UInt64:
+                case FieldType.Fixed64:
+                    return ParseNumericString(text, ulong.Parse);
+                case FieldType.Double:
+                    double d = ParseNumericString(text, double.Parse);
+                    ValidateInfinityAndNan(text, double.IsPositiveInfinity(d), double.IsNegativeInfinity(d), double.IsNaN(d));
+                    return d;
+                case FieldType.Float:
+                    float f = ParseNumericString(text, float.Parse);
+                    ValidateInfinityAndNan(text, float.IsPositiveInfinity(f), float.IsNegativeInfinity(f), float.IsNaN(f));
+                    return f;
+                case FieldType.Enum:
+                    var enumValue = field.EnumType.FindValueByName(text);
+                    if (enumValue == null)
+                    {
+                        throw new InvalidProtocolBufferException($"Invalid enum value: {text} for enum type: {field.EnumType.FullName}");
+                    }
+                    // Just return it as an int, and let the CLR convert it.
+                    return enumValue.Number;
+                default:
+                    throw new InvalidProtocolBufferException($"Unsupported conversion from JSON string for field type {field.FieldType}");
+            }
+        }
+
+        /// <summary>
+        /// Creates a new instance of the message type for the given field.
+        /// </summary>
+        private static IMessage NewMessageForField(FieldDescriptor field)
+        {
+            return field.MessageType.Parser.CreateTemplate();
+        }
+
+        private static T ParseNumericString<T>(string text, Func<string, NumberStyles, IFormatProvider, T> parser)
+        {
+            // Can't prohibit this with NumberStyles.
+            if (text.StartsWith("+"))
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+            }
+            if (text.StartsWith("0") && text.Length > 1)
+            {
+                if (text[1] >= '0' && text[1] <= '9')
+                {
+                    throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+                }
+            }
+            else if (text.StartsWith("-0") && text.Length > 2)
+            {
+                if (text[2] >= '0' && text[2] <= '9')
+                {
+                    throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+                }
+            }
+            try
+            {
+                return parser(text, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value for type: {text}");
+            }
+            catch (OverflowException)
+            {
+                throw new InvalidProtocolBufferException($"Value out of range: {text}");
+            }
+        }
+
+        /// <summary>
+        /// Checks that any infinite/NaN values originated from the correct text.
+        /// This corrects the lenient whitespace handling of double.Parse/float.Parse, as well as the
+        /// way that Mono parses out-of-range values as infinity.
+        /// </summary>
+        private static void ValidateInfinityAndNan(string text, bool isPositiveInfinity, bool isNegativeInfinity, bool isNaN)
+        {
+            if ((isPositiveInfinity && text != "Infinity") ||
+                (isNegativeInfinity && text != "-Infinity") ||
+                (isNaN && text != "NaN"))
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+            }
+        }
+
+        private static void MergeTimestamp(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Timestamp");
+            }
+            var match = TimestampRegex.Match(token.StringValue);
+            if (!match.Success)
+            {
+                throw new InvalidProtocolBufferException($"Invalid Timestamp value: {token.StringValue}");
+            }
+            var dateTime = match.Groups["datetime"].Value;
+            var subseconds = match.Groups["subseconds"].Value;
+            var offset = match.Groups["offset"].Value;
+
+            try
+            {
+                DateTime parsed = DateTime.ParseExact(
+                    dateTime,
+                    "yyyy-MM-dd'T'HH:mm:ss",
+                    CultureInfo.InvariantCulture,
+                    DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
+                // TODO: It would be nice not to have to create all these objects... easy to optimize later though.
+                Timestamp timestamp = Timestamp.FromDateTime(parsed);
+                int nanosToAdd = 0;
+                if (subseconds != "")
+                {
+                    // This should always work, as we've got 1-9 digits.
+                    int parsedFraction = int.Parse(subseconds.Substring(1), CultureInfo.InvariantCulture);
+                    nanosToAdd = parsedFraction * SubsecondScalingFactors[subseconds.Length];
+                }
+                int secondsToAdd = 0;
+                if (offset != "Z")
+                {
+                    // This is the amount we need to *subtract* from the local time to get to UTC - hence - => +1 and vice versa.
+                    int sign = offset[0] == '-' ? 1 : -1;
+                    int hours = int.Parse(offset.Substring(1, 2), CultureInfo.InvariantCulture);
+                    int minutes = int.Parse(offset.Substring(4, 2));
+                    int totalMinutes = hours * 60 + minutes;
+                    if (totalMinutes > 18 * 60)
+                    {
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                    if (totalMinutes == 0 && sign == 1)
+                    {
+                        // This is an offset of -00:00, which means "unknown local offset". It makes no sense for a timestamp.
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                    // We need to *subtract* the offset from local time to get UTC.
+                    secondsToAdd = sign * totalMinutes * 60;
+                }
+                // Ensure we've got the right signs. Currently unnecessary, but easy to do.
+                if (secondsToAdd < 0 && nanosToAdd > 0)
+                {
+                    secondsToAdd++;
+                    nanosToAdd = nanosToAdd - Duration.NanosecondsPerSecond;
+                }
+                if (secondsToAdd != 0 || nanosToAdd != 0)
+                {
+                    timestamp += new Duration { Nanos = nanosToAdd, Seconds = secondsToAdd };
+                    // The resulting timestamp after offset change would be out of our expected range. Currently the Timestamp message doesn't validate this
+                    // anywhere, but we shouldn't parse it.
+                    if (timestamp.Seconds < Timestamp.UnixSecondsAtBclMinValue || timestamp.Seconds > Timestamp.UnixSecondsAtBclMaxValue)
+                    {
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                }
+                message.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.SetValue(message, timestamp.Seconds);
+                message.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.SetValue(message, timestamp.Nanos);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+            }
+        }
+
+        private static void MergeDuration(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Duration");
+            }
+            var match = DurationRegex.Match(token.StringValue);
+            if (!match.Success)
+            {
+                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
+            }
+            var sign = match.Groups["sign"].Value;
+            var secondsText = match.Groups["int"].Value;
+            // Prohibit leading insignficant zeroes
+            if (secondsText[0] == '0' && secondsText.Length > 1)
+            {
+                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
+            }
+            var subseconds = match.Groups["subseconds"].Value;
+            var multiplier = sign == "-" ? -1 : 1;
+
+            try
+            {
+                long seconds = long.Parse(secondsText, CultureInfo.InvariantCulture) * multiplier;
+                int nanos = 0;
+                if (subseconds != "")
+                {
+                    // This should always work, as we've got 1-9 digits.
+                    int parsedFraction = int.Parse(subseconds.Substring(1));
+                    nanos = parsedFraction * SubsecondScalingFactors[subseconds.Length] * multiplier;
+                }
+                if (!Duration.IsNormalized(seconds, nanos))
+                {
+                    throw new InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}");
+                }
+                message.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.SetValue(message, seconds);
+                message.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.SetValue(message, nanos);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}");
+            }
+        }
+
+        private static void MergeFieldMask(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for FieldMask");
+            }
+            // TODO: Do we *want* to remove empty entries? Probably okay to treat "" as "no paths", but "foo,,bar"?
+            string[] jsonPaths = token.StringValue.Split(FieldMaskPathSeparators, StringSplitOptions.RemoveEmptyEntries);
+            IList messagePaths = (IList) message.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(message);
+            foreach (var path in jsonPaths)
+            {
+                messagePaths.Add(ToSnakeCase(path));
+            }
+        }
+        
+        // Ported from src/google/protobuf/util/internal/utility.cc
+        private static string ToSnakeCase(string text)
+        {
+            var builder = new StringBuilder(text.Length * 2);
+            // Note: this is probably unnecessary now, but currently retained to be as close as possible to the
+            // C++, whilst still throwing an exception on underscores.
+            bool wasNotUnderscore = false;  // Initialize to false for case 1 (below)
+            bool wasNotCap = false;
+
+            for (int i = 0; i < text.Length; i++)
+            {
+                char c = text[i];
+                if (c >= 'A' && c <= 'Z') // ascii_isupper
+                {
+                    // Consider when the current character B is capitalized:
+                    // 1) At beginning of input:   "B..." => "b..."
+                    //    (e.g. "Biscuit" => "biscuit")
+                    // 2) Following a lowercase:   "...aB..." => "...a_b..."
+                    //    (e.g. "gBike" => "g_bike")
+                    // 3) At the end of input:     "...AB" => "...ab"
+                    //    (e.g. "GoogleLAB" => "google_lab")
+                    // 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
+                    //    (e.g. "GBike" => "g_bike")
+                    if (wasNotUnderscore &&               //            case 1 out
+                        (wasNotCap ||                     // case 2 in, case 3 out
+                         (i + 1 < text.Length &&         //            case 3 out
+                          (text[i + 1] >= 'a' && text[i + 1] <= 'z')))) // ascii_islower(text[i + 1])
+                    {  // case 4 in
+                       // We add an underscore for case 2 and case 4.
+                        builder.Append('_');
+                    }
+                    // ascii_tolower, but we already know that c *is* an upper case ASCII character...
+                    builder.Append((char) (c + 'a' - 'A'));
+                    wasNotUnderscore = true;
+                    wasNotCap = false;
+                }
+                else
+                {
+                    builder.Append(c);
+                    if (c == '_')
+                    {
+                        throw new InvalidProtocolBufferException($"Invalid field mask: {text}");
+                    }
+                    wasNotUnderscore = true;
+                    wasNotCap = true;
+                }
+            }
+            return builder.ToString();
+        }
+        #endregion
+
+        /// <summary>
+        /// Settings controlling JSON parsing.
+        /// </summary>
+        public sealed class Settings
+        {
+            /// <summary>
+            /// Default settings, as used by <see cref="JsonParser.Default"/>. This has the same default
+            /// recursion limit as <see cref="CodedInputStream"/>, and an empty type registry.
+            /// </summary>
+            public static Settings Default { get; }
+
+            // Workaround for the Mono compiler complaining about XML comments not being on
+            // valid language elements.
+            static Settings()
+            {
+                Default = new Settings(CodedInputStream.DefaultRecursionLimit);
+            }
+
+            /// <summary>
+            /// The maximum depth of messages to parse. Note that this limit only applies to parsing
+            /// messages, not collections - so a message within a collection within a message only counts as
+            /// depth 2, not 3.
+            /// </summary>
+            public int RecursionLimit { get; }
+
+            /// <summary>
+            /// The type registry used to parse <see cref="Any"/> messages.
+            /// </summary>
+            public TypeRegistry TypeRegistry { get; }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified recursion limit.
+            /// </summary>
+            /// <param name="recursionLimit">The maximum depth of messages to parse</param>
+            public Settings(int recursionLimit) : this(recursionLimit, TypeRegistry.Empty)
+            {
+            }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified recursion limit and type registry.
+            /// </summary>
+            /// <param name="recursionLimit">The maximum depth of messages to parse</param>
+            /// <param name="typeRegistry">The type registry used to parse <see cref="Any"/> messages</param>
+            public Settings(int recursionLimit, TypeRegistry typeRegistry)
+            {
+                RecursionLimit = recursionLimit;
+                TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonToken.cs b/csharp/src/Google.Protobuf/JsonToken.cs
new file mode 100644
index 0000000..6c0138c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonToken.cs
@@ -0,0 +1,166 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    internal sealed class JsonToken : IEquatable<JsonToken>
+    {
+        // Tokens with no value can be reused.
+        private static readonly JsonToken _true = new JsonToken(TokenType.True);
+        private static readonly JsonToken _false = new JsonToken(TokenType.False);
+        private static readonly JsonToken _null = new JsonToken(TokenType.Null);
+        private static readonly JsonToken startObject = new JsonToken(TokenType.StartObject);
+        private static readonly JsonToken endObject = new JsonToken(TokenType.EndObject);
+        private static readonly JsonToken startArray = new JsonToken(TokenType.StartArray);
+        private static readonly JsonToken endArray = new JsonToken(TokenType.EndArray);
+        private static readonly JsonToken endDocument = new JsonToken(TokenType.EndDocument);
+
+        internal static JsonToken Null { get { return _null; } }
+        internal static JsonToken False { get { return _false; } }
+        internal static JsonToken True { get { return _true; } }
+        internal static JsonToken StartObject{ get { return startObject; } }
+        internal static JsonToken EndObject { get { return endObject; } }
+        internal static JsonToken StartArray { get { return startArray; } }
+        internal static JsonToken EndArray { get { return endArray; } }
+        internal static JsonToken EndDocument { get { return endDocument; } }
+
+        internal static JsonToken Name(string name)
+        {
+            return new JsonToken(TokenType.Name, stringValue: name);
+        }
+
+        internal static JsonToken Value(string value)
+        {
+            return new JsonToken(TokenType.StringValue, stringValue: value);
+        }
+
+        internal static JsonToken Value(double value)
+        {
+            return new JsonToken(TokenType.Number, numberValue: value);
+        }
+
+        internal enum TokenType
+        {
+            Null,
+            False,
+            True,
+            StringValue,
+            Number,
+            Name,
+            StartObject,
+            EndObject,
+            StartArray,
+            EndArray,
+            EndDocument
+        }
+
+        // A value is a string, number, array, object, null, true or false
+        // Arrays and objects have start/end
+        // A document consists of a value
+        // Objects are name/value sequences.
+
+        private readonly TokenType type;
+        private readonly string stringValue;
+        private readonly double numberValue;
+
+        internal TokenType Type { get { return type; } }
+        internal string StringValue { get { return stringValue; } }
+        internal double NumberValue { get { return numberValue; } }
+
+        private JsonToken(TokenType type, string stringValue = null, double numberValue = 0)
+        {
+            this.type = type;
+            this.stringValue = stringValue;
+            this.numberValue = numberValue;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as JsonToken);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = 17;
+                hash = hash * 31 + (int) type;
+                hash = hash * 31 + stringValue == null ? 0 : stringValue.GetHashCode();
+                hash = hash * 31 + numberValue.GetHashCode();
+                return hash;
+            }
+        }
+
+        public override string ToString()
+        {
+            switch (type)
+            {
+                case TokenType.Null:
+                    return "null";
+                case TokenType.True:
+                    return "true";
+                case TokenType.False:
+                    return "false";
+                case TokenType.Name:
+                    return "name (" + stringValue + ")";
+                case TokenType.StringValue:
+                    return "value (" + stringValue + ")";
+                case TokenType.Number:
+                    return "number (" + numberValue + ")";
+                case TokenType.StartObject:
+                    return "start-object";
+                case TokenType.EndObject:
+                    return "end-object";
+                case TokenType.StartArray:
+                    return "start-array";
+                case TokenType.EndArray:
+                    return "end-array";
+                case TokenType.EndDocument:
+                    return "end-document";
+                default:
+                    throw new InvalidOperationException("Token is of unknown type " + type);
+            }
+        }
+
+        public bool Equals(JsonToken other)
+        {
+            if (ReferenceEquals(other, null))
+            {
+                return false;
+            }
+            // Note use of other.numberValue.Equals rather than ==, so that NaN compares appropriately.
+            return other.type == type && other.stringValue == stringValue && other.numberValue.Equals(numberValue);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs
new file mode 100644
index 0000000..09a6d43
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs
@@ -0,0 +1,738 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Simple but strict JSON tokenizer, rigidly following RFC 7159.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This tokenizer is stateful, and only returns "useful" tokens - names, values etc.
+    /// It does not create tokens for the separator between names and values, or for the comma
+    /// between values. It validates the token stream as it goes - so callers can assume that the
+    /// tokens it produces are appropriate. For example, it would never produce "start object, end array."
+    /// </para>
+    /// <para>Implementation details: the base class handles single token push-back and </para>
+    /// <para>Not thread-safe.</para>
+    /// </remarks>
+    internal abstract class JsonTokenizer
+    {
+        private JsonToken bufferedToken;
+
+        /// <summary>
+        ///  Creates a tokenizer that reads from the given text reader.
+        /// </summary>
+        internal static JsonTokenizer FromTextReader(TextReader reader)
+        {
+            return new JsonTextTokenizer(reader);
+        }
+
+        /// <summary>
+        /// Creates a tokenizer that first replays the given list of tokens, then continues reading
+        /// from another tokenizer. Note that if the returned tokenizer is "pushed back", that does not push back
+        /// on the continuation tokenizer, or vice versa. Care should be taken when using this method - it was
+        /// created for the sake of Any parsing.
+        /// </summary>
+        internal static JsonTokenizer FromReplayedTokens(IList<JsonToken> tokens, JsonTokenizer continuation)
+        {
+            return new JsonReplayTokenizer(tokens, continuation);
+        }
+
+        /// <summary>
+        /// Returns the depth of the stack, purely in objects (not collections).
+        /// Informally, this is the number of remaining unclosed '{' characters we have.
+        /// </summary>
+        internal int ObjectDepth { get; private set; }
+
+        // TODO: Why do we allow a different token to be pushed back? It might be better to always remember the previous
+        // token returned, and allow a parameterless Rewind() method (which could only be called once, just like the current PushBack).
+        internal void PushBack(JsonToken token)
+        {
+            if (bufferedToken != null)
+            {
+                throw new InvalidOperationException("Can't push back twice");
+            }
+            bufferedToken = token;
+            if (token.Type == JsonToken.TokenType.StartObject)
+            {
+                ObjectDepth--;
+            }
+            else if (token.Type == JsonToken.TokenType.EndObject)
+            {
+                ObjectDepth++;
+            }
+        }
+
+        /// <summary>
+        /// Returns the next JSON token in the stream. An EndDocument token is returned to indicate the end of the stream,
+        /// after which point <c>Next()</c> should not be called again.
+        /// </summary>
+        /// <remarks>This implementation provides single-token buffering, and calls <see cref="NextImpl"/> if there is no buffered token.</remarks>
+        /// <returns>The next token in the stream. This is never null.</returns>
+        /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
+        /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
+        internal JsonToken Next()
+        {
+            JsonToken tokenToReturn;
+            if (bufferedToken != null)
+            {
+                tokenToReturn = bufferedToken;
+                bufferedToken = null;
+            }
+            else
+            {
+                tokenToReturn = NextImpl();
+            }
+            if (tokenToReturn.Type == JsonToken.TokenType.StartObject)
+            {
+                ObjectDepth++;
+            }
+            else if (tokenToReturn.Type == JsonToken.TokenType.EndObject)
+            {
+                ObjectDepth--;
+            }
+            return tokenToReturn;
+        }
+
+        /// <summary>
+        /// Returns the next JSON token in the stream, when requested by the base class. (The <see cref="Next"/> method delegates
+        /// to this if it doesn't have a buffered token.)
+        /// </summary>
+        /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
+        /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
+        protected abstract JsonToken NextImpl();
+
+        /// <summary>
+        /// Tokenizer which first exhausts a list of tokens, then consults another tokenizer.
+        /// </summary>
+        private class JsonReplayTokenizer : JsonTokenizer
+        {
+            private readonly IList<JsonToken> tokens;
+            private readonly JsonTokenizer nextTokenizer;
+            private int nextTokenIndex;
+
+            internal JsonReplayTokenizer(IList<JsonToken> tokens, JsonTokenizer nextTokenizer)
+            {
+                this.tokens = tokens;
+                this.nextTokenizer = nextTokenizer;
+            }
+
+            // FIXME: Object depth not maintained...
+            protected override JsonToken NextImpl()
+            {
+                if (nextTokenIndex >= tokens.Count)
+                {
+                    return nextTokenizer.Next();
+                }
+                return tokens[nextTokenIndex++];
+            }
+        }
+
+        /// <summary>
+        /// Tokenizer which does all the *real* work of parsing JSON.
+        /// </summary>
+        private sealed class JsonTextTokenizer : JsonTokenizer
+        {
+            // The set of states in which a value is valid next token.
+            private static readonly State ValueStates = State.ArrayStart | State.ArrayAfterComma | State.ObjectAfterColon | State.StartOfDocument;
+
+            private readonly Stack<ContainerType> containerStack = new Stack<ContainerType>();
+            private readonly PushBackReader reader;
+            private State state;
+
+            internal JsonTextTokenizer(TextReader reader)
+            {
+                this.reader = new PushBackReader(reader);
+                state = State.StartOfDocument;
+                containerStack.Push(ContainerType.Document);
+            }
+
+            /// <remarks>
+            /// This method essentially just loops through characters skipping whitespace, validating and
+            /// changing state (e.g. from ObjectBeforeColon to ObjectAfterColon)
+            /// until it reaches something which will be a genuine token (e.g. a start object, or a value) at which point
+            /// it returns the token. Although the method is large, it would be relatively hard to break down further... most
+            /// of it is the large switch statement, which sometimes returns and sometimes doesn't.
+            /// </remarks>
+            protected override JsonToken NextImpl()
+            {
+                if (state == State.ReaderExhausted)
+                {
+                    throw new InvalidOperationException("Next() called after end of document");
+                }
+                while (true)
+                {
+                    var next = reader.Read();
+                    if (next == null)
+                    {
+                        ValidateState(State.ExpectedEndOfDocument, "Unexpected end of document in state: ");
+                        state = State.ReaderExhausted;
+                        return JsonToken.EndDocument;
+                    }
+                    switch (next.Value)
+                    {
+                        // Skip whitespace between tokens
+                        case ' ':
+                        case '\t':
+                        case '\r':
+                        case '\n':
+                            break;
+                        case ':':
+                            ValidateState(State.ObjectBeforeColon, "Invalid state to read a colon: ");
+                            state = State.ObjectAfterColon;
+                            break;
+                        case ',':
+                            ValidateState(State.ObjectAfterProperty | State.ArrayAfterValue, "Invalid state to read a colon: ");
+                            state = state == State.ObjectAfterProperty ? State.ObjectAfterComma : State.ArrayAfterComma;
+                            break;
+                        case '"':
+                            string stringValue = ReadString();
+                            if ((state & (State.ObjectStart | State.ObjectAfterComma)) != 0)
+                            {
+                                state = State.ObjectBeforeColon;
+                                return JsonToken.Name(stringValue);
+                            }
+                            else
+                            {
+                                ValidateAndModifyStateForValue("Invalid state to read a double quote: ");
+                                return JsonToken.Value(stringValue);
+                            }
+                        case '{':
+                            ValidateState(ValueStates, "Invalid state to read an open brace: ");
+                            state = State.ObjectStart;
+                            containerStack.Push(ContainerType.Object);
+                            return JsonToken.StartObject;
+                        case '}':
+                            ValidateState(State.ObjectAfterProperty | State.ObjectStart, "Invalid state to read a close brace: ");
+                            PopContainer();
+                            return JsonToken.EndObject;
+                        case '[':
+                            ValidateState(ValueStates, "Invalid state to read an open square bracket: ");
+                            state = State.ArrayStart;
+                            containerStack.Push(ContainerType.Array);
+                            return JsonToken.StartArray;
+                        case ']':
+                            ValidateState(State.ArrayAfterValue | State.ArrayStart, "Invalid state to read a close square bracket: ");
+                            PopContainer();
+                            return JsonToken.EndArray;
+                        case 'n': // Start of null
+                            ConsumeLiteral("null");
+                            ValidateAndModifyStateForValue("Invalid state to read a null literal: ");
+                            return JsonToken.Null;
+                        case 't': // Start of true
+                            ConsumeLiteral("true");
+                            ValidateAndModifyStateForValue("Invalid state to read a true literal: ");
+                            return JsonToken.True;
+                        case 'f': // Start of false
+                            ConsumeLiteral("false");
+                            ValidateAndModifyStateForValue("Invalid state to read a false literal: ");
+                            return JsonToken.False;
+                        case '-': // Start of a number
+                        case '0':
+                        case '1':
+                        case '2':
+                        case '3':
+                        case '4':
+                        case '5':
+                        case '6':
+                        case '7':
+                        case '8':
+                        case '9':
+                            double number = ReadNumber(next.Value);
+                            ValidateAndModifyStateForValue("Invalid state to read a number token: ");
+                            return JsonToken.Value(number);
+                        default:
+                            throw new InvalidJsonException("Invalid first character of token: " + next.Value);
+                    }
+                }
+            }
+
+            private void ValidateState(State validStates, string errorPrefix)
+            {
+                if ((validStates & state) == 0)
+                {
+                    throw reader.CreateException(errorPrefix + state);
+                }
+            }
+
+            /// <summary>
+            /// Reads a string token. It is assumed that the opening " has already been read.
+            /// </summary>
+            private string ReadString()
+            {
+                var value = new StringBuilder();
+                bool haveHighSurrogate = false;
+                while (true)
+                {
+                    char c = reader.ReadOrFail("Unexpected end of text while reading string");
+                    if (c < ' ')
+                    {
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c));
+                    }
+                    if (c == '"')
+                    {
+                        if (haveHighSurrogate)
+                        {
+                            throw reader.CreateException("Invalid use of surrogate pair code units");
+                        }
+                        return value.ToString();
+                    }
+                    if (c == '\\')
+                    {
+                        c = ReadEscapedCharacter();
+                    }
+                    // TODO: Consider only allowing surrogate pairs that are either both escaped,
+                    // or both not escaped. It would be a very odd text stream that contained a "lone" high surrogate
+                    // followed by an escaped low surrogate or vice versa... and that couldn't even be represented in UTF-8.
+                    if (haveHighSurrogate != char.IsLowSurrogate(c))
+                    {
+                        throw reader.CreateException("Invalid use of surrogate pair code units");
+                    }
+                    haveHighSurrogate = char.IsHighSurrogate(c);
+                    value.Append(c);
+                }
+            }
+
+            /// <summary>
+            /// Reads an escaped character. It is assumed that the leading backslash has already been read.
+            /// </summary>
+            private char ReadEscapedCharacter()
+            {
+                char c = reader.ReadOrFail("Unexpected end of text while reading character escape sequence");
+                switch (c)
+                {
+                    case 'n':
+                        return '\n';
+                    case '\\':
+                        return '\\';
+                    case 'b':
+                        return '\b';
+                    case 'f':
+                        return '\f';
+                    case 'r':
+                        return '\r';
+                    case 't':
+                        return '\t';
+                    case '"':
+                        return '"';
+                    case '/':
+                        return '/';
+                    case 'u':
+                        return ReadUnicodeEscape();
+                    default:
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+                }
+            }
+
+            /// <summary>
+            /// Reads an escaped Unicode 4-nybble hex sequence. It is assumed that the leading \u has already been read.
+            /// </summary>
+            private char ReadUnicodeEscape()
+            {
+                int result = 0;
+                for (int i = 0; i < 4; i++)
+                {
+                    char c = reader.ReadOrFail("Unexpected end of text while reading Unicode escape sequence");
+                    int nybble;
+                    if (c >= '0' && c <= '9')
+                    {
+                        nybble = c - '0';
+                    }
+                    else if (c >= 'a' && c <= 'f')
+                    {
+                        nybble = c - 'a' + 10;
+                    }
+                    else if (c >= 'A' && c <= 'F')
+                    {
+                        nybble = c - 'A' + 10;
+                    }
+                    else
+                    {
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+                    }
+                    result = (result << 4) + nybble;
+                }
+                return (char) result;
+            }
+
+            /// <summary>
+            /// Consumes a text-only literal, throwing an exception if the read text doesn't match it.
+            /// It is assumed that the first letter of the literal has already been read.
+            /// </summary>
+            private void ConsumeLiteral(string text)
+            {
+                for (int i = 1; i < text.Length; i++)
+                {
+                    char? next = reader.Read();
+                    if (next == null)
+                    {
+                        throw reader.CreateException("Unexpected end of text while reading literal token " + text);
+                    }
+                    if (next.Value != text[i])
+                    {
+                        throw reader.CreateException("Unexpected character while reading literal token " + text);
+                    }
+                }
+            }
+
+            private double ReadNumber(char initialCharacter)
+            {
+                StringBuilder builder = new StringBuilder();
+                if (initialCharacter == '-')
+                {
+                    builder.Append("-");
+                }
+                else
+                {
+                    reader.PushBack(initialCharacter);
+                }
+                // Each method returns the character it read that doesn't belong in that part,
+                // so we know what to do next, including pushing the character back at the end.
+                // null is returned for "end of text".
+                char? next = ReadInt(builder);
+                if (next == '.')
+                {
+                    next = ReadFrac(builder);
+                }
+                if (next == 'e' || next == 'E')
+                {
+                    next = ReadExp(builder);
+                }
+                // If we read a character which wasn't part of the number, push it back so we can read it again
+                // to parse the next token.
+                if (next != null)
+                {
+                    reader.PushBack(next.Value);
+                }
+
+                // TODO: What exception should we throw if the value can't be represented as a double?
+                try
+                {
+                    return double.Parse(builder.ToString(),
+                        NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent,
+                        CultureInfo.InvariantCulture);
+                }
+                catch (OverflowException)
+                {
+                    throw reader.CreateException("Numeric value out of range: " + builder);
+                }
+            }
+
+            private char? ReadInt(StringBuilder builder)
+            {
+                char first = reader.ReadOrFail("Invalid numeric literal");
+                if (first < '0' || first > '9')
+                {
+                    throw reader.CreateException("Invalid numeric literal");
+                }
+                builder.Append(first);
+                int digitCount;
+                char? next = ConsumeDigits(builder, out digitCount);
+                if (first == '0' && digitCount != 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value.");
+                }
+                return next;
+            }
+
+            private char? ReadFrac(StringBuilder builder)
+            {
+                builder.Append('.'); // Already consumed this
+                int digitCount;
+                char? next = ConsumeDigits(builder, out digitCount);
+                if (digitCount == 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits");
+                }
+                return next;
+            }
+
+            private char? ReadExp(StringBuilder builder)
+            {
+                builder.Append('E'); // Already consumed this (or 'e')
+                char? next = reader.Read();
+                if (next == null)
+                {
+                    throw reader.CreateException("Invalid numeric literal: exponent with no trailing digits");
+                }
+                if (next == '-' || next == '+')
+                {
+                    builder.Append(next.Value);
+                }
+                else
+                {
+                    reader.PushBack(next.Value);
+                }
+                int digitCount;
+                next = ConsumeDigits(builder, out digitCount);
+                if (digitCount == 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: exponent without value");
+                }
+                return next;
+            }
+
+            private char? ConsumeDigits(StringBuilder builder, out int count)
+            {
+                count = 0;
+                while (true)
+                {
+                    char? next = reader.Read();
+                    if (next == null || next.Value < '0' || next.Value > '9')
+                    {
+                        return next;
+                    }
+                    count++;
+                    builder.Append(next.Value);
+                }
+            }
+
+            /// <summary>
+            /// Validates that we're in a valid state to read a value (using the given error prefix if necessary)
+            /// and changes the state to the appropriate one, e.g. ObjectAfterColon to ObjectAfterProperty.
+            /// </summary>
+            private void ValidateAndModifyStateForValue(string errorPrefix)
+            {
+                ValidateState(ValueStates, errorPrefix);
+                switch (state)
+                {
+                    case State.StartOfDocument:
+                        state = State.ExpectedEndOfDocument;
+                        return;
+                    case State.ObjectAfterColon:
+                        state = State.ObjectAfterProperty;
+                        return;
+                    case State.ArrayStart:
+                    case State.ArrayAfterComma:
+                        state = State.ArrayAfterValue;
+                        return;
+                    default:
+                        throw new InvalidOperationException("ValidateAndModifyStateForValue does not handle all value states (and should)");
+                }
+            }
+
+            /// <summary>
+            /// Pops the top-most container, and sets the state to the appropriate one for the end of a value
+            /// in the parent container.
+            /// </summary>
+            private void PopContainer()
+            {
+                containerStack.Pop();
+                var parent = containerStack.Peek();
+                switch (parent)
+                {
+                    case ContainerType.Object:
+                        state = State.ObjectAfterProperty;
+                        break;
+                    case ContainerType.Array:
+                        state = State.ArrayAfterValue;
+                        break;
+                    case ContainerType.Document:
+                        state = State.ExpectedEndOfDocument;
+                        break;
+                    default:
+                        throw new InvalidOperationException("Unexpected container type: " + parent);
+                }
+            }
+
+            private enum ContainerType
+            {
+                Document, Object, Array
+            }
+
+            /// <summary>
+            /// Possible states of the tokenizer.
+            /// </summary>
+            /// <remarks>
+            /// <para>This is a flags enum purely so we can simply and efficiently represent a set of valid states
+            /// for checking.</para>
+            /// <para>
+            /// Each is documented with an example,
+            /// where ^ represents the current position within the text stream. The examples all use string values,
+            /// but could be any value, including nested objects/arrays.
+            /// The complete state of the tokenizer also includes a stack to indicate the contexts (arrays/objects).
+            /// Any additional notional state of "AfterValue" indicates that a value has been completed, at which 
+            /// point there's an immediate transition to ExpectedEndOfDocument,  ObjectAfterProperty or ArrayAfterValue.
+            /// </para>
+            /// <para>
+            /// These states were derived manually by reading RFC 7159 carefully.
+            /// </para>
+            /// </remarks>
+            [Flags]
+            private enum State
+            {
+                /// <summary>
+                /// ^ { "foo": "bar" }
+                /// Before the value in a document. Next states: ObjectStart, ArrayStart, "AfterValue"
+                /// </summary>
+                StartOfDocument = 1 << 0,
+                /// <summary>
+                /// { "foo": "bar" } ^
+                /// After the value in a document. Next states: ReaderExhausted
+                /// </summary>
+                ExpectedEndOfDocument = 1 << 1,
+                /// <summary>
+                /// { "foo": "bar" } ^ (and already read to the end of the reader)
+                /// Terminal state.
+                /// </summary>
+                ReaderExhausted = 1 << 2,
+                /// <summary>
+                /// { ^ "foo": "bar" }
+                /// Before the *first* property in an object.
+                /// Next states:
+                /// "AfterValue" (empty object)
+                /// ObjectBeforeColon (read a name)
+                /// </summary>
+                ObjectStart = 1 << 3,
+                /// <summary>
+                /// { "foo" ^ : "bar", "x": "y" }
+                /// Next state: ObjectAfterColon
+                /// </summary>
+                ObjectBeforeColon = 1 << 4,
+                /// <summary>
+                /// { "foo" : ^ "bar", "x": "y" }
+                /// Before any property other than the first in an object.
+                /// (Equivalently: after any property in an object) 
+                /// Next states:
+                /// "AfterValue" (value is simple)
+                /// ObjectStart (value is object)
+                /// ArrayStart (value is array)
+                /// </summary>
+                ObjectAfterColon = 1 << 5,
+                /// <summary>
+                /// { "foo" : "bar" ^ , "x" : "y" }
+                /// At the end of a property, so expecting either a comma or end-of-object
+                /// Next states: ObjectAfterComma or "AfterValue"
+                /// </summary>
+                ObjectAfterProperty = 1 << 6,
+                /// <summary>
+                /// { "foo":"bar", ^ "x":"y" }
+                /// Read the comma after the previous property, so expecting another property.
+                /// This is like ObjectStart, but closing brace isn't valid here
+                /// Next state: ObjectBeforeColon.
+                /// </summary>
+                ObjectAfterComma = 1 << 7,
+                /// <summary>
+                /// [ ^ "foo", "bar" ]
+                /// Before the *first* value in an array.
+                /// Next states:
+                /// "AfterValue" (read a value)
+                /// "AfterValue" (end of array; will pop stack)
+                /// </summary>
+                ArrayStart = 1 << 8,
+                /// <summary>
+                /// [ "foo" ^ , "bar" ]
+                /// After any value in an array, so expecting either a comma or end-of-array
+                /// Next states: ArrayAfterComma or "AfterValue"
+                /// </summary>
+                ArrayAfterValue = 1 << 9,
+                /// <summary>
+                /// [ "foo", ^ "bar" ]
+                /// After a comma in an array, so there *must* be another value (simple or complex).
+                /// Next states: "AfterValue" (simple value), StartObject, StartArray
+                /// </summary>
+                ArrayAfterComma = 1 << 10
+            }
+
+            /// <summary>
+            /// Wrapper around a text reader allowing small amounts of buffering and location handling.
+            /// </summary>
+            private class PushBackReader
+            {
+                // TODO: Add locations for errors etc.
+
+                private readonly TextReader reader;
+
+                internal PushBackReader(TextReader reader)
+                {
+                    // TODO: Wrap the reader in a BufferedReader?
+                    this.reader = reader;
+                }
+
+                /// <summary>
+                /// The buffered next character, if we have one.
+                /// </summary>
+                private char? nextChar;
+
+                /// <summary>
+                /// Returns the next character in the stream, or null if we have reached the end.
+                /// </summary>
+                /// <returns></returns>
+                internal char? Read()
+                {
+                    if (nextChar != null)
+                    {
+                        char? tmp = nextChar;
+                        nextChar = null;
+                        return tmp;
+                    }
+                    int next = reader.Read();
+                    return next == -1 ? null : (char?) next;
+                }
+
+                internal char ReadOrFail(string messageOnFailure)
+                {
+                    char? next = Read();
+                    if (next == null)
+                    {
+                        throw CreateException(messageOnFailure);
+                    }
+                    return next.Value;
+                }
+
+                internal void PushBack(char c)
+                {
+                    if (nextChar != null)
+                    {
+                        throw new InvalidOperationException("Cannot push back when already buffering a character");
+                    }
+                    nextChar = c;
+                }
+
+                /// <summary>
+                /// Creates a new exception appropriate for the current state of the reader.
+                /// </summary>
+                internal InvalidJsonException CreateException(string message)
+                {
+                    // TODO: Keep track of and use the location.
+                    return new InvalidJsonException(message);
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/LimitedInputStream.cs b/csharp/src/Google.Protobuf/LimitedInputStream.cs
new file mode 100644
index 0000000..f11d19d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/LimitedInputStream.cs
@@ -0,0 +1,110 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Stream implementation which proxies another stream, only allowing a certain amount
+    /// of data to be read. Note that this is only used to read delimited streams, so it
+    /// doesn't attempt to implement everything.
+    /// </summary>
+    internal sealed class LimitedInputStream : Stream
+    {
+        private readonly Stream proxied;
+        private int bytesLeft;
+
+        internal LimitedInputStream(Stream proxied, int size)
+        {
+            this.proxied = proxied;
+            bytesLeft = size;
+        }
+
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+        public override bool CanWrite
+        {
+            get { return false; }
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override long Length
+        {
+            get { throw new NotSupportedException(); }
+        }
+
+        public override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            if (bytesLeft > 0)
+            {
+                int bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count));
+                bytesLeft -= bytesRead;
+                return bytesRead;
+            }
+            return 0;
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException();
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs
new file mode 100644
index 0000000..047156c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/MessageExtensions.cs
@@ -0,0 +1,157 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Extension methods on <see cref="IMessage"/> and <see cref="IMessage{T}"/>.
+    /// </summary>
+    public static class MessageExtensions
+    {
+        /// <summary>
+        /// Merges data from the given byte array into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = new CodedInputStream(data);
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges data from the given byte string into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
+            CodedInputStream input = data.CreateCodedInput();
+            message.MergeFrom(input);
+            input.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges data from the given stream into an existing message.
+        /// </summary>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            CodedInputStream codedInput = new CodedInputStream(input);
+            message.MergeFrom(codedInput);
+            codedInput.CheckReadEndOfStreamTag();
+        }
+
+        /// <summary>
+        /// Merges length-delimited data from the given stream into an existing message.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="message">The message to merge the data into.</param>
+        /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
+        public static void MergeDelimitedFrom(this IMessage message, Stream input)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
+            int size = (int) CodedInputStream.ReadRawVarint32(input);
+            Stream limitedStream = new LimitedInputStream(input, size);
+            message.MergeFrom(limitedStream);
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte array in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte array.</returns>
+        public static byte[] ToByteArray(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            byte[] result = new byte[message.CalculateSize()];
+            CodedOutputStream output = new CodedOutputStream(result);
+            message.WriteTo(output);
+            output.CheckNoSpaceLeft();
+            return result;
+        }
+
+        /// <summary>
+        /// Writes the given message data to the given stream in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to write to the stream.</param>
+        /// <param name="output">The stream to write to.</param>
+        public static void WriteTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Writes the length and then data of the given message to a stream.
+        /// </summary>
+        /// <param name="message">The message to write.</param>
+        /// <param name="output">The output stream to write to.</param>
+        public static void WriteDelimitedTo(this IMessage message, Stream output)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
+            CodedOutputStream codedOutput = new CodedOutputStream(output);
+            codedOutput.WriteRawVarint32((uint)message.CalculateSize());
+            message.WriteTo(codedOutput);
+            codedOutput.Flush();
+        }
+
+        /// <summary>
+        /// Converts the given message into a byte string in protobuf encoding.
+        /// </summary>
+        /// <param name="message">The message to convert.</param>
+        /// <returns>The message data as a byte string.</returns>
+        public static ByteString ToByteString(this IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            return ByteString.AttachBytes(message.ToByteArray());
+        }        
+    }
+}
diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs
new file mode 100644
index 0000000..8889638
--- /dev/null
+++ b/csharp/src/Google.Protobuf/MessageParser.cs
@@ -0,0 +1,267 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+    
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A general message parser, typically used by reflection-based code as all the methods
+    /// return simple <see cref="IMessage"/>.
+    /// </summary>
+    public class MessageParser
+    {
+        private Func<IMessage> factory;
+
+        internal MessageParser(Func<IMessage> factory)
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal IMessage CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public IMessage ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseDelimitedFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(CodedInputStream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given JSON.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <returns>The parsed message.</returns>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage ParseJson(string json)
+        {
+            IMessage message = factory();
+            JsonParser.Default.Merge(message, json);
+            return message;
+        }
+    }
+
+    /// <summary>
+    /// A parser for a specific message type.
+    /// </summary>
+    /// <remarks>
+    /// <p>
+    /// This delegates most behavior to the
+    /// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
+    /// provides convenient overloads to parse from a variety of sources.
+    /// </p>
+    /// <p>
+    /// Most applications will never need to create their own instances of this type;
+    /// instead, use the static <c>Parser</c> property of a generated message type to obtain a
+    /// parser for that type.
+    /// </p>
+    /// </remarks>
+    /// <typeparam name="T">The type of message to be parsed.</typeparam>
+    public sealed class MessageParser<T> : MessageParser where T : IMessage<T>
+    {
+        // Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
+        // The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
+        // Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
+        // The API wouldn't change anyway - just the implementation - so this work can be deferred.
+        private readonly Func<T> factory; 
+
+        /// <summary>
+        /// Creates a new parser.
+        /// </summary>
+        /// <remarks>
+        /// The factory method is effectively an optimization over using a generic constraint
+        /// to require a parameterless constructor: delegates are significantly faster to execute.
+        /// </remarks>
+        /// <param name="factory">Function to invoke when a new, empty message is required.</param>
+        public MessageParser(Func<T> factory) : base(() => factory())
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal new T CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public new T ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            T message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseDelimitedFrom(Stream input)
+        {
+            T message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public new T ParseFrom(CodedInputStream input)
+        {
+            T message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given JSON.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <returns>The parsed message.</returns>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public new T ParseJson(string json)
+        {
+            T message = factory();
+            JsonParser.Default.Merge(message, json);
+            return message;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..225ac0d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
@@ -0,0 +1,67 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+using System.Reflection;

+using System.Runtime.CompilerServices;

+using System.Security;

+

+// General Information about an assembly is controlled through the following 

+// set of attributes. Change these attribute values to modify the information

+// associated with an assembly.

+

+[assembly: AssemblyTitle("Google.Protobuf")]

+[assembly: AssemblyDescription("")]

+[assembly: AssemblyConfiguration("")]

+[assembly: AssemblyCompany("")]

+[assembly: AssemblyProduct("Google.Protobuf")]

+[assembly: AssemblyCopyright("Copyright ©  2015")]

+[assembly: AssemblyTrademark("")]

+[assembly: AssemblyCulture("")]

+

+#if !NCRUNCH

+[assembly: AllowPartiallyTrustedCallers]

+#endif

+

+#if SIGNED

+[assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" +

+    "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" +

+    "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" +

+    "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" +

+    "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" +

+    "c5ae9cb6")]

+#else

+[assembly: InternalsVisibleTo("Google.Protobuf.Test")]

+#endif

+

+[assembly: AssemblyVersion("3.0.0.0")]

+[assembly: AssemblyFileVersion("3.0.0.0")]

+[assembly: AssemblyInformationalVersion("3.0.0-alpha4")]

diff --git a/csharp/src/Google.Protobuf/ProtoPreconditions.cs b/csharp/src/Google.Protobuf/ProtoPreconditions.cs
new file mode 100644
index 0000000..abaeb9b
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ProtoPreconditions.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Helper methods for throwing exceptions when preconditions are not met.
+    /// </summary>
+    /// <remarks>
+    /// This class is used internally and by generated code; it is not particularly
+    /// expected to be used from application code, although nothing prevents it
+    /// from being used that way.
+    /// </remarks>
+    public static class ProtoPreconditions
+    {
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        public static T CheckNotNull<T>(T value, string name) where T : class
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+
+        /// <summary>
+        /// Throws an ArgumentNullException if the given value is null, otherwise
+        /// return the value to the caller.
+        /// </summary>
+        /// <remarks>
+        /// This is equivalent to <see cref="CheckNotNull{T}(T, string)"/> but without the type parameter
+        /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
+        /// with a value type - but it gets in the way if either you want to use it with a nullable
+        /// value type, or you want to use it with an unconstrained type parameter.
+        /// </remarks>
+        internal static T CheckNotNullUnconstrained<T>(T value, string name)
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(name);
+            }
+            return value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
new file mode 100644
index 0000000..7de7b5f
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
@@ -0,0 +1,5454 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/descriptor.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.Reflection {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/descriptor.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal static partial class DescriptorReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/descriptor.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static DescriptorReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiBnb29nbGUvcHJvdG9idWYvZGVzY3JpcHRvci5wcm90bxIPZ29vZ2xlLnBy",
+            "b3RvYnVmIkcKEUZpbGVEZXNjcmlwdG9yU2V0EjIKBGZpbGUYASADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuRmlsZURlc2NyaXB0b3JQcm90byLbAwoTRmlsZURl",
+            "c2NyaXB0b3JQcm90bxIMCgRuYW1lGAEgASgJEg8KB3BhY2thZ2UYAiABKAkS",
+            "EgoKZGVwZW5kZW5jeRgDIAMoCRIZChFwdWJsaWNfZGVwZW5kZW5jeRgKIAMo",
+            "BRIXCg93ZWFrX2RlcGVuZGVuY3kYCyADKAUSNgoMbWVzc2FnZV90eXBlGAQg",
+            "AygLMiAuZ29vZ2xlLnByb3RvYnVmLkRlc2NyaXB0b3JQcm90bxI3CgllbnVt",
+            "X3R5cGUYBSADKAsyJC5nb29nbGUucHJvdG9idWYuRW51bURlc2NyaXB0b3JQ",
+            "cm90bxI4CgdzZXJ2aWNlGAYgAygLMicuZ29vZ2xlLnByb3RvYnVmLlNlcnZp",
+            "Y2VEZXNjcmlwdG9yUHJvdG8SOAoJZXh0ZW5zaW9uGAcgAygLMiUuZ29vZ2xl",
+            "LnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvEi0KB29wdGlvbnMYCCAB",
+            "KAsyHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMSOQoQc291cmNlX2Nv",
+            "ZGVfaW5mbxgJIAEoCzIfLmdvb2dsZS5wcm90b2J1Zi5Tb3VyY2VDb2RlSW5m",
+            "bxIOCgZzeW50YXgYDCABKAki8AQKD0Rlc2NyaXB0b3JQcm90bxIMCgRuYW1l",
+            "GAEgASgJEjQKBWZpZWxkGAIgAygLMiUuZ29vZ2xlLnByb3RvYnVmLkZpZWxk",
+            "RGVzY3JpcHRvclByb3RvEjgKCWV4dGVuc2lvbhgGIAMoCzIlLmdvb2dsZS5w",
+            "cm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90bxI1CgtuZXN0ZWRfdHlwZRgD",
+            "IAMoCzIgLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG8SNwoJZW51",
+            "bV90eXBlGAQgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9y",
+            "UHJvdG8SSAoPZXh0ZW5zaW9uX3JhbmdlGAUgAygLMi8uZ29vZ2xlLnByb3Rv",
+            "YnVmLkRlc2NyaXB0b3JQcm90by5FeHRlbnNpb25SYW5nZRI5CgpvbmVvZl9k",
+            "ZWNsGAggAygLMiUuZ29vZ2xlLnByb3RvYnVmLk9uZW9mRGVzY3JpcHRvclBy",
+            "b3RvEjAKB29wdGlvbnMYByABKAsyHy5nb29nbGUucHJvdG9idWYuTWVzc2Fn",
+            "ZU9wdGlvbnMSRgoOcmVzZXJ2ZWRfcmFuZ2UYCSADKAsyLi5nb29nbGUucHJv",
+            "dG9idWYuRGVzY3JpcHRvclByb3RvLlJlc2VydmVkUmFuZ2USFQoNcmVzZXJ2",
+            "ZWRfbmFtZRgKIAMoCRosCg5FeHRlbnNpb25SYW5nZRINCgVzdGFydBgBIAEo",
+            "BRILCgNlbmQYAiABKAUaKwoNUmVzZXJ2ZWRSYW5nZRINCgVzdGFydBgBIAEo",
+            "BRILCgNlbmQYAiABKAUivAUKFEZpZWxkRGVzY3JpcHRvclByb3RvEgwKBG5h",
+            "bWUYASABKAkSDgoGbnVtYmVyGAMgASgFEjoKBWxhYmVsGAQgASgOMisuZ29v",
+            "Z2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLkxhYmVsEjgKBHR5",
+            "cGUYBSABKA4yKi5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJv",
+            "dG8uVHlwZRIRCgl0eXBlX25hbWUYBiABKAkSEAoIZXh0ZW5kZWUYAiABKAkS",
+            "FQoNZGVmYXVsdF92YWx1ZRgHIAEoCRITCgtvbmVvZl9pbmRleBgJIAEoBRIR",
+            "Cglqc29uX25hbWUYCiABKAkSLgoHb3B0aW9ucxgIIAEoCzIdLmdvb2dsZS5w",
+            "cm90b2J1Zi5GaWVsZE9wdGlvbnMitgIKBFR5cGUSDwoLVFlQRV9ET1VCTEUQ",
+            "ARIOCgpUWVBFX0ZMT0FUEAISDgoKVFlQRV9JTlQ2NBADEg8KC1RZUEVfVUlO",
+            "VDY0EAQSDgoKVFlQRV9JTlQzMhAFEhAKDFRZUEVfRklYRUQ2NBAGEhAKDFRZ",
+            "UEVfRklYRUQzMhAHEg0KCVRZUEVfQk9PTBAIEg8KC1RZUEVfU1RSSU5HEAkS",
+            "DgoKVFlQRV9HUk9VUBAKEhAKDFRZUEVfTUVTU0FHRRALEg4KClRZUEVfQllU",
+            "RVMQDBIPCgtUWVBFX1VJTlQzMhANEg0KCVRZUEVfRU5VTRAOEhEKDVRZUEVf",
+            "U0ZJWEVEMzIQDxIRCg1UWVBFX1NGSVhFRDY0EBASDwoLVFlQRV9TSU5UMzIQ",
+            "ERIPCgtUWVBFX1NJTlQ2NBASIkMKBUxhYmVsEhIKDkxBQkVMX09QVElPTkFM",
+            "EAESEgoOTEFCRUxfUkVRVUlSRUQQAhISCg5MQUJFTF9SRVBFQVRFRBADIiQK",
+            "FE9uZW9mRGVzY3JpcHRvclByb3RvEgwKBG5hbWUYASABKAkijAEKE0VudW1E",
+            "ZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRI4CgV2YWx1ZRgCIAMoCzIp",
+            "Lmdvb2dsZS5wcm90b2J1Zi5FbnVtVmFsdWVEZXNjcmlwdG9yUHJvdG8SLQoH",
+            "b3B0aW9ucxgDIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5FbnVtT3B0aW9ucyJs",
+            "ChhFbnVtVmFsdWVEZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRIOCgZu",
+            "dW1iZXIYAiABKAUSMgoHb3B0aW9ucxgDIAEoCzIhLmdvb2dsZS5wcm90b2J1",
+            "Zi5FbnVtVmFsdWVPcHRpb25zIpABChZTZXJ2aWNlRGVzY3JpcHRvclByb3Rv",
+            "EgwKBG5hbWUYASABKAkSNgoGbWV0aG9kGAIgAygLMiYuZ29vZ2xlLnByb3Rv",
+            "YnVmLk1ldGhvZERlc2NyaXB0b3JQcm90bxIwCgdvcHRpb25zGAMgASgLMh8u",
+            "Z29vZ2xlLnByb3RvYnVmLlNlcnZpY2VPcHRpb25zIsEBChVNZXRob2REZXNj",
+            "cmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRISCgppbnB1dF90eXBlGAIgASgJ",
+            "EhMKC291dHB1dF90eXBlGAMgASgJEi8KB29wdGlvbnMYBCABKAsyHi5nb29n",
+            "bGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxIfChBjbGllbnRfc3RyZWFtaW5n",
+            "GAUgASgIOgVmYWxzZRIfChBzZXJ2ZXJfc3RyZWFtaW5nGAYgASgIOgVmYWxz",
+            "ZSKuBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwKFGph",
+            "dmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVfZmls",
+            "ZXMYCiABKAg6BWZhbHNlEiwKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2FuZF9o",
+            "YXNoGBQgASgIOgVmYWxzZRIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg",
+            "ASgIOgVmYWxzZRJGCgxvcHRpbWl6ZV9mb3IYCSABKA4yKS5nb29nbGUucHJv",
+            "dG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpnb19w",
+            "YWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6BWZh",
+            "bHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2USIgoT",
+            "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFs",
+            "c2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVz",
+            "cGFjZRglIAEoCRIrCh9qYXZhbmFub191c2VfZGVwcmVjYXRlZF9wYWNrYWdl",
+            "GCYgASgIQgIYARJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRpbWl6",
+            "ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JVTlRJ",
+            "TUUQAyoJCOgHEICAgIACIuYBCg5NZXNzYWdlT3B0aW9ucxImChdtZXNzYWdl",
+            "X3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9fc3RhbmRhcmRf",
+            "ZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMKFHVuaW50ZXJw",
+            "cmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVy",
+            "cHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAMKDEZpZWxkT3B0aW9ucxI6CgVj",
+            "dHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuQ1R5",
+            "cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBlGAYgASgOMiQu",
+            "Z29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6CUpTX05PUk1B",
+            "TBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMgASgIOgVm",
+            "YWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29w",
+            "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w",
+            "dGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoMU1RSSU5H",
+            "X1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpTX1NUUklO",
+            "RxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAIijQEKC0VudW1PcHRpb25z",
+            "EhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZh",
+            "bHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5w",
+            "cm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIifQoQRW51",
+            "bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxzZRJDChR1",
+            "bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYu",
+            "VW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNlcnZpY2VPcHRp",
+            "b25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0",
+            "ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJl",
+            "dGVkT3B0aW9uKgkI6AcQgICAgAIiegoNTWV0aG9kT3B0aW9ucxIZCgpkZXBy",
+            "ZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjn",
+            "ByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJ",
+            "COgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5hbWUYAiAD",
+            "KAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbi5OYW1l",
+            "UGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0aXZlX2lu",
+            "dF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoM",
+            "ZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEoDBIXCg9h",
+            "Z2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0",
+            "GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291cmNlQ29kZUlu",
+            "Zm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYuU291cmNl",
+            "Q29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBhdGgYASADKAVC",
+            "AhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29tbWVudHMYAyAB",
+            "KAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVhZGluZ19kZXRh",
+            "Y2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29kZUluZm8SQQoK",
+            "YW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5HZW5lcmF0ZWRD",
+            "b2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoEcGF0aBgBIAMo",
+            "BUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4YAyABKAUSCwoD",
+            "ZW5kGAQgASgFQlgKE2NvbS5nb29nbGUucHJvdG9idWZCEERlc2NyaXB0b3JQ",
+            "cm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5S",
+            "ZWZsZWN0aW9u"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorSet), global::Google.Protobuf.Reflection.FileDescriptorSet.Parser, new[]{ "File" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorProto), global::Google.Protobuf.Reflection.FileDescriptorProto.Parser, new[]{ "Name", "Package", "Dependency", "PublicDependency", "WeakDependency", "MessageType", "EnumType", "Service", "Extension", "Options", "SourceCodeInfo", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto), global::Google.Protobuf.Reflection.DescriptorProto.Parser, new[]{ "Name", "Field", "Extension", "NestedType", "EnumType", "ExtensionRange", "OneofDecl", "Options", "ReservedRange", "ReservedName" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange), global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange.Parser, new[]{ "Start", "End" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange), global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange.Parser, new[]{ "Start", "End" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto), global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser, new[]{ "Name", "Number", "Label", "Type", "TypeName", "Extendee", "DefaultValue", "OneofIndex", "JsonName", "Options" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type), typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.OneofDescriptorProto), global::Google.Protobuf.Reflection.OneofDescriptorProto.Parser, new[]{ "Name" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumDescriptorProto), global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser, new[]{ "Name", "Value", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueDescriptorProto), global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceDescriptorProto), global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser, new[]{ "Name", "Method", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodDescriptorProto), global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser, new[]{ "Name", "InputType", "OutputType", "Options", "ClientStreaming", "ServerStreaming" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), global::Google.Protobuf.Reflection.FileOptions.Parser, new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "JavananoUseDeprecatedPackage", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MessageOptions), global::Google.Protobuf.Reflection.MessageOptions.Parser, new[]{ "MessageSetWireFormat", "NoStandardDescriptorAccessor", "Deprecated", "MapEntry", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldOptions), global::Google.Protobuf.Reflection.FieldOptions.Parser, new[]{ "Ctype", "Packed", "Jstype", "Lazy", "Deprecated", "Weak", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.CType), typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumOptions), global::Google.Protobuf.Reflection.EnumOptions.Parser, new[]{ "AllowAlias", "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueOptions), global::Google.Protobuf.Reflection.EnumValueOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceOptions), global::Google.Protobuf.Reflection.ServiceOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodOptions), global::Google.Protobuf.Reflection.MethodOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption), global::Google.Protobuf.Reflection.UninterpretedOption.Parser, new[]{ "Name", "IdentifierValue", "PositiveIntValue", "NegativeIntValue", "DoubleValue", "StringValue", "AggregateValue" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart), global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart.Parser, new[]{ "NamePart_", "IsExtension" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo), global::Google.Protobuf.Reflection.SourceCodeInfo.Parser, new[]{ "Location" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location), global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location.Parser, new[]{ "Path", "Span", "LeadingComments", "TrailingComments", "LeadingDetachedComments" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Parser, new[]{ "Annotation" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation.Parser, new[]{ "Path", "SourceFile", "Begin", "End" }, null, null, null)})
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  The protocol compiler can output a FileDescriptorSet containing the .proto
+  ///  files it parses.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FileDescriptorSet : pb::IMessage<FileDescriptorSet> {
+    private static readonly pb::MessageParser<FileDescriptorSet> _parser = new pb::MessageParser<FileDescriptorSet>(() => new FileDescriptorSet());
+    public static pb::MessageParser<FileDescriptorSet> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FileDescriptorSet() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FileDescriptorSet(FileDescriptorSet other) : this() {
+      file_ = other.file_.Clone();
+    }
+
+    public FileDescriptorSet Clone() {
+      return new FileDescriptorSet(this);
+    }
+
+    /// <summary>Field number for the "file" field.</summary>
+    public const int FileFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FileDescriptorProto> _repeated_file_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.FileDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FileDescriptorProto> file_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FileDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FileDescriptorProto> File {
+      get { return file_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FileDescriptorSet);
+    }
+
+    public bool Equals(FileDescriptorSet other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!file_.Equals(other.file_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= file_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      file_.WriteTo(output, _repeated_file_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += file_.CalculateSize(_repeated_file_codec);
+      return size;
+    }
+
+    public void MergeFrom(FileDescriptorSet other) {
+      if (other == null) {
+        return;
+      }
+      file_.Add(other.file_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            file_.AddEntriesFrom(input, _repeated_file_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a complete .proto file.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FileDescriptorProto : pb::IMessage<FileDescriptorProto> {
+    private static readonly pb::MessageParser<FileDescriptorProto> _parser = new pb::MessageParser<FileDescriptorProto>(() => new FileDescriptorProto());
+    public static pb::MessageParser<FileDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FileDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FileDescriptorProto(FileDescriptorProto other) : this() {
+      name_ = other.name_;
+      package_ = other.package_;
+      dependency_ = other.dependency_.Clone();
+      publicDependency_ = other.publicDependency_.Clone();
+      weakDependency_ = other.weakDependency_.Clone();
+      messageType_ = other.messageType_.Clone();
+      enumType_ = other.enumType_.Clone();
+      service_ = other.service_.Clone();
+      extension_ = other.extension_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+      SourceCodeInfo = other.sourceCodeInfo_ != null ? other.SourceCodeInfo.Clone() : null;
+      syntax_ = other.syntax_;
+    }
+
+    public FileDescriptorProto Clone() {
+      return new FileDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  file name, relative to root of source tree
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "package" field.</summary>
+    public const int PackageFieldNumber = 2;
+    private string package_ = "";
+    /// <summary>
+    ///  e.g. "foo", "foo.bar", etc.
+    /// </summary>
+    public string Package {
+      get { return package_; }
+      set {
+        package_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "dependency" field.</summary>
+    public const int DependencyFieldNumber = 3;
+    private static readonly pb::FieldCodec<string> _repeated_dependency_codec
+        = pb::FieldCodec.ForString(26);
+    private readonly pbc::RepeatedField<string> dependency_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  Names of files imported by this file.
+    /// </summary>
+    public pbc::RepeatedField<string> Dependency {
+      get { return dependency_; }
+    }
+
+    /// <summary>Field number for the "public_dependency" field.</summary>
+    public const int PublicDependencyFieldNumber = 10;
+    private static readonly pb::FieldCodec<int> _repeated_publicDependency_codec
+        = pb::FieldCodec.ForInt32(80);
+    private readonly pbc::RepeatedField<int> publicDependency_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Indexes of the public imported files in the dependency list above.
+    /// </summary>
+    public pbc::RepeatedField<int> PublicDependency {
+      get { return publicDependency_; }
+    }
+
+    /// <summary>Field number for the "weak_dependency" field.</summary>
+    public const int WeakDependencyFieldNumber = 11;
+    private static readonly pb::FieldCodec<int> _repeated_weakDependency_codec
+        = pb::FieldCodec.ForInt32(88);
+    private readonly pbc::RepeatedField<int> weakDependency_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Indexes of the weak imported files in the dependency list.
+    ///  For Google-internal migration only. Do not use.
+    /// </summary>
+    public pbc::RepeatedField<int> WeakDependency {
+      get { return weakDependency_; }
+    }
+
+    /// <summary>Field number for the "message_type" field.</summary>
+    public const int MessageTypeFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto> _repeated_messageType_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Reflection.DescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> messageType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto>();
+    /// <summary>
+    ///  All top-level definitions in this file.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> MessageType {
+      get { return messageType_; }
+    }
+
+    /// <summary>Field number for the "enum_type" field.</summary>
+    public const int EnumTypeFieldNumber = 5;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumDescriptorProto> _repeated_enumType_codec
+        = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> enumType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> EnumType {
+      get { return enumType_; }
+    }
+
+    /// <summary>Field number for the "service" field.</summary>
+    public const int ServiceFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.ServiceDescriptorProto> _repeated_service_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.ServiceDescriptorProto> service_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.ServiceDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.ServiceDescriptorProto> Service {
+      get { return service_; }
+    }
+
+    /// <summary>Field number for the "extension" field.</summary>
+    public const int ExtensionFieldNumber = 7;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_extension_codec
+        = pb::FieldCodec.ForMessage(58, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> extension_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> Extension {
+      get { return extension_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 8;
+    private global::Google.Protobuf.Reflection.FileOptions options_;
+    public global::Google.Protobuf.Reflection.FileOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "source_code_info" field.</summary>
+    public const int SourceCodeInfoFieldNumber = 9;
+    private global::Google.Protobuf.Reflection.SourceCodeInfo sourceCodeInfo_;
+    /// <summary>
+    ///  This field contains optional information about the original source code.
+    ///  You may safely remove this entire field without harming runtime
+    ///  functionality of the descriptors -- the information is needed only by
+    ///  development tools.
+    /// </summary>
+    public global::Google.Protobuf.Reflection.SourceCodeInfo SourceCodeInfo {
+      get { return sourceCodeInfo_; }
+      set {
+        sourceCodeInfo_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 12;
+    private string syntax_ = "";
+    /// <summary>
+    ///  The syntax of the proto file.
+    ///  The supported values are "proto2" and "proto3".
+    /// </summary>
+    public string Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FileDescriptorProto);
+    }
+
+    public bool Equals(FileDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Package != other.Package) return false;
+      if(!dependency_.Equals(other.dependency_)) return false;
+      if(!publicDependency_.Equals(other.publicDependency_)) return false;
+      if(!weakDependency_.Equals(other.weakDependency_)) return false;
+      if(!messageType_.Equals(other.messageType_)) return false;
+      if(!enumType_.Equals(other.enumType_)) return false;
+      if(!service_.Equals(other.service_)) return false;
+      if(!extension_.Equals(other.extension_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      if (!object.Equals(SourceCodeInfo, other.SourceCodeInfo)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Package.Length != 0) hash ^= Package.GetHashCode();
+      hash ^= dependency_.GetHashCode();
+      hash ^= publicDependency_.GetHashCode();
+      hash ^= weakDependency_.GetHashCode();
+      hash ^= messageType_.GetHashCode();
+      hash ^= enumType_.GetHashCode();
+      hash ^= service_.GetHashCode();
+      hash ^= extension_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      if (sourceCodeInfo_ != null) hash ^= SourceCodeInfo.GetHashCode();
+      if (Syntax.Length != 0) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Package.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Package);
+      }
+      dependency_.WriteTo(output, _repeated_dependency_codec);
+      messageType_.WriteTo(output, _repeated_messageType_codec);
+      enumType_.WriteTo(output, _repeated_enumType_codec);
+      service_.WriteTo(output, _repeated_service_codec);
+      extension_.WriteTo(output, _repeated_extension_codec);
+      if (options_ != null) {
+        output.WriteRawTag(66);
+        output.WriteMessage(Options);
+      }
+      if (sourceCodeInfo_ != null) {
+        output.WriteRawTag(74);
+        output.WriteMessage(SourceCodeInfo);
+      }
+      publicDependency_.WriteTo(output, _repeated_publicDependency_codec);
+      weakDependency_.WriteTo(output, _repeated_weakDependency_codec);
+      if (Syntax.Length != 0) {
+        output.WriteRawTag(98);
+        output.WriteString(Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Package.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Package);
+      }
+      size += dependency_.CalculateSize(_repeated_dependency_codec);
+      size += publicDependency_.CalculateSize(_repeated_publicDependency_codec);
+      size += weakDependency_.CalculateSize(_repeated_weakDependency_codec);
+      size += messageType_.CalculateSize(_repeated_messageType_codec);
+      size += enumType_.CalculateSize(_repeated_enumType_codec);
+      size += service_.CalculateSize(_repeated_service_codec);
+      size += extension_.CalculateSize(_repeated_extension_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      if (sourceCodeInfo_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceCodeInfo);
+      }
+      if (Syntax.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(FileDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Package.Length != 0) {
+        Package = other.Package;
+      }
+      dependency_.Add(other.dependency_);
+      publicDependency_.Add(other.publicDependency_);
+      weakDependency_.Add(other.weakDependency_);
+      messageType_.Add(other.messageType_);
+      enumType_.Add(other.enumType_);
+      service_.Add(other.service_);
+      extension_.Add(other.extension_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.FileOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+      if (other.sourceCodeInfo_ != null) {
+        if (sourceCodeInfo_ == null) {
+          sourceCodeInfo_ = new global::Google.Protobuf.Reflection.SourceCodeInfo();
+        }
+        SourceCodeInfo.MergeFrom(other.SourceCodeInfo);
+      }
+      if (other.Syntax.Length != 0) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Package = input.ReadString();
+            break;
+          }
+          case 26: {
+            dependency_.AddEntriesFrom(input, _repeated_dependency_codec);
+            break;
+          }
+          case 34: {
+            messageType_.AddEntriesFrom(input, _repeated_messageType_codec);
+            break;
+          }
+          case 42: {
+            enumType_.AddEntriesFrom(input, _repeated_enumType_codec);
+            break;
+          }
+          case 50: {
+            service_.AddEntriesFrom(input, _repeated_service_codec);
+            break;
+          }
+          case 58: {
+            extension_.AddEntriesFrom(input, _repeated_extension_codec);
+            break;
+          }
+          case 66: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.FileOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 74: {
+            if (sourceCodeInfo_ == null) {
+              sourceCodeInfo_ = new global::Google.Protobuf.Reflection.SourceCodeInfo();
+            }
+            input.ReadMessage(sourceCodeInfo_);
+            break;
+          }
+          case 82:
+          case 80: {
+            publicDependency_.AddEntriesFrom(input, _repeated_publicDependency_codec);
+            break;
+          }
+          case 90:
+          case 88: {
+            weakDependency_.AddEntriesFrom(input, _repeated_weakDependency_codec);
+            break;
+          }
+          case 98: {
+            Syntax = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a message type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class DescriptorProto : pb::IMessage<DescriptorProto> {
+    private static readonly pb::MessageParser<DescriptorProto> _parser = new pb::MessageParser<DescriptorProto>(() => new DescriptorProto());
+    public static pb::MessageParser<DescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public DescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public DescriptorProto(DescriptorProto other) : this() {
+      name_ = other.name_;
+      field_ = other.field_.Clone();
+      extension_ = other.extension_.Clone();
+      nestedType_ = other.nestedType_.Clone();
+      enumType_ = other.enumType_.Clone();
+      extensionRange_ = other.extensionRange_.Clone();
+      oneofDecl_ = other.oneofDecl_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+      reservedRange_ = other.reservedRange_.Clone();
+      reservedName_ = other.reservedName_.Clone();
+    }
+
+    public DescriptorProto Clone() {
+      return new DescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "field" field.</summary>
+    public const int FieldFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_field_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> field_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> Field {
+      get { return field_; }
+    }
+
+    /// <summary>Field number for the "extension" field.</summary>
+    public const int ExtensionFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_extension_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> extension_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.FieldDescriptorProto> Extension {
+      get { return extension_; }
+    }
+
+    /// <summary>Field number for the "nested_type" field.</summary>
+    public const int NestedTypeFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto> _repeated_nestedType_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.Reflection.DescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> nestedType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> NestedType {
+      get { return nestedType_; }
+    }
+
+    /// <summary>Field number for the "enum_type" field.</summary>
+    public const int EnumTypeFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumDescriptorProto> _repeated_enumType_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> enumType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumDescriptorProto> EnumType {
+      get { return enumType_; }
+    }
+
+    /// <summary>Field number for the "extension_range" field.</summary>
+    public const int ExtensionRangeFieldNumber = 5;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange> _repeated_extensionRange_codec
+        = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange> extensionRange_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange> ExtensionRange {
+      get { return extensionRange_; }
+    }
+
+    /// <summary>Field number for the "oneof_decl" field.</summary>
+    public const int OneofDeclFieldNumber = 8;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.OneofDescriptorProto> _repeated_oneofDecl_codec
+        = pb::FieldCodec.ForMessage(66, global::Google.Protobuf.Reflection.OneofDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.OneofDescriptorProto> oneofDecl_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.OneofDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.OneofDescriptorProto> OneofDecl {
+      get { return oneofDecl_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 7;
+    private global::Google.Protobuf.Reflection.MessageOptions options_;
+    public global::Google.Protobuf.Reflection.MessageOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "reserved_range" field.</summary>
+    public const int ReservedRangeFieldNumber = 9;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange> _repeated_reservedRange_codec
+        = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange> reservedRange_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange> ReservedRange {
+      get { return reservedRange_; }
+    }
+
+    /// <summary>Field number for the "reserved_name" field.</summary>
+    public const int ReservedNameFieldNumber = 10;
+    private static readonly pb::FieldCodec<string> _repeated_reservedName_codec
+        = pb::FieldCodec.ForString(82);
+    private readonly pbc::RepeatedField<string> reservedName_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  Reserved field names, which may not be used by fields in the same message.
+    ///  A given name may only be reserved once.
+    /// </summary>
+    public pbc::RepeatedField<string> ReservedName {
+      get { return reservedName_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as DescriptorProto);
+    }
+
+    public bool Equals(DescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!field_.Equals(other.field_)) return false;
+      if(!extension_.Equals(other.extension_)) return false;
+      if(!nestedType_.Equals(other.nestedType_)) return false;
+      if(!enumType_.Equals(other.enumType_)) return false;
+      if(!extensionRange_.Equals(other.extensionRange_)) return false;
+      if(!oneofDecl_.Equals(other.oneofDecl_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      if(!reservedRange_.Equals(other.reservedRange_)) return false;
+      if(!reservedName_.Equals(other.reservedName_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= field_.GetHashCode();
+      hash ^= extension_.GetHashCode();
+      hash ^= nestedType_.GetHashCode();
+      hash ^= enumType_.GetHashCode();
+      hash ^= extensionRange_.GetHashCode();
+      hash ^= oneofDecl_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      hash ^= reservedRange_.GetHashCode();
+      hash ^= reservedName_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      field_.WriteTo(output, _repeated_field_codec);
+      nestedType_.WriteTo(output, _repeated_nestedType_codec);
+      enumType_.WriteTo(output, _repeated_enumType_codec);
+      extensionRange_.WriteTo(output, _repeated_extensionRange_codec);
+      extension_.WriteTo(output, _repeated_extension_codec);
+      if (options_ != null) {
+        output.WriteRawTag(58);
+        output.WriteMessage(Options);
+      }
+      oneofDecl_.WriteTo(output, _repeated_oneofDecl_codec);
+      reservedRange_.WriteTo(output, _repeated_reservedRange_codec);
+      reservedName_.WriteTo(output, _repeated_reservedName_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += field_.CalculateSize(_repeated_field_codec);
+      size += extension_.CalculateSize(_repeated_extension_codec);
+      size += nestedType_.CalculateSize(_repeated_nestedType_codec);
+      size += enumType_.CalculateSize(_repeated_enumType_codec);
+      size += extensionRange_.CalculateSize(_repeated_extensionRange_codec);
+      size += oneofDecl_.CalculateSize(_repeated_oneofDecl_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      size += reservedRange_.CalculateSize(_repeated_reservedRange_codec);
+      size += reservedName_.CalculateSize(_repeated_reservedName_codec);
+      return size;
+    }
+
+    public void MergeFrom(DescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      field_.Add(other.field_);
+      extension_.Add(other.extension_);
+      nestedType_.Add(other.nestedType_);
+      enumType_.Add(other.enumType_);
+      extensionRange_.Add(other.extensionRange_);
+      oneofDecl_.Add(other.oneofDecl_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.MessageOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+      reservedRange_.Add(other.reservedRange_);
+      reservedName_.Add(other.reservedName_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            field_.AddEntriesFrom(input, _repeated_field_codec);
+            break;
+          }
+          case 26: {
+            nestedType_.AddEntriesFrom(input, _repeated_nestedType_codec);
+            break;
+          }
+          case 34: {
+            enumType_.AddEntriesFrom(input, _repeated_enumType_codec);
+            break;
+          }
+          case 42: {
+            extensionRange_.AddEntriesFrom(input, _repeated_extensionRange_codec);
+            break;
+          }
+          case 50: {
+            extension_.AddEntriesFrom(input, _repeated_extension_codec);
+            break;
+          }
+          case 58: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.MessageOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 66: {
+            oneofDecl_.AddEntriesFrom(input, _repeated_oneofDecl_codec);
+            break;
+          }
+          case 74: {
+            reservedRange_.AddEntriesFrom(input, _repeated_reservedRange_codec);
+            break;
+          }
+          case 82: {
+            reservedName_.AddEntriesFrom(input, _repeated_reservedName_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the DescriptorProto message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class ExtensionRange : pb::IMessage<ExtensionRange> {
+        private static readonly pb::MessageParser<ExtensionRange> _parser = new pb::MessageParser<ExtensionRange>(() => new ExtensionRange());
+        public static pb::MessageParser<ExtensionRange> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.DescriptorProto.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public ExtensionRange() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public ExtensionRange(ExtensionRange other) : this() {
+          start_ = other.start_;
+          end_ = other.end_;
+        }
+
+        public ExtensionRange Clone() {
+          return new ExtensionRange(this);
+        }
+
+        /// <summary>Field number for the "start" field.</summary>
+        public const int StartFieldNumber = 1;
+        private int start_;
+        public int Start {
+          get { return start_; }
+          set {
+            start_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "end" field.</summary>
+        public const int EndFieldNumber = 2;
+        private int end_;
+        public int End {
+          get { return end_; }
+          set {
+            end_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as ExtensionRange);
+        }
+
+        public bool Equals(ExtensionRange other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (Start != other.Start) return false;
+          if (End != other.End) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (Start != 0) hash ^= Start.GetHashCode();
+          if (End != 0) hash ^= End.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (Start != 0) {
+            output.WriteRawTag(8);
+            output.WriteInt32(Start);
+          }
+          if (End != 0) {
+            output.WriteRawTag(16);
+            output.WriteInt32(End);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (Start != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Start);
+          }
+          if (End != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(End);
+          }
+          return size;
+        }
+
+        public void MergeFrom(ExtensionRange other) {
+          if (other == null) {
+            return;
+          }
+          if (other.Start != 0) {
+            Start = other.Start;
+          }
+          if (other.End != 0) {
+            End = other.End;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 8: {
+                Start = input.ReadInt32();
+                break;
+              }
+              case 16: {
+                End = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+      /// <summary>
+      ///  Range of reserved tag numbers. Reserved tag numbers may not be used by
+      ///  fields or extension ranges in the same message. Reserved ranges may
+      ///  not overlap.
+      /// </summary>
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class ReservedRange : pb::IMessage<ReservedRange> {
+        private static readonly pb::MessageParser<ReservedRange> _parser = new pb::MessageParser<ReservedRange>(() => new ReservedRange());
+        public static pb::MessageParser<ReservedRange> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.DescriptorProto.Descriptor.NestedTypes[1]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public ReservedRange() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public ReservedRange(ReservedRange other) : this() {
+          start_ = other.start_;
+          end_ = other.end_;
+        }
+
+        public ReservedRange Clone() {
+          return new ReservedRange(this);
+        }
+
+        /// <summary>Field number for the "start" field.</summary>
+        public const int StartFieldNumber = 1;
+        private int start_;
+        /// <summary>
+        ///  Inclusive.
+        /// </summary>
+        public int Start {
+          get { return start_; }
+          set {
+            start_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "end" field.</summary>
+        public const int EndFieldNumber = 2;
+        private int end_;
+        /// <summary>
+        ///  Exclusive.
+        /// </summary>
+        public int End {
+          get { return end_; }
+          set {
+            end_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as ReservedRange);
+        }
+
+        public bool Equals(ReservedRange other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (Start != other.Start) return false;
+          if (End != other.End) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (Start != 0) hash ^= Start.GetHashCode();
+          if (End != 0) hash ^= End.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (Start != 0) {
+            output.WriteRawTag(8);
+            output.WriteInt32(Start);
+          }
+          if (End != 0) {
+            output.WriteRawTag(16);
+            output.WriteInt32(End);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (Start != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Start);
+          }
+          if (End != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(End);
+          }
+          return size;
+        }
+
+        public void MergeFrom(ReservedRange other) {
+          if (other == null) {
+            return;
+          }
+          if (other.Start != 0) {
+            Start = other.Start;
+          }
+          if (other.End != 0) {
+            End = other.End;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 8: {
+                Start = input.ReadInt32();
+                break;
+              }
+              case 16: {
+                End = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Describes a field within a message.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FieldDescriptorProto : pb::IMessage<FieldDescriptorProto> {
+    private static readonly pb::MessageParser<FieldDescriptorProto> _parser = new pb::MessageParser<FieldDescriptorProto>(() => new FieldDescriptorProto());
+    public static pb::MessageParser<FieldDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FieldDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FieldDescriptorProto(FieldDescriptorProto other) : this() {
+      name_ = other.name_;
+      number_ = other.number_;
+      label_ = other.label_;
+      type_ = other.type_;
+      typeName_ = other.typeName_;
+      extendee_ = other.extendee_;
+      defaultValue_ = other.defaultValue_;
+      oneofIndex_ = other.oneofIndex_;
+      jsonName_ = other.jsonName_;
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public FieldDescriptorProto Clone() {
+      return new FieldDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 3;
+    private int number_;
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "label" field.</summary>
+    public const int LabelFieldNumber = 4;
+    private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label label_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL;
+    public global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label Label {
+      get { return label_; }
+      set {
+        label_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "type" field.</summary>
+    public const int TypeFieldNumber = 5;
+    private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type type_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE;
+    /// <summary>
+    ///  If type_name is set, this need not be set.  If both this and type_name
+    ///  are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
+    /// </summary>
+    public global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type Type {
+      get { return type_; }
+      set {
+        type_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "type_name" field.</summary>
+    public const int TypeNameFieldNumber = 6;
+    private string typeName_ = "";
+    /// <summary>
+    ///  For message and enum types, this is the name of the type.  If the name
+    ///  starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
+    ///  rules are used to find the type (i.e. first the nested types within this
+    ///  message are searched, then within the parent, on up to the root
+    ///  namespace).
+    /// </summary>
+    public string TypeName {
+      get { return typeName_; }
+      set {
+        typeName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "extendee" field.</summary>
+    public const int ExtendeeFieldNumber = 2;
+    private string extendee_ = "";
+    /// <summary>
+    ///  For extensions, this is the name of the type being extended.  It is
+    ///  resolved in the same manner as type_name.
+    /// </summary>
+    public string Extendee {
+      get { return extendee_; }
+      set {
+        extendee_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "default_value" field.</summary>
+    public const int DefaultValueFieldNumber = 7;
+    private string defaultValue_ = "";
+    /// <summary>
+    ///  For numeric types, contains the original text representation of the value.
+    ///  For booleans, "true" or "false".
+    ///  For strings, contains the default text contents (not escaped in any way).
+    ///  For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
+    ///  TODO(kenton):  Base-64 encode?
+    /// </summary>
+    public string DefaultValue {
+      get { return defaultValue_; }
+      set {
+        defaultValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "oneof_index" field.</summary>
+    public const int OneofIndexFieldNumber = 9;
+    private int oneofIndex_;
+    /// <summary>
+    ///  If set, gives the index of a oneof in the containing type's oneof_decl
+    ///  list.  This field is a member of that oneof.
+    /// </summary>
+    public int OneofIndex {
+      get { return oneofIndex_; }
+      set {
+        oneofIndex_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "json_name" field.</summary>
+    public const int JsonNameFieldNumber = 10;
+    private string jsonName_ = "";
+    /// <summary>
+    ///  JSON name of this field. The value is set by protocol compiler. If the
+    ///  user has set a "json_name" option on this field, that option's value
+    ///  will be used. Otherwise, it's deduced from the field's name by converting
+    ///  it to camelCase.
+    /// </summary>
+    public string JsonName {
+      get { return jsonName_; }
+      set {
+        jsonName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 8;
+    private global::Google.Protobuf.Reflection.FieldOptions options_;
+    public global::Google.Protobuf.Reflection.FieldOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FieldDescriptorProto);
+    }
+
+    public bool Equals(FieldDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Number != other.Number) return false;
+      if (Label != other.Label) return false;
+      if (Type != other.Type) return false;
+      if (TypeName != other.TypeName) return false;
+      if (Extendee != other.Extendee) return false;
+      if (DefaultValue != other.DefaultValue) return false;
+      if (OneofIndex != other.OneofIndex) return false;
+      if (JsonName != other.JsonName) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      if (Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) hash ^= Label.GetHashCode();
+      if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) hash ^= Type.GetHashCode();
+      if (TypeName.Length != 0) hash ^= TypeName.GetHashCode();
+      if (Extendee.Length != 0) hash ^= Extendee.GetHashCode();
+      if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode();
+      if (OneofIndex != 0) hash ^= OneofIndex.GetHashCode();
+      if (JsonName.Length != 0) hash ^= JsonName.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Extendee.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Extendee);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(24);
+        output.WriteInt32(Number);
+      }
+      if (Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
+        output.WriteRawTag(32);
+        output.WriteEnum((int) Label);
+      }
+      if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
+        output.WriteRawTag(40);
+        output.WriteEnum((int) Type);
+      }
+      if (TypeName.Length != 0) {
+        output.WriteRawTag(50);
+        output.WriteString(TypeName);
+      }
+      if (DefaultValue.Length != 0) {
+        output.WriteRawTag(58);
+        output.WriteString(DefaultValue);
+      }
+      if (options_ != null) {
+        output.WriteRawTag(66);
+        output.WriteMessage(Options);
+      }
+      if (OneofIndex != 0) {
+        output.WriteRawTag(72);
+        output.WriteInt32(OneofIndex);
+      }
+      if (JsonName.Length != 0) {
+        output.WriteRawTag(82);
+        output.WriteString(JsonName);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      if (Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Label);
+      }
+      if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
+      }
+      if (TypeName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeName);
+      }
+      if (Extendee.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Extendee);
+      }
+      if (DefaultValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(DefaultValue);
+      }
+      if (OneofIndex != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(OneofIndex);
+      }
+      if (JsonName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName);
+      }
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(FieldDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      if (other.Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) {
+        Label = other.Label;
+      }
+      if (other.Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) {
+        Type = other.Type;
+      }
+      if (other.TypeName.Length != 0) {
+        TypeName = other.TypeName;
+      }
+      if (other.Extendee.Length != 0) {
+        Extendee = other.Extendee;
+      }
+      if (other.DefaultValue.Length != 0) {
+        DefaultValue = other.DefaultValue;
+      }
+      if (other.OneofIndex != 0) {
+        OneofIndex = other.OneofIndex;
+      }
+      if (other.JsonName.Length != 0) {
+        JsonName = other.JsonName;
+      }
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.FieldOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Extendee = input.ReadString();
+            break;
+          }
+          case 24: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 32: {
+            label_ = (global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label) input.ReadEnum();
+            break;
+          }
+          case 40: {
+            type_ = (global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type) input.ReadEnum();
+            break;
+          }
+          case 50: {
+            TypeName = input.ReadString();
+            break;
+          }
+          case 58: {
+            DefaultValue = input.ReadString();
+            break;
+          }
+          case 66: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.FieldOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 72: {
+            OneofIndex = input.ReadInt32();
+            break;
+          }
+          case 82: {
+            JsonName = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the FieldDescriptorProto message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      internal enum Type {
+        /// <summary>
+        ///  0 is reserved for errors.
+        ///  Order is weird for historical reasons.
+        /// </summary>
+        TYPE_DOUBLE = 1,
+        TYPE_FLOAT = 2,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+        ///  negative values are likely.
+        /// </summary>
+        TYPE_INT64 = 3,
+        TYPE_UINT64 = 4,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+        ///  negative values are likely.
+        /// </summary>
+        TYPE_INT32 = 5,
+        TYPE_FIXED64 = 6,
+        TYPE_FIXED32 = 7,
+        TYPE_BOOL = 8,
+        TYPE_STRING = 9,
+        /// <summary>
+        ///  Tag-delimited aggregate.
+        /// </summary>
+        TYPE_GROUP = 10,
+        /// <summary>
+        ///  Length-delimited aggregate.
+        /// </summary>
+        TYPE_MESSAGE = 11,
+        /// <summary>
+        ///  New in version 2.
+        /// </summary>
+        TYPE_BYTES = 12,
+        TYPE_UINT32 = 13,
+        TYPE_ENUM = 14,
+        TYPE_SFIXED32 = 15,
+        TYPE_SFIXED64 = 16,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
+        TYPE_SINT32 = 17,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
+        TYPE_SINT64 = 18,
+      }
+
+      internal enum Label {
+        /// <summary>
+        ///  0 is reserved for errors
+        /// </summary>
+        LABEL_OPTIONAL = 1,
+        LABEL_REQUIRED = 2,
+        /// <summary>
+        ///  TODO(sanjay): Should we add LABEL_MAP?
+        /// </summary>
+        LABEL_REPEATED = 3,
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Describes a oneof.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class OneofDescriptorProto : pb::IMessage<OneofDescriptorProto> {
+    private static readonly pb::MessageParser<OneofDescriptorProto> _parser = new pb::MessageParser<OneofDescriptorProto>(() => new OneofDescriptorProto());
+    public static pb::MessageParser<OneofDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public OneofDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public OneofDescriptorProto(OneofDescriptorProto other) : this() {
+      name_ = other.name_;
+    }
+
+    public OneofDescriptorProto Clone() {
+      return new OneofDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as OneofDescriptorProto);
+    }
+
+    public bool Equals(OneofDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      return size;
+    }
+
+    public void MergeFrom(OneofDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes an enum type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumDescriptorProto : pb::IMessage<EnumDescriptorProto> {
+    private static readonly pb::MessageParser<EnumDescriptorProto> _parser = new pb::MessageParser<EnumDescriptorProto>(() => new EnumDescriptorProto());
+    public static pb::MessageParser<EnumDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[5]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumDescriptorProto(EnumDescriptorProto other) : this() {
+      name_ = other.name_;
+      value_ = other.value_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public EnumDescriptorProto Clone() {
+      return new EnumDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumValueDescriptorProto> _repeated_value_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumValueDescriptorProto> value_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumValueDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.EnumValueDescriptorProto> Value {
+      get { return value_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private global::Google.Protobuf.Reflection.EnumOptions options_;
+    public global::Google.Protobuf.Reflection.EnumOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumDescriptorProto);
+    }
+
+    public bool Equals(EnumDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!value_.Equals(other.value_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= value_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      value_.WriteTo(output, _repeated_value_codec);
+      if (options_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(Options);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += value_.CalculateSize(_repeated_value_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(EnumDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      value_.Add(other.value_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.EnumOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            value_.AddEntriesFrom(input, _repeated_value_codec);
+            break;
+          }
+          case 26: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.EnumOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a value within an enum.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumValueDescriptorProto : pb::IMessage<EnumValueDescriptorProto> {
+    private static readonly pb::MessageParser<EnumValueDescriptorProto> _parser = new pb::MessageParser<EnumValueDescriptorProto>(() => new EnumValueDescriptorProto());
+    public static pb::MessageParser<EnumValueDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[6]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumValueDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumValueDescriptorProto(EnumValueDescriptorProto other) : this() {
+      name_ = other.name_;
+      number_ = other.number_;
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public EnumValueDescriptorProto Clone() {
+      return new EnumValueDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 2;
+    private int number_;
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private global::Google.Protobuf.Reflection.EnumValueOptions options_;
+    public global::Google.Protobuf.Reflection.EnumValueOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumValueDescriptorProto);
+    }
+
+    public bool Equals(EnumValueDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Number != other.Number) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Number);
+      }
+      if (options_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(Options);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(EnumValueDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.EnumValueOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 16: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.EnumValueOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a service.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class ServiceDescriptorProto : pb::IMessage<ServiceDescriptorProto> {
+    private static readonly pb::MessageParser<ServiceDescriptorProto> _parser = new pb::MessageParser<ServiceDescriptorProto>(() => new ServiceDescriptorProto());
+    public static pb::MessageParser<ServiceDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[7]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ServiceDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ServiceDescriptorProto(ServiceDescriptorProto other) : this() {
+      name_ = other.name_;
+      method_ = other.method_.Clone();
+      Options = other.options_ != null ? other.Options.Clone() : null;
+    }
+
+    public ServiceDescriptorProto Clone() {
+      return new ServiceDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "method" field.</summary>
+    public const int MethodFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.MethodDescriptorProto> _repeated_method_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.MethodDescriptorProto> method_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.MethodDescriptorProto>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.MethodDescriptorProto> Method {
+      get { return method_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private global::Google.Protobuf.Reflection.ServiceOptions options_;
+    public global::Google.Protobuf.Reflection.ServiceOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ServiceDescriptorProto);
+    }
+
+    public bool Equals(ServiceDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!method_.Equals(other.method_)) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= method_.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      method_.WriteTo(output, _repeated_method_codec);
+      if (options_ != null) {
+        output.WriteRawTag(26);
+        output.WriteMessage(Options);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += method_.CalculateSize(_repeated_method_codec);
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      return size;
+    }
+
+    public void MergeFrom(ServiceDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      method_.Add(other.method_);
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.ServiceOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            method_.AddEntriesFrom(input, _repeated_method_codec);
+            break;
+          }
+          case 26: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.ServiceOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Describes a method of a service.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class MethodDescriptorProto : pb::IMessage<MethodDescriptorProto> {
+    private static readonly pb::MessageParser<MethodDescriptorProto> _parser = new pb::MessageParser<MethodDescriptorProto>(() => new MethodDescriptorProto());
+    public static pb::MessageParser<MethodDescriptorProto> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[8]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MethodDescriptorProto() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MethodDescriptorProto(MethodDescriptorProto other) : this() {
+      name_ = other.name_;
+      inputType_ = other.inputType_;
+      outputType_ = other.outputType_;
+      Options = other.options_ != null ? other.Options.Clone() : null;
+      clientStreaming_ = other.clientStreaming_;
+      serverStreaming_ = other.serverStreaming_;
+    }
+
+    public MethodDescriptorProto Clone() {
+      return new MethodDescriptorProto(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "input_type" field.</summary>
+    public const int InputTypeFieldNumber = 2;
+    private string inputType_ = "";
+    /// <summary>
+    ///  Input and output type names.  These are resolved in the same way as
+    ///  FieldDescriptorProto.type_name, but must refer to a message type.
+    /// </summary>
+    public string InputType {
+      get { return inputType_; }
+      set {
+        inputType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "output_type" field.</summary>
+    public const int OutputTypeFieldNumber = 3;
+    private string outputType_ = "";
+    public string OutputType {
+      get { return outputType_; }
+      set {
+        outputType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 4;
+    private global::Google.Protobuf.Reflection.MethodOptions options_;
+    public global::Google.Protobuf.Reflection.MethodOptions Options {
+      get { return options_; }
+      set {
+        options_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "client_streaming" field.</summary>
+    public const int ClientStreamingFieldNumber = 5;
+    private bool clientStreaming_;
+    /// <summary>
+    ///  Identifies if client streams multiple client messages
+    /// </summary>
+    public bool ClientStreaming {
+      get { return clientStreaming_; }
+      set {
+        clientStreaming_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "server_streaming" field.</summary>
+    public const int ServerStreamingFieldNumber = 6;
+    private bool serverStreaming_;
+    /// <summary>
+    ///  Identifies if server streams multiple server messages
+    /// </summary>
+    public bool ServerStreaming {
+      get { return serverStreaming_; }
+      set {
+        serverStreaming_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MethodDescriptorProto);
+    }
+
+    public bool Equals(MethodDescriptorProto other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (InputType != other.InputType) return false;
+      if (OutputType != other.OutputType) return false;
+      if (!object.Equals(Options, other.Options)) return false;
+      if (ClientStreaming != other.ClientStreaming) return false;
+      if (ServerStreaming != other.ServerStreaming) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (InputType.Length != 0) hash ^= InputType.GetHashCode();
+      if (OutputType.Length != 0) hash ^= OutputType.GetHashCode();
+      if (options_ != null) hash ^= Options.GetHashCode();
+      if (ClientStreaming != false) hash ^= ClientStreaming.GetHashCode();
+      if (ServerStreaming != false) hash ^= ServerStreaming.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (InputType.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(InputType);
+      }
+      if (OutputType.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(OutputType);
+      }
+      if (options_ != null) {
+        output.WriteRawTag(34);
+        output.WriteMessage(Options);
+      }
+      if (ClientStreaming != false) {
+        output.WriteRawTag(40);
+        output.WriteBool(ClientStreaming);
+      }
+      if (ServerStreaming != false) {
+        output.WriteRawTag(48);
+        output.WriteBool(ServerStreaming);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (InputType.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(InputType);
+      }
+      if (OutputType.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(OutputType);
+      }
+      if (options_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
+      }
+      if (ClientStreaming != false) {
+        size += 1 + 1;
+      }
+      if (ServerStreaming != false) {
+        size += 1 + 1;
+      }
+      return size;
+    }
+
+    public void MergeFrom(MethodDescriptorProto other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.InputType.Length != 0) {
+        InputType = other.InputType;
+      }
+      if (other.OutputType.Length != 0) {
+        OutputType = other.OutputType;
+      }
+      if (other.options_ != null) {
+        if (options_ == null) {
+          options_ = new global::Google.Protobuf.Reflection.MethodOptions();
+        }
+        Options.MergeFrom(other.Options);
+      }
+      if (other.ClientStreaming != false) {
+        ClientStreaming = other.ClientStreaming;
+      }
+      if (other.ServerStreaming != false) {
+        ServerStreaming = other.ServerStreaming;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            InputType = input.ReadString();
+            break;
+          }
+          case 26: {
+            OutputType = input.ReadString();
+            break;
+          }
+          case 34: {
+            if (options_ == null) {
+              options_ = new global::Google.Protobuf.Reflection.MethodOptions();
+            }
+            input.ReadMessage(options_);
+            break;
+          }
+          case 40: {
+            ClientStreaming = input.ReadBool();
+            break;
+          }
+          case 48: {
+            ServerStreaming = input.ReadBool();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FileOptions : pb::IMessage<FileOptions> {
+    private static readonly pb::MessageParser<FileOptions> _parser = new pb::MessageParser<FileOptions>(() => new FileOptions());
+    public static pb::MessageParser<FileOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[9]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FileOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FileOptions(FileOptions other) : this() {
+      javaPackage_ = other.javaPackage_;
+      javaOuterClassname_ = other.javaOuterClassname_;
+      javaMultipleFiles_ = other.javaMultipleFiles_;
+      javaGenerateEqualsAndHash_ = other.javaGenerateEqualsAndHash_;
+      javaStringCheckUtf8_ = other.javaStringCheckUtf8_;
+      optimizeFor_ = other.optimizeFor_;
+      goPackage_ = other.goPackage_;
+      ccGenericServices_ = other.ccGenericServices_;
+      javaGenericServices_ = other.javaGenericServices_;
+      pyGenericServices_ = other.pyGenericServices_;
+      deprecated_ = other.deprecated_;
+      ccEnableArenas_ = other.ccEnableArenas_;
+      objcClassPrefix_ = other.objcClassPrefix_;
+      csharpNamespace_ = other.csharpNamespace_;
+      javananoUseDeprecatedPackage_ = other.javananoUseDeprecatedPackage_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public FileOptions Clone() {
+      return new FileOptions(this);
+    }
+
+    /// <summary>Field number for the "java_package" field.</summary>
+    public const int JavaPackageFieldNumber = 1;
+    private string javaPackage_ = "";
+    /// <summary>
+    ///  Sets the Java package where classes generated from this .proto will be
+    ///  placed.  By default, the proto package is used, but this is often
+    ///  inappropriate because proto packages do not normally start with backwards
+    ///  domain names.
+    /// </summary>
+    public string JavaPackage {
+      get { return javaPackage_; }
+      set {
+        javaPackage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "java_outer_classname" field.</summary>
+    public const int JavaOuterClassnameFieldNumber = 8;
+    private string javaOuterClassname_ = "";
+    /// <summary>
+    ///  If set, all the classes from the .proto file are wrapped in a single
+    ///  outer class with the given name.  This applies to both Proto1
+    ///  (equivalent to the old "--one_java_file" option) and Proto2 (where
+    ///  a .proto always translates to a single class, but you may want to
+    ///  explicitly choose the class name).
+    /// </summary>
+    public string JavaOuterClassname {
+      get { return javaOuterClassname_; }
+      set {
+        javaOuterClassname_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "java_multiple_files" field.</summary>
+    public const int JavaMultipleFilesFieldNumber = 10;
+    private bool javaMultipleFiles_;
+    /// <summary>
+    ///  If set true, then the Java code generator will generate a separate .java
+    ///  file for each top-level message, enum, and service defined in the .proto
+    ///  file.  Thus, these types will *not* be nested inside the outer class
+    ///  named by java_outer_classname.  However, the outer class will still be
+    ///  generated to contain the file's getDescriptor() method as well as any
+    ///  top-level extensions defined in the file.
+    /// </summary>
+    public bool JavaMultipleFiles {
+      get { return javaMultipleFiles_; }
+      set {
+        javaMultipleFiles_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "java_generate_equals_and_hash" field.</summary>
+    public const int JavaGenerateEqualsAndHashFieldNumber = 20;
+    private bool javaGenerateEqualsAndHash_;
+    /// <summary>
+    ///  If set true, then the Java code generator will generate equals() and
+    ///  hashCode() methods for all messages defined in the .proto file.
+    ///  This increases generated code size, potentially substantially for large
+    ///  protos, which may harm a memory-constrained application.
+    ///  - In the full runtime this is a speed optimization, as the
+    ///  AbstractMessage base class includes reflection-based implementations of
+    ///  these methods.
+    ///  - In the lite runtime, setting this option changes the semantics of
+    ///  equals() and hashCode() to more closely match those of the full runtime;
+    ///  the generated methods compute their results based on field values rather
+    ///  than object identity. (Implementations should not assume that hashcodes
+    ///  will be consistent across runtimes or versions of the protocol compiler.)
+    /// </summary>
+    public bool JavaGenerateEqualsAndHash {
+      get { return javaGenerateEqualsAndHash_; }
+      set {
+        javaGenerateEqualsAndHash_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "java_string_check_utf8" field.</summary>
+    public const int JavaStringCheckUtf8FieldNumber = 27;
+    private bool javaStringCheckUtf8_;
+    /// <summary>
+    ///  If set true, then the Java2 code generator will generate code that
+    ///  throws an exception whenever an attempt is made to assign a non-UTF-8
+    ///  byte sequence to a string field.
+    ///  Message reflection will do the same.
+    ///  However, an extension field still accepts non-UTF-8 byte sequences.
+    ///  This option has no effect on when used with the lite runtime.
+    /// </summary>
+    public bool JavaStringCheckUtf8 {
+      get { return javaStringCheckUtf8_; }
+      set {
+        javaStringCheckUtf8_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optimize_for" field.</summary>
+    public const int OptimizeForFieldNumber = 9;
+    private global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode optimizeFor_ = global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED;
+    public global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode OptimizeFor {
+      get { return optimizeFor_; }
+      set {
+        optimizeFor_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "go_package" field.</summary>
+    public const int GoPackageFieldNumber = 11;
+    private string goPackage_ = "";
+    /// <summary>
+    ///  Sets the Go package where structs generated from this .proto will be
+    ///  placed. If omitted, the Go package will be derived from the following:
+    ///    - The basename of the package import path, if provided.
+    ///    - Otherwise, the package statement in the .proto file, if present.
+    ///    - Otherwise, the basename of the .proto file, without extension.
+    /// </summary>
+    public string GoPackage {
+      get { return goPackage_; }
+      set {
+        goPackage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "cc_generic_services" field.</summary>
+    public const int CcGenericServicesFieldNumber = 16;
+    private bool ccGenericServices_;
+    /// <summary>
+    ///  Should generic services be generated in each language?  "Generic" services
+    ///  are not specific to any particular RPC system.  They are generated by the
+    ///  main code generators in each language (without additional plugins).
+    ///  Generic services were the only kind of service generation supported by
+    ///  early versions of google.protobuf.
+    ///
+    ///  Generic services are now considered deprecated in favor of using plugins
+    ///  that generate code specific to your particular RPC system.  Therefore,
+    ///  these default to false.  Old code which depends on generic services should
+    ///  explicitly set them to true.
+    /// </summary>
+    public bool CcGenericServices {
+      get { return ccGenericServices_; }
+      set {
+        ccGenericServices_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "java_generic_services" field.</summary>
+    public const int JavaGenericServicesFieldNumber = 17;
+    private bool javaGenericServices_;
+    public bool JavaGenericServices {
+      get { return javaGenericServices_; }
+      set {
+        javaGenericServices_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "py_generic_services" field.</summary>
+    public const int PyGenericServicesFieldNumber = 18;
+    private bool pyGenericServices_;
+    public bool PyGenericServices {
+      get { return pyGenericServices_; }
+      set {
+        pyGenericServices_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 23;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this file deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for everything in the file, or it will be completely ignored; in the very
+    ///  least, this is a formalization for deprecating files.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "cc_enable_arenas" field.</summary>
+    public const int CcEnableArenasFieldNumber = 31;
+    private bool ccEnableArenas_;
+    /// <summary>
+    ///  Enables the use of arenas for the proto messages in this file. This applies
+    ///  only to generated classes for C++.
+    /// </summary>
+    public bool CcEnableArenas {
+      get { return ccEnableArenas_; }
+      set {
+        ccEnableArenas_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "objc_class_prefix" field.</summary>
+    public const int ObjcClassPrefixFieldNumber = 36;
+    private string objcClassPrefix_ = "";
+    /// <summary>
+    ///  Sets the objective c class prefix which is prepended to all objective c
+    ///  generated classes from this .proto. There is no default.
+    /// </summary>
+    public string ObjcClassPrefix {
+      get { return objcClassPrefix_; }
+      set {
+        objcClassPrefix_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "csharp_namespace" field.</summary>
+    public const int CsharpNamespaceFieldNumber = 37;
+    private string csharpNamespace_ = "";
+    /// <summary>
+    ///  Namespace for generated classes; defaults to the package.
+    /// </summary>
+    public string CsharpNamespace {
+      get { return csharpNamespace_; }
+      set {
+        csharpNamespace_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "javanano_use_deprecated_package" field.</summary>
+    public const int JavananoUseDeprecatedPackageFieldNumber = 38;
+    private bool javananoUseDeprecatedPackage_;
+    /// <summary>
+    ///  Whether the nano proto compiler should generate in the deprecated non-nano
+    ///  suffixed package.
+    /// </summary>
+    [global::System.ObsoleteAttribute()]
+    public bool JavananoUseDeprecatedPackage {
+      get { return javananoUseDeprecatedPackage_; }
+      set {
+        javananoUseDeprecatedPackage_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FileOptions);
+    }
+
+    public bool Equals(FileOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (JavaPackage != other.JavaPackage) return false;
+      if (JavaOuterClassname != other.JavaOuterClassname) return false;
+      if (JavaMultipleFiles != other.JavaMultipleFiles) return false;
+      if (JavaGenerateEqualsAndHash != other.JavaGenerateEqualsAndHash) return false;
+      if (JavaStringCheckUtf8 != other.JavaStringCheckUtf8) return false;
+      if (OptimizeFor != other.OptimizeFor) return false;
+      if (GoPackage != other.GoPackage) return false;
+      if (CcGenericServices != other.CcGenericServices) return false;
+      if (JavaGenericServices != other.JavaGenericServices) return false;
+      if (PyGenericServices != other.PyGenericServices) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if (CcEnableArenas != other.CcEnableArenas) return false;
+      if (ObjcClassPrefix != other.ObjcClassPrefix) return false;
+      if (CsharpNamespace != other.CsharpNamespace) return false;
+      if (JavananoUseDeprecatedPackage != other.JavananoUseDeprecatedPackage) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (JavaPackage.Length != 0) hash ^= JavaPackage.GetHashCode();
+      if (JavaOuterClassname.Length != 0) hash ^= JavaOuterClassname.GetHashCode();
+      if (JavaMultipleFiles != false) hash ^= JavaMultipleFiles.GetHashCode();
+      if (JavaGenerateEqualsAndHash != false) hash ^= JavaGenerateEqualsAndHash.GetHashCode();
+      if (JavaStringCheckUtf8 != false) hash ^= JavaStringCheckUtf8.GetHashCode();
+      if (OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) hash ^= OptimizeFor.GetHashCode();
+      if (GoPackage.Length != 0) hash ^= GoPackage.GetHashCode();
+      if (CcGenericServices != false) hash ^= CcGenericServices.GetHashCode();
+      if (JavaGenericServices != false) hash ^= JavaGenericServices.GetHashCode();
+      if (PyGenericServices != false) hash ^= PyGenericServices.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      if (CcEnableArenas != false) hash ^= CcEnableArenas.GetHashCode();
+      if (ObjcClassPrefix.Length != 0) hash ^= ObjcClassPrefix.GetHashCode();
+      if (CsharpNamespace.Length != 0) hash ^= CsharpNamespace.GetHashCode();
+      if (JavananoUseDeprecatedPackage != false) hash ^= JavananoUseDeprecatedPackage.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (JavaPackage.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(JavaPackage);
+      }
+      if (JavaOuterClassname.Length != 0) {
+        output.WriteRawTag(66);
+        output.WriteString(JavaOuterClassname);
+      }
+      if (OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) {
+        output.WriteRawTag(72);
+        output.WriteEnum((int) OptimizeFor);
+      }
+      if (JavaMultipleFiles != false) {
+        output.WriteRawTag(80);
+        output.WriteBool(JavaMultipleFiles);
+      }
+      if (GoPackage.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(GoPackage);
+      }
+      if (CcGenericServices != false) {
+        output.WriteRawTag(128, 1);
+        output.WriteBool(CcGenericServices);
+      }
+      if (JavaGenericServices != false) {
+        output.WriteRawTag(136, 1);
+        output.WriteBool(JavaGenericServices);
+      }
+      if (PyGenericServices != false) {
+        output.WriteRawTag(144, 1);
+        output.WriteBool(PyGenericServices);
+      }
+      if (JavaGenerateEqualsAndHash != false) {
+        output.WriteRawTag(160, 1);
+        output.WriteBool(JavaGenerateEqualsAndHash);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(184, 1);
+        output.WriteBool(Deprecated);
+      }
+      if (JavaStringCheckUtf8 != false) {
+        output.WriteRawTag(216, 1);
+        output.WriteBool(JavaStringCheckUtf8);
+      }
+      if (CcEnableArenas != false) {
+        output.WriteRawTag(248, 1);
+        output.WriteBool(CcEnableArenas);
+      }
+      if (ObjcClassPrefix.Length != 0) {
+        output.WriteRawTag(162, 2);
+        output.WriteString(ObjcClassPrefix);
+      }
+      if (CsharpNamespace.Length != 0) {
+        output.WriteRawTag(170, 2);
+        output.WriteString(CsharpNamespace);
+      }
+      if (JavananoUseDeprecatedPackage != false) {
+        output.WriteRawTag(176, 2);
+        output.WriteBool(JavananoUseDeprecatedPackage);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (JavaPackage.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JavaPackage);
+      }
+      if (JavaOuterClassname.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JavaOuterClassname);
+      }
+      if (JavaMultipleFiles != false) {
+        size += 1 + 1;
+      }
+      if (JavaGenerateEqualsAndHash != false) {
+        size += 2 + 1;
+      }
+      if (JavaStringCheckUtf8 != false) {
+        size += 2 + 1;
+      }
+      if (OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) OptimizeFor);
+      }
+      if (GoPackage.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(GoPackage);
+      }
+      if (CcGenericServices != false) {
+        size += 2 + 1;
+      }
+      if (JavaGenericServices != false) {
+        size += 2 + 1;
+      }
+      if (PyGenericServices != false) {
+        size += 2 + 1;
+      }
+      if (Deprecated != false) {
+        size += 2 + 1;
+      }
+      if (CcEnableArenas != false) {
+        size += 2 + 1;
+      }
+      if (ObjcClassPrefix.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(ObjcClassPrefix);
+      }
+      if (CsharpNamespace.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(CsharpNamespace);
+      }
+      if (JavananoUseDeprecatedPackage != false) {
+        size += 2 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(FileOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.JavaPackage.Length != 0) {
+        JavaPackage = other.JavaPackage;
+      }
+      if (other.JavaOuterClassname.Length != 0) {
+        JavaOuterClassname = other.JavaOuterClassname;
+      }
+      if (other.JavaMultipleFiles != false) {
+        JavaMultipleFiles = other.JavaMultipleFiles;
+      }
+      if (other.JavaGenerateEqualsAndHash != false) {
+        JavaGenerateEqualsAndHash = other.JavaGenerateEqualsAndHash;
+      }
+      if (other.JavaStringCheckUtf8 != false) {
+        JavaStringCheckUtf8 = other.JavaStringCheckUtf8;
+      }
+      if (other.OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) {
+        OptimizeFor = other.OptimizeFor;
+      }
+      if (other.GoPackage.Length != 0) {
+        GoPackage = other.GoPackage;
+      }
+      if (other.CcGenericServices != false) {
+        CcGenericServices = other.CcGenericServices;
+      }
+      if (other.JavaGenericServices != false) {
+        JavaGenericServices = other.JavaGenericServices;
+      }
+      if (other.PyGenericServices != false) {
+        PyGenericServices = other.PyGenericServices;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      if (other.CcEnableArenas != false) {
+        CcEnableArenas = other.CcEnableArenas;
+      }
+      if (other.ObjcClassPrefix.Length != 0) {
+        ObjcClassPrefix = other.ObjcClassPrefix;
+      }
+      if (other.CsharpNamespace.Length != 0) {
+        CsharpNamespace = other.CsharpNamespace;
+      }
+      if (other.JavananoUseDeprecatedPackage != false) {
+        JavananoUseDeprecatedPackage = other.JavananoUseDeprecatedPackage;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            JavaPackage = input.ReadString();
+            break;
+          }
+          case 66: {
+            JavaOuterClassname = input.ReadString();
+            break;
+          }
+          case 72: {
+            optimizeFor_ = (global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) input.ReadEnum();
+            break;
+          }
+          case 80: {
+            JavaMultipleFiles = input.ReadBool();
+            break;
+          }
+          case 90: {
+            GoPackage = input.ReadString();
+            break;
+          }
+          case 128: {
+            CcGenericServices = input.ReadBool();
+            break;
+          }
+          case 136: {
+            JavaGenericServices = input.ReadBool();
+            break;
+          }
+          case 144: {
+            PyGenericServices = input.ReadBool();
+            break;
+          }
+          case 160: {
+            JavaGenerateEqualsAndHash = input.ReadBool();
+            break;
+          }
+          case 184: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 216: {
+            JavaStringCheckUtf8 = input.ReadBool();
+            break;
+          }
+          case 248: {
+            CcEnableArenas = input.ReadBool();
+            break;
+          }
+          case 290: {
+            ObjcClassPrefix = input.ReadString();
+            break;
+          }
+          case 298: {
+            CsharpNamespace = input.ReadString();
+            break;
+          }
+          case 304: {
+            JavananoUseDeprecatedPackage = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the FileOptions message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      /// <summary>
+      ///  Generated classes can be optimized for speed or code size.
+      /// </summary>
+      internal enum OptimizeMode {
+        /// <summary>
+        ///  Generate complete code for parsing, serialization,
+        /// </summary>
+        SPEED = 1,
+        /// <summary>
+        ///  etc.
+        /// </summary>
+        CODE_SIZE = 2,
+        /// <summary>
+        ///  Generate code using MessageLite and the lite runtime.
+        /// </summary>
+        LITE_RUNTIME = 3,
+      }
+
+    }
+    #endregion
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class MessageOptions : pb::IMessage<MessageOptions> {
+    private static readonly pb::MessageParser<MessageOptions> _parser = new pb::MessageParser<MessageOptions>(() => new MessageOptions());
+    public static pb::MessageParser<MessageOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[10]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MessageOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MessageOptions(MessageOptions other) : this() {
+      messageSetWireFormat_ = other.messageSetWireFormat_;
+      noStandardDescriptorAccessor_ = other.noStandardDescriptorAccessor_;
+      deprecated_ = other.deprecated_;
+      mapEntry_ = other.mapEntry_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public MessageOptions Clone() {
+      return new MessageOptions(this);
+    }
+
+    /// <summary>Field number for the "message_set_wire_format" field.</summary>
+    public const int MessageSetWireFormatFieldNumber = 1;
+    private bool messageSetWireFormat_;
+    /// <summary>
+    ///  Set true to use the old proto1 MessageSet wire format for extensions.
+    ///  This is provided for backwards-compatibility with the MessageSet wire
+    ///  format.  You should not use this for any other reason:  It's less
+    ///  efficient, has fewer features, and is more complicated.
+    ///
+    ///  The message must be defined exactly as follows:
+    ///    message Foo {
+    ///      option message_set_wire_format = true;
+    ///      extensions 4 to max;
+    ///    }
+    ///  Note that the message cannot have any defined fields; MessageSets only
+    ///  have extensions.
+    ///
+    ///  All extensions of your type must be singular messages; e.g. they cannot
+    ///  be int32s, enums, or repeated messages.
+    ///
+    ///  Because this is an option, the above two restrictions are not enforced by
+    ///  the protocol compiler.
+    /// </summary>
+    public bool MessageSetWireFormat {
+      get { return messageSetWireFormat_; }
+      set {
+        messageSetWireFormat_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "no_standard_descriptor_accessor" field.</summary>
+    public const int NoStandardDescriptorAccessorFieldNumber = 2;
+    private bool noStandardDescriptorAccessor_;
+    /// <summary>
+    ///  Disables the generation of the standard "descriptor()" accessor, which can
+    ///  conflict with a field of the same name.  This is meant to make migration
+    ///  from proto1 easier; new code should avoid fields named "descriptor".
+    /// </summary>
+    public bool NoStandardDescriptorAccessor {
+      get { return noStandardDescriptorAccessor_; }
+      set {
+        noStandardDescriptorAccessor_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 3;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this message deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the message, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating messages.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "map_entry" field.</summary>
+    public const int MapEntryFieldNumber = 7;
+    private bool mapEntry_;
+    /// <summary>
+    ///  Whether the message is an automatically generated map entry type for the
+    ///  maps field.
+    ///
+    ///  For maps fields:
+    ///      map&lt;KeyType, ValueType> map_field = 1;
+    ///  The parsed descriptor looks like:
+    ///      message MapFieldEntry {
+    ///          option map_entry = true;
+    ///          optional KeyType key = 1;
+    ///          optional ValueType value = 2;
+    ///      }
+    ///      repeated MapFieldEntry map_field = 1;
+    ///
+    ///  Implementations may choose not to generate the map_entry=true message, but
+    ///  use a native map in the target language to hold the keys and values.
+    ///  The reflection APIs in such implementions still need to work as
+    ///  if the field is a repeated message field.
+    ///
+    ///  NOTE: Do not set the option in .proto files. Always use the maps syntax
+    ///  instead. The option should only be implicitly set by the proto compiler
+    ///  parser.
+    /// </summary>
+    public bool MapEntry {
+      get { return mapEntry_; }
+      set {
+        mapEntry_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MessageOptions);
+    }
+
+    public bool Equals(MessageOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (MessageSetWireFormat != other.MessageSetWireFormat) return false;
+      if (NoStandardDescriptorAccessor != other.NoStandardDescriptorAccessor) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if (MapEntry != other.MapEntry) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (MessageSetWireFormat != false) hash ^= MessageSetWireFormat.GetHashCode();
+      if (NoStandardDescriptorAccessor != false) hash ^= NoStandardDescriptorAccessor.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      if (MapEntry != false) hash ^= MapEntry.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (MessageSetWireFormat != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(MessageSetWireFormat);
+      }
+      if (NoStandardDescriptorAccessor != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(NoStandardDescriptorAccessor);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(Deprecated);
+      }
+      if (MapEntry != false) {
+        output.WriteRawTag(56);
+        output.WriteBool(MapEntry);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (MessageSetWireFormat != false) {
+        size += 1 + 1;
+      }
+      if (NoStandardDescriptorAccessor != false) {
+        size += 1 + 1;
+      }
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      if (MapEntry != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(MessageOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.MessageSetWireFormat != false) {
+        MessageSetWireFormat = other.MessageSetWireFormat;
+      }
+      if (other.NoStandardDescriptorAccessor != false) {
+        NoStandardDescriptorAccessor = other.NoStandardDescriptorAccessor;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      if (other.MapEntry != false) {
+        MapEntry = other.MapEntry;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            MessageSetWireFormat = input.ReadBool();
+            break;
+          }
+          case 16: {
+            NoStandardDescriptorAccessor = input.ReadBool();
+            break;
+          }
+          case 24: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 56: {
+            MapEntry = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class FieldOptions : pb::IMessage<FieldOptions> {
+    private static readonly pb::MessageParser<FieldOptions> _parser = new pb::MessageParser<FieldOptions>(() => new FieldOptions());
+    public static pb::MessageParser<FieldOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[11]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FieldOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FieldOptions(FieldOptions other) : this() {
+      ctype_ = other.ctype_;
+      packed_ = other.packed_;
+      jstype_ = other.jstype_;
+      lazy_ = other.lazy_;
+      deprecated_ = other.deprecated_;
+      weak_ = other.weak_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public FieldOptions Clone() {
+      return new FieldOptions(this);
+    }
+
+    /// <summary>Field number for the "ctype" field.</summary>
+    public const int CtypeFieldNumber = 1;
+    private global::Google.Protobuf.Reflection.FieldOptions.Types.CType ctype_ = global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING;
+    /// <summary>
+    ///  The ctype option instructs the C++ code generator to use a different
+    ///  representation of the field than it normally would.  See the specific
+    ///  options below.  This option is not yet implemented in the open source
+    ///  release -- sorry, we'll try to include it in a future version!
+    /// </summary>
+    public global::Google.Protobuf.Reflection.FieldOptions.Types.CType Ctype {
+      get { return ctype_; }
+      set {
+        ctype_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "packed" field.</summary>
+    public const int PackedFieldNumber = 2;
+    private bool packed_;
+    /// <summary>
+    ///  The packed option can be enabled for repeated primitive fields to enable
+    ///  a more efficient representation on the wire. Rather than repeatedly
+    ///  writing the tag and type for each element, the entire array is encoded as
+    ///  a single length-delimited blob. In proto3, only explicit setting it to
+    ///  false will avoid using packed encoding.
+    /// </summary>
+    public bool Packed {
+      get { return packed_; }
+      set {
+        packed_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "jstype" field.</summary>
+    public const int JstypeFieldNumber = 6;
+    private global::Google.Protobuf.Reflection.FieldOptions.Types.JSType jstype_ = global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL;
+    /// <summary>
+    ///  The jstype option determines the JavaScript type used for values of the
+    ///  field.  The option is permitted only for 64 bit integral and fixed types
+    ///  (int64, uint64, sint64, fixed64, sfixed64).  By default these types are
+    ///  represented as JavaScript strings.  This avoids loss of precision that can
+    ///  happen when a large value is converted to a floating point JavaScript
+    ///  numbers.  Specifying JS_NUMBER for the jstype causes the generated
+    ///  JavaScript code to use the JavaScript "number" type instead of strings.
+    ///  This option is an enum to permit additional types to be added,
+    ///  e.g. goog.math.Integer.
+    /// </summary>
+    public global::Google.Protobuf.Reflection.FieldOptions.Types.JSType Jstype {
+      get { return jstype_; }
+      set {
+        jstype_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "lazy" field.</summary>
+    public const int LazyFieldNumber = 5;
+    private bool lazy_;
+    /// <summary>
+    ///  Should this field be parsed lazily?  Lazy applies only to message-type
+    ///  fields.  It means that when the outer message is initially parsed, the
+    ///  inner message's contents will not be parsed but instead stored in encoded
+    ///  form.  The inner message will actually be parsed when it is first accessed.
+    ///
+    ///  This is only a hint.  Implementations are free to choose whether to use
+    ///  eager or lazy parsing regardless of the value of this option.  However,
+    ///  setting this option true suggests that the protocol author believes that
+    ///  using lazy parsing on this field is worth the additional bookkeeping
+    ///  overhead typically needed to implement it.
+    ///
+    ///  This option does not affect the public interface of any generated code;
+    ///  all method signatures remain the same.  Furthermore, thread-safety of the
+    ///  interface is not affected by this option; const methods remain safe to
+    ///  call from multiple threads concurrently, while non-const methods continue
+    ///  to require exclusive access.
+    ///
+    ///  Note that implementations may choose not to check required fields within
+    ///  a lazy sub-message.  That is, calling IsInitialized() on the outher message
+    ///  may return true even if the inner message has missing required fields.
+    ///  This is necessary because otherwise the inner message would have to be
+    ///  parsed in order to perform the check, defeating the purpose of lazy
+    ///  parsing.  An implementation which chooses not to check required fields
+    ///  must be consistent about it.  That is, for any particular sub-message, the
+    ///  implementation must either *always* check its required fields, or *never*
+    ///  check its required fields, regardless of whether or not the message has
+    ///  been parsed.
+    /// </summary>
+    public bool Lazy {
+      get { return lazy_; }
+      set {
+        lazy_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 3;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this field deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for accessors, or it will be completely ignored; in the very least, this
+    ///  is a formalization for deprecating fields.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "weak" field.</summary>
+    public const int WeakFieldNumber = 10;
+    private bool weak_;
+    /// <summary>
+    ///  For Google-internal migration only. Do not use.
+    /// </summary>
+    public bool Weak {
+      get { return weak_; }
+      set {
+        weak_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FieldOptions);
+    }
+
+    public bool Equals(FieldOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Ctype != other.Ctype) return false;
+      if (Packed != other.Packed) return false;
+      if (Jstype != other.Jstype) return false;
+      if (Lazy != other.Lazy) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if (Weak != other.Weak) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) hash ^= Ctype.GetHashCode();
+      if (Packed != false) hash ^= Packed.GetHashCode();
+      if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) hash ^= Jstype.GetHashCode();
+      if (Lazy != false) hash ^= Lazy.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      if (Weak != false) hash ^= Weak.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) Ctype);
+      }
+      if (Packed != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(Packed);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(Deprecated);
+      }
+      if (Lazy != false) {
+        output.WriteRawTag(40);
+        output.WriteBool(Lazy);
+      }
+      if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) {
+        output.WriteRawTag(48);
+        output.WriteEnum((int) Jstype);
+      }
+      if (Weak != false) {
+        output.WriteRawTag(80);
+        output.WriteBool(Weak);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Ctype);
+      }
+      if (Packed != false) {
+        size += 1 + 1;
+      }
+      if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Jstype);
+      }
+      if (Lazy != false) {
+        size += 1 + 1;
+      }
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      if (Weak != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(FieldOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) {
+        Ctype = other.Ctype;
+      }
+      if (other.Packed != false) {
+        Packed = other.Packed;
+      }
+      if (other.Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) {
+        Jstype = other.Jstype;
+      }
+      if (other.Lazy != false) {
+        Lazy = other.Lazy;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      if (other.Weak != false) {
+        Weak = other.Weak;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            ctype_ = (global::Google.Protobuf.Reflection.FieldOptions.Types.CType) input.ReadEnum();
+            break;
+          }
+          case 16: {
+            Packed = input.ReadBool();
+            break;
+          }
+          case 24: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 40: {
+            Lazy = input.ReadBool();
+            break;
+          }
+          case 48: {
+            jstype_ = (global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) input.ReadEnum();
+            break;
+          }
+          case 80: {
+            Weak = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the FieldOptions message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      internal enum CType {
+        /// <summary>
+        ///  Default mode.
+        /// </summary>
+        STRING = 0,
+        CORD = 1,
+        STRING_PIECE = 2,
+      }
+
+      internal enum JSType {
+        /// <summary>
+        ///  Use the default type.
+        /// </summary>
+        JS_NORMAL = 0,
+        /// <summary>
+        ///  Use JavaScript strings.
+        /// </summary>
+        JS_STRING = 1,
+        /// <summary>
+        ///  Use JavaScript numbers.
+        /// </summary>
+        JS_NUMBER = 2,
+      }
+
+    }
+    #endregion
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumOptions : pb::IMessage<EnumOptions> {
+    private static readonly pb::MessageParser<EnumOptions> _parser = new pb::MessageParser<EnumOptions>(() => new EnumOptions());
+    public static pb::MessageParser<EnumOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[12]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumOptions(EnumOptions other) : this() {
+      allowAlias_ = other.allowAlias_;
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public EnumOptions Clone() {
+      return new EnumOptions(this);
+    }
+
+    /// <summary>Field number for the "allow_alias" field.</summary>
+    public const int AllowAliasFieldNumber = 2;
+    private bool allowAlias_;
+    /// <summary>
+    ///  Set this option to true to allow mapping different tag names to the same
+    ///  value.
+    /// </summary>
+    public bool AllowAlias {
+      get { return allowAlias_; }
+      set {
+        allowAlias_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 3;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this enum deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the enum, or it will be completely ignored; in the very least, this
+    ///  is a formalization for deprecating enums.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumOptions);
+    }
+
+    public bool Equals(EnumOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (AllowAlias != other.AllowAlias) return false;
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (AllowAlias != false) hash ^= AllowAlias.GetHashCode();
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (AllowAlias != false) {
+        output.WriteRawTag(16);
+        output.WriteBool(AllowAlias);
+      }
+      if (Deprecated != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (AllowAlias != false) {
+        size += 1 + 1;
+      }
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(EnumOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.AllowAlias != false) {
+        AllowAlias = other.AllowAlias;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 16: {
+            AllowAlias = input.ReadBool();
+            break;
+          }
+          case 24: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class EnumValueOptions : pb::IMessage<EnumValueOptions> {
+    private static readonly pb::MessageParser<EnumValueOptions> _parser = new pb::MessageParser<EnumValueOptions>(() => new EnumValueOptions());
+    public static pb::MessageParser<EnumValueOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[13]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumValueOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumValueOptions(EnumValueOptions other) : this() {
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public EnumValueOptions Clone() {
+      return new EnumValueOptions(this);
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 1;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this enum value deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the enum value, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating enum values.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumValueOptions);
+    }
+
+    public bool Equals(EnumValueOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Deprecated != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Deprecated != false) {
+        size += 1 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(EnumValueOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class ServiceOptions : pb::IMessage<ServiceOptions> {
+    private static readonly pb::MessageParser<ServiceOptions> _parser = new pb::MessageParser<ServiceOptions>(() => new ServiceOptions());
+    public static pb::MessageParser<ServiceOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[14]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ServiceOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ServiceOptions(ServiceOptions other) : this() {
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public ServiceOptions Clone() {
+      return new ServiceOptions(this);
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 33;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this service deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the service, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating services.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ServiceOptions);
+    }
+
+    public bool Equals(ServiceOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Deprecated != false) {
+        output.WriteRawTag(136, 2);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Deprecated != false) {
+        size += 2 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(ServiceOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 264: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class MethodOptions : pb::IMessage<MethodOptions> {
+    private static readonly pb::MessageParser<MethodOptions> _parser = new pb::MessageParser<MethodOptions>(() => new MethodOptions());
+    public static pb::MessageParser<MethodOptions> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[15]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public MethodOptions() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public MethodOptions(MethodOptions other) : this() {
+      deprecated_ = other.deprecated_;
+      uninterpretedOption_ = other.uninterpretedOption_.Clone();
+    }
+
+    public MethodOptions Clone() {
+      return new MethodOptions(this);
+    }
+
+    /// <summary>Field number for the "deprecated" field.</summary>
+    public const int DeprecatedFieldNumber = 33;
+    private bool deprecated_;
+    /// <summary>
+    ///  Is this method deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the method, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating methods.
+    /// </summary>
+    public bool Deprecated {
+      get { return deprecated_; }
+      set {
+        deprecated_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
+    public const int UninterpretedOptionFieldNumber = 999;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
+        = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
+      get { return uninterpretedOption_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as MethodOptions);
+    }
+
+    public bool Equals(MethodOptions other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Deprecated != other.Deprecated) return false;
+      if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      hash ^= uninterpretedOption_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Deprecated != false) {
+        output.WriteRawTag(136, 2);
+        output.WriteBool(Deprecated);
+      }
+      uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Deprecated != false) {
+        size += 2 + 1;
+      }
+      size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
+      return size;
+    }
+
+    public void MergeFrom(MethodOptions other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Deprecated != false) {
+        Deprecated = other.Deprecated;
+      }
+      uninterpretedOption_.Add(other.uninterpretedOption_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 264: {
+            Deprecated = input.ReadBool();
+            break;
+          }
+          case 7994: {
+            uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A message representing a option the parser does not recognize. This only
+  ///  appears in options protos created by the compiler::Parser class.
+  ///  DescriptorPool resolves these when building Descriptor objects. Therefore,
+  ///  options protos in descriptor objects (e.g. returned by Descriptor::options(),
+  ///  or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+  ///  in them.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class UninterpretedOption : pb::IMessage<UninterpretedOption> {
+    private static readonly pb::MessageParser<UninterpretedOption> _parser = new pb::MessageParser<UninterpretedOption>(() => new UninterpretedOption());
+    public static pb::MessageParser<UninterpretedOption> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[16]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public UninterpretedOption() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public UninterpretedOption(UninterpretedOption other) : this() {
+      name_ = other.name_.Clone();
+      identifierValue_ = other.identifierValue_;
+      positiveIntValue_ = other.positiveIntValue_;
+      negativeIntValue_ = other.negativeIntValue_;
+      doubleValue_ = other.doubleValue_;
+      stringValue_ = other.stringValue_;
+      aggregateValue_ = other.aggregateValue_;
+    }
+
+    public UninterpretedOption Clone() {
+      return new UninterpretedOption(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart> _repeated_name_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart> name_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart>();
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart> Name {
+      get { return name_; }
+    }
+
+    /// <summary>Field number for the "identifier_value" field.</summary>
+    public const int IdentifierValueFieldNumber = 3;
+    private string identifierValue_ = "";
+    /// <summary>
+    ///  The value of the uninterpreted option, in whatever type the tokenizer
+    ///  identified it as during parsing. Exactly one of these should be set.
+    /// </summary>
+    public string IdentifierValue {
+      get { return identifierValue_; }
+      set {
+        identifierValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "positive_int_value" field.</summary>
+    public const int PositiveIntValueFieldNumber = 4;
+    private ulong positiveIntValue_;
+    public ulong PositiveIntValue {
+      get { return positiveIntValue_; }
+      set {
+        positiveIntValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "negative_int_value" field.</summary>
+    public const int NegativeIntValueFieldNumber = 5;
+    private long negativeIntValue_;
+    public long NegativeIntValue {
+      get { return negativeIntValue_; }
+      set {
+        negativeIntValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "double_value" field.</summary>
+    public const int DoubleValueFieldNumber = 6;
+    private double doubleValue_;
+    public double DoubleValue {
+      get { return doubleValue_; }
+      set {
+        doubleValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "string_value" field.</summary>
+    public const int StringValueFieldNumber = 7;
+    private pb::ByteString stringValue_ = pb::ByteString.Empty;
+    public pb::ByteString StringValue {
+      get { return stringValue_; }
+      set {
+        stringValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "aggregate_value" field.</summary>
+    public const int AggregateValueFieldNumber = 8;
+    private string aggregateValue_ = "";
+    public string AggregateValue {
+      get { return aggregateValue_; }
+      set {
+        aggregateValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as UninterpretedOption);
+    }
+
+    public bool Equals(UninterpretedOption other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!name_.Equals(other.name_)) return false;
+      if (IdentifierValue != other.IdentifierValue) return false;
+      if (PositiveIntValue != other.PositiveIntValue) return false;
+      if (NegativeIntValue != other.NegativeIntValue) return false;
+      if (DoubleValue != other.DoubleValue) return false;
+      if (StringValue != other.StringValue) return false;
+      if (AggregateValue != other.AggregateValue) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= name_.GetHashCode();
+      if (IdentifierValue.Length != 0) hash ^= IdentifierValue.GetHashCode();
+      if (PositiveIntValue != 0UL) hash ^= PositiveIntValue.GetHashCode();
+      if (NegativeIntValue != 0L) hash ^= NegativeIntValue.GetHashCode();
+      if (DoubleValue != 0D) hash ^= DoubleValue.GetHashCode();
+      if (StringValue.Length != 0) hash ^= StringValue.GetHashCode();
+      if (AggregateValue.Length != 0) hash ^= AggregateValue.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      name_.WriteTo(output, _repeated_name_codec);
+      if (IdentifierValue.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(IdentifierValue);
+      }
+      if (PositiveIntValue != 0UL) {
+        output.WriteRawTag(32);
+        output.WriteUInt64(PositiveIntValue);
+      }
+      if (NegativeIntValue != 0L) {
+        output.WriteRawTag(40);
+        output.WriteInt64(NegativeIntValue);
+      }
+      if (DoubleValue != 0D) {
+        output.WriteRawTag(49);
+        output.WriteDouble(DoubleValue);
+      }
+      if (StringValue.Length != 0) {
+        output.WriteRawTag(58);
+        output.WriteBytes(StringValue);
+      }
+      if (AggregateValue.Length != 0) {
+        output.WriteRawTag(66);
+        output.WriteString(AggregateValue);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += name_.CalculateSize(_repeated_name_codec);
+      if (IdentifierValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(IdentifierValue);
+      }
+      if (PositiveIntValue != 0UL) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt64Size(PositiveIntValue);
+      }
+      if (NegativeIntValue != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(NegativeIntValue);
+      }
+      if (DoubleValue != 0D) {
+        size += 1 + 8;
+      }
+      if (StringValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(StringValue);
+      }
+      if (AggregateValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(AggregateValue);
+      }
+      return size;
+    }
+
+    public void MergeFrom(UninterpretedOption other) {
+      if (other == null) {
+        return;
+      }
+      name_.Add(other.name_);
+      if (other.IdentifierValue.Length != 0) {
+        IdentifierValue = other.IdentifierValue;
+      }
+      if (other.PositiveIntValue != 0UL) {
+        PositiveIntValue = other.PositiveIntValue;
+      }
+      if (other.NegativeIntValue != 0L) {
+        NegativeIntValue = other.NegativeIntValue;
+      }
+      if (other.DoubleValue != 0D) {
+        DoubleValue = other.DoubleValue;
+      }
+      if (other.StringValue.Length != 0) {
+        StringValue = other.StringValue;
+      }
+      if (other.AggregateValue.Length != 0) {
+        AggregateValue = other.AggregateValue;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 18: {
+            name_.AddEntriesFrom(input, _repeated_name_codec);
+            break;
+          }
+          case 26: {
+            IdentifierValue = input.ReadString();
+            break;
+          }
+          case 32: {
+            PositiveIntValue = input.ReadUInt64();
+            break;
+          }
+          case 40: {
+            NegativeIntValue = input.ReadInt64();
+            break;
+          }
+          case 49: {
+            DoubleValue = input.ReadDouble();
+            break;
+          }
+          case 58: {
+            StringValue = input.ReadBytes();
+            break;
+          }
+          case 66: {
+            AggregateValue = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the UninterpretedOption message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      /// <summary>
+      ///  The name of the uninterpreted option.  Each string represents a segment in
+      ///  a dot-separated name.  is_extension is true iff a segment represents an
+      ///  extension (denoted with parentheses in options specs in .proto files).
+      ///  E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+      ///  "foo.(bar.baz).qux".
+      /// </summary>
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class NamePart : pb::IMessage<NamePart> {
+        private static readonly pb::MessageParser<NamePart> _parser = new pb::MessageParser<NamePart>(() => new NamePart());
+        public static pb::MessageParser<NamePart> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.UninterpretedOption.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public NamePart() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public NamePart(NamePart other) : this() {
+          namePart_ = other.namePart_;
+          isExtension_ = other.isExtension_;
+        }
+
+        public NamePart Clone() {
+          return new NamePart(this);
+        }
+
+        /// <summary>Field number for the "name_part" field.</summary>
+        public const int NamePart_FieldNumber = 1;
+        private string namePart_ = "";
+        public string NamePart_ {
+          get { return namePart_; }
+          set {
+            namePart_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "is_extension" field.</summary>
+        public const int IsExtensionFieldNumber = 2;
+        private bool isExtension_;
+        public bool IsExtension {
+          get { return isExtension_; }
+          set {
+            isExtension_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as NamePart);
+        }
+
+        public bool Equals(NamePart other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if (NamePart_ != other.NamePart_) return false;
+          if (IsExtension != other.IsExtension) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          if (NamePart_.Length != 0) hash ^= NamePart_.GetHashCode();
+          if (IsExtension != false) hash ^= IsExtension.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          if (NamePart_.Length != 0) {
+            output.WriteRawTag(10);
+            output.WriteString(NamePart_);
+          }
+          if (IsExtension != false) {
+            output.WriteRawTag(16);
+            output.WriteBool(IsExtension);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          if (NamePart_.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(NamePart_);
+          }
+          if (IsExtension != false) {
+            size += 1 + 1;
+          }
+          return size;
+        }
+
+        public void MergeFrom(NamePart other) {
+          if (other == null) {
+            return;
+          }
+          if (other.NamePart_.Length != 0) {
+            NamePart_ = other.NamePart_;
+          }
+          if (other.IsExtension != false) {
+            IsExtension = other.IsExtension;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10: {
+                NamePart_ = input.ReadString();
+                break;
+              }
+              case 16: {
+                IsExtension = input.ReadBool();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Encapsulates information about the original source file from which a
+  ///  FileDescriptorProto was generated.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class SourceCodeInfo : pb::IMessage<SourceCodeInfo> {
+    private static readonly pb::MessageParser<SourceCodeInfo> _parser = new pb::MessageParser<SourceCodeInfo>(() => new SourceCodeInfo());
+    public static pb::MessageParser<SourceCodeInfo> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[17]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public SourceCodeInfo() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public SourceCodeInfo(SourceCodeInfo other) : this() {
+      location_ = other.location_.Clone();
+    }
+
+    public SourceCodeInfo Clone() {
+      return new SourceCodeInfo(this);
+    }
+
+    /// <summary>Field number for the "location" field.</summary>
+    public const int LocationFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> _repeated_location_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> location_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location>();
+    /// <summary>
+    ///  A Location identifies a piece of source code in a .proto file which
+    ///  corresponds to a particular definition.  This information is intended
+    ///  to be useful to IDEs, code indexers, documentation generators, and similar
+    ///  tools.
+    ///
+    ///  For example, say we have a file like:
+    ///    message Foo {
+    ///      optional string foo = 1;
+    ///    }
+    ///  Let's look at just the field definition:
+    ///    optional string foo = 1;
+    ///    ^       ^^     ^^  ^  ^^^
+    ///    a       bc     de  f  ghi
+    ///  We have the following locations:
+    ///    span   path               represents
+    ///    [a,i)  [ 4, 0, 2, 0 ]     The whole field definition.
+    ///    [a,b)  [ 4, 0, 2, 0, 4 ]  The label (optional).
+    ///    [c,d)  [ 4, 0, 2, 0, 5 ]  The type (string).
+    ///    [e,f)  [ 4, 0, 2, 0, 1 ]  The name (foo).
+    ///    [g,h)  [ 4, 0, 2, 0, 3 ]  The number (1).
+    ///
+    ///  Notes:
+    ///  - A location may refer to a repeated field itself (i.e. not to any
+    ///    particular index within it).  This is used whenever a set of elements are
+    ///    logically enclosed in a single code segment.  For example, an entire
+    ///    extend block (possibly containing multiple extension definitions) will
+    ///    have an outer location whose path refers to the "extensions" repeated
+    ///    field without an index.
+    ///  - Multiple locations may have the same path.  This happens when a single
+    ///    logical declaration is spread out across multiple places.  The most
+    ///    obvious example is the "extend" block again -- there may be multiple
+    ///    extend blocks in the same scope, each of which will have the same path.
+    ///  - A location's span is not always a subset of its parent's span.  For
+    ///    example, the "extendee" of an extension declaration appears at the
+    ///    beginning of the "extend" block and is shared by all extensions within
+    ///    the block.
+    ///  - Just because a location's span is a subset of some other location's span
+    ///    does not mean that it is a descendent.  For example, a "group" defines
+    ///    both a type and a field in a single declaration.  Thus, the locations
+    ///    corresponding to the type and field and their components will overlap.
+    ///  - Code which tries to interpret locations should probably be designed to
+    ///    ignore those that it doesn't understand, as more types of locations could
+    ///    be recorded in the future.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> Location {
+      get { return location_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as SourceCodeInfo);
+    }
+
+    public bool Equals(SourceCodeInfo other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!location_.Equals(other.location_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= location_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      location_.WriteTo(output, _repeated_location_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += location_.CalculateSize(_repeated_location_codec);
+      return size;
+    }
+
+    public void MergeFrom(SourceCodeInfo other) {
+      if (other == null) {
+        return;
+      }
+      location_.Add(other.location_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            location_.AddEntriesFrom(input, _repeated_location_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the SourceCodeInfo message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class Location : pb::IMessage<Location> {
+        private static readonly pb::MessageParser<Location> _parser = new pb::MessageParser<Location>(() => new Location());
+        public static pb::MessageParser<Location> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.SourceCodeInfo.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public Location() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public Location(Location other) : this() {
+          path_ = other.path_.Clone();
+          span_ = other.span_.Clone();
+          leadingComments_ = other.leadingComments_;
+          trailingComments_ = other.trailingComments_;
+          leadingDetachedComments_ = other.leadingDetachedComments_.Clone();
+        }
+
+        public Location Clone() {
+          return new Location(this);
+        }
+
+        /// <summary>Field number for the "path" field.</summary>
+        public const int PathFieldNumber = 1;
+        private static readonly pb::FieldCodec<int> _repeated_path_codec
+            = pb::FieldCodec.ForInt32(10);
+        private readonly pbc::RepeatedField<int> path_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Identifies which part of the FileDescriptorProto was defined at this
+        ///  location.
+        ///
+        ///  Each element is a field number or an index.  They form a path from
+        ///  the root FileDescriptorProto to the place where the definition.  For
+        ///  example, this path:
+        ///    [ 4, 3, 2, 7, 1 ]
+        ///  refers to:
+        ///    file.message_type(3)  // 4, 3
+        ///        .field(7)         // 2, 7
+        ///        .name()           // 1
+        ///  This is because FileDescriptorProto.message_type has field number 4:
+        ///    repeated DescriptorProto message_type = 4;
+        ///  and DescriptorProto.field has field number 2:
+        ///    repeated FieldDescriptorProto field = 2;
+        ///  and FieldDescriptorProto.name has field number 1:
+        ///    optional string name = 1;
+        ///
+        ///  Thus, the above path gives the location of a field name.  If we removed
+        ///  the last element:
+        ///    [ 4, 3, 2, 7 ]
+        ///  this path refers to the whole field declaration (from the beginning
+        ///  of the label to the terminating semicolon).
+        /// </summary>
+        public pbc::RepeatedField<int> Path {
+          get { return path_; }
+        }
+
+        /// <summary>Field number for the "span" field.</summary>
+        public const int SpanFieldNumber = 2;
+        private static readonly pb::FieldCodec<int> _repeated_span_codec
+            = pb::FieldCodec.ForInt32(18);
+        private readonly pbc::RepeatedField<int> span_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Always has exactly three or four elements: start line, start column,
+        ///  end line (optional, otherwise assumed same as start line), end column.
+        ///  These are packed into a single field for efficiency.  Note that line
+        ///  and column numbers are zero-based -- typically you will want to add
+        ///  1 to each before displaying to a user.
+        /// </summary>
+        public pbc::RepeatedField<int> Span {
+          get { return span_; }
+        }
+
+        /// <summary>Field number for the "leading_comments" field.</summary>
+        public const int LeadingCommentsFieldNumber = 3;
+        private string leadingComments_ = "";
+        /// <summary>
+        ///  If this SourceCodeInfo represents a complete declaration, these are any
+        ///  comments appearing before and after the declaration which appear to be
+        ///  attached to the declaration.
+        ///
+        ///  A series of line comments appearing on consecutive lines, with no other
+        ///  tokens appearing on those lines, will be treated as a single comment.
+        ///
+        ///  leading_detached_comments will keep paragraphs of comments that appear
+        ///  before (but not connected to) the current element. Each paragraph,
+        ///  separated by empty lines, will be one comment element in the repeated
+        ///  field.
+        ///
+        ///  Only the comment content is provided; comment markers (e.g. //) are
+        ///  stripped out.  For block comments, leading whitespace and an asterisk
+        ///  will be stripped from the beginning of each line other than the first.
+        ///  Newlines are included in the output.
+        ///
+        ///  Examples:
+        ///
+        ///    optional int32 foo = 1;  // Comment attached to foo.
+        ///    // Comment attached to bar.
+        ///    optional int32 bar = 2;
+        ///
+        ///    optional string baz = 3;
+        ///    // Comment attached to baz.
+        ///    // Another line attached to baz.
+        ///
+        ///    // Comment attached to qux.
+        ///    //
+        ///    // Another line attached to qux.
+        ///    optional double qux = 4;
+        ///
+        ///    // Detached comment for corge. This is not leading or trailing comments
+        ///    // to qux or corge because there are blank lines separating it from
+        ///    // both.
+        ///
+        ///    // Detached comment for corge paragraph 2.
+        ///
+        ///    optional string corge = 5;
+        ///    /* Block comment attached
+        ///     * to corge.  Leading asterisks
+        ///     * will be removed. */
+        ///    /* Block comment attached to
+        ///     * grault. */
+        ///    optional int32 grault = 6;
+        ///
+        ///    // ignored detached comments.
+        /// </summary>
+        public string LeadingComments {
+          get { return leadingComments_; }
+          set {
+            leadingComments_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "trailing_comments" field.</summary>
+        public const int TrailingCommentsFieldNumber = 4;
+        private string trailingComments_ = "";
+        public string TrailingComments {
+          get { return trailingComments_; }
+          set {
+            trailingComments_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "leading_detached_comments" field.</summary>
+        public const int LeadingDetachedCommentsFieldNumber = 6;
+        private static readonly pb::FieldCodec<string> _repeated_leadingDetachedComments_codec
+            = pb::FieldCodec.ForString(50);
+        private readonly pbc::RepeatedField<string> leadingDetachedComments_ = new pbc::RepeatedField<string>();
+        public pbc::RepeatedField<string> LeadingDetachedComments {
+          get { return leadingDetachedComments_; }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as Location);
+        }
+
+        public bool Equals(Location other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if(!path_.Equals(other.path_)) return false;
+          if(!span_.Equals(other.span_)) return false;
+          if (LeadingComments != other.LeadingComments) return false;
+          if (TrailingComments != other.TrailingComments) return false;
+          if(!leadingDetachedComments_.Equals(other.leadingDetachedComments_)) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          hash ^= path_.GetHashCode();
+          hash ^= span_.GetHashCode();
+          if (LeadingComments.Length != 0) hash ^= LeadingComments.GetHashCode();
+          if (TrailingComments.Length != 0) hash ^= TrailingComments.GetHashCode();
+          hash ^= leadingDetachedComments_.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          path_.WriteTo(output, _repeated_path_codec);
+          span_.WriteTo(output, _repeated_span_codec);
+          if (LeadingComments.Length != 0) {
+            output.WriteRawTag(26);
+            output.WriteString(LeadingComments);
+          }
+          if (TrailingComments.Length != 0) {
+            output.WriteRawTag(34);
+            output.WriteString(TrailingComments);
+          }
+          leadingDetachedComments_.WriteTo(output, _repeated_leadingDetachedComments_codec);
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          size += path_.CalculateSize(_repeated_path_codec);
+          size += span_.CalculateSize(_repeated_span_codec);
+          if (LeadingComments.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(LeadingComments);
+          }
+          if (TrailingComments.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(TrailingComments);
+          }
+          size += leadingDetachedComments_.CalculateSize(_repeated_leadingDetachedComments_codec);
+          return size;
+        }
+
+        public void MergeFrom(Location other) {
+          if (other == null) {
+            return;
+          }
+          path_.Add(other.path_);
+          span_.Add(other.span_);
+          if (other.LeadingComments.Length != 0) {
+            LeadingComments = other.LeadingComments;
+          }
+          if (other.TrailingComments.Length != 0) {
+            TrailingComments = other.TrailingComments;
+          }
+          leadingDetachedComments_.Add(other.leadingDetachedComments_);
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10:
+              case 8: {
+                path_.AddEntriesFrom(input, _repeated_path_codec);
+                break;
+              }
+              case 18:
+              case 16: {
+                span_.AddEntriesFrom(input, _repeated_span_codec);
+                break;
+              }
+              case 26: {
+                LeadingComments = input.ReadString();
+                break;
+              }
+              case 34: {
+                TrailingComments = input.ReadString();
+                break;
+              }
+              case 50: {
+                leadingDetachedComments_.AddEntriesFrom(input, _repeated_leadingDetachedComments_codec);
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Describes the relationship between generated code and its original source
+  ///  file. A GeneratedCodeInfo message is associated with only one generated
+  ///  source file, but may contain references to different source .proto files.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class GeneratedCodeInfo : pb::IMessage<GeneratedCodeInfo> {
+    private static readonly pb::MessageParser<GeneratedCodeInfo> _parser = new pb::MessageParser<GeneratedCodeInfo>(() => new GeneratedCodeInfo());
+    public static pb::MessageParser<GeneratedCodeInfo> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[18]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public GeneratedCodeInfo() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public GeneratedCodeInfo(GeneratedCodeInfo other) : this() {
+      annotation_ = other.annotation_.Clone();
+    }
+
+    public GeneratedCodeInfo Clone() {
+      return new GeneratedCodeInfo(this);
+    }
+
+    /// <summary>Field number for the "annotation" field.</summary>
+    public const int AnnotationFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> _repeated_annotation_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> annotation_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation>();
+    /// <summary>
+    ///  An Annotation connects some span of text in generated code to an element
+    ///  of its generating .proto file.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> Annotation {
+      get { return annotation_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as GeneratedCodeInfo);
+    }
+
+    public bool Equals(GeneratedCodeInfo other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!annotation_.Equals(other.annotation_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= annotation_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      annotation_.WriteTo(output, _repeated_annotation_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += annotation_.CalculateSize(_repeated_annotation_codec);
+      return size;
+    }
+
+    public void MergeFrom(GeneratedCodeInfo other) {
+      if (other == null) {
+        return;
+      }
+      annotation_.Add(other.annotation_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            annotation_.AddEntriesFrom(input, _repeated_annotation_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the GeneratedCodeInfo message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class Annotation : pb::IMessage<Annotation> {
+        private static readonly pb::MessageParser<Annotation> _parser = new pb::MessageParser<Annotation>(() => new Annotation());
+        public static pb::MessageParser<Annotation> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.GeneratedCodeInfo.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public Annotation() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public Annotation(Annotation other) : this() {
+          path_ = other.path_.Clone();
+          sourceFile_ = other.sourceFile_;
+          begin_ = other.begin_;
+          end_ = other.end_;
+        }
+
+        public Annotation Clone() {
+          return new Annotation(this);
+        }
+
+        /// <summary>Field number for the "path" field.</summary>
+        public const int PathFieldNumber = 1;
+        private static readonly pb::FieldCodec<int> _repeated_path_codec
+            = pb::FieldCodec.ForInt32(10);
+        private readonly pbc::RepeatedField<int> path_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Identifies the element in the original source .proto file. This field
+        ///  is formatted the same as SourceCodeInfo.Location.path.
+        /// </summary>
+        public pbc::RepeatedField<int> Path {
+          get { return path_; }
+        }
+
+        /// <summary>Field number for the "source_file" field.</summary>
+        public const int SourceFileFieldNumber = 2;
+        private string sourceFile_ = "";
+        /// <summary>
+        ///  Identifies the filesystem path to the original source .proto.
+        /// </summary>
+        public string SourceFile {
+          get { return sourceFile_; }
+          set {
+            sourceFile_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "begin" field.</summary>
+        public const int BeginFieldNumber = 3;
+        private int begin_;
+        /// <summary>
+        ///  Identifies the starting offset in bytes in the generated code
+        ///  that relates to the identified object.
+        /// </summary>
+        public int Begin {
+          get { return begin_; }
+          set {
+            begin_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "end" field.</summary>
+        public const int EndFieldNumber = 4;
+        private int end_;
+        /// <summary>
+        ///  Identifies the ending offset in bytes in the generated code that
+        ///  relates to the identified offset. The end offset should be one past
+        ///  the last relevant byte (so the length of the text = end - begin).
+        /// </summary>
+        public int End {
+          get { return end_; }
+          set {
+            end_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as Annotation);
+        }
+
+        public bool Equals(Annotation other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if(!path_.Equals(other.path_)) return false;
+          if (SourceFile != other.SourceFile) return false;
+          if (Begin != other.Begin) return false;
+          if (End != other.End) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          hash ^= path_.GetHashCode();
+          if (SourceFile.Length != 0) hash ^= SourceFile.GetHashCode();
+          if (Begin != 0) hash ^= Begin.GetHashCode();
+          if (End != 0) hash ^= End.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          path_.WriteTo(output, _repeated_path_codec);
+          if (SourceFile.Length != 0) {
+            output.WriteRawTag(18);
+            output.WriteString(SourceFile);
+          }
+          if (Begin != 0) {
+            output.WriteRawTag(24);
+            output.WriteInt32(Begin);
+          }
+          if (End != 0) {
+            output.WriteRawTag(32);
+            output.WriteInt32(End);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          size += path_.CalculateSize(_repeated_path_codec);
+          if (SourceFile.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceFile);
+          }
+          if (Begin != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Begin);
+          }
+          if (End != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(End);
+          }
+          return size;
+        }
+
+        public void MergeFrom(Annotation other) {
+          if (other == null) {
+            return;
+          }
+          path_.Add(other.path_);
+          if (other.SourceFile.Length != 0) {
+            SourceFile = other.SourceFile;
+          }
+          if (other.Begin != 0) {
+            Begin = other.Begin;
+          }
+          if (other.End != 0) {
+            End = other.End;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10:
+              case 8: {
+                path_.AddEntriesFrom(input, _repeated_path_codec);
+                break;
+              }
+              case 18: {
+                SourceFile = input.ReadString();
+                break;
+              }
+              case 24: {
+                Begin = input.ReadInt32();
+                break;
+              }
+              case 32: {
+                End = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs
new file mode 100644
index 0000000..194041a
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs
@@ -0,0 +1,85 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Base class for nearly all descriptors, providing common functionality.
+    /// </summary>
+    public abstract class DescriptorBase : IDescriptor
+    {
+        private readonly FileDescriptor file;
+        private readonly string fullName;
+        private readonly int index;
+
+        internal DescriptorBase(FileDescriptor file, string fullName, int index)
+        {
+            this.file = file;
+            this.fullName = fullName;
+            this.index = index;
+        }
+
+        /// <value>
+        /// The index of this descriptor within its parent descriptor. 
+        /// </value>
+        /// <remarks>
+        /// This returns the index of this descriptor within its parent, for
+        /// this descriptor's type. (There can be duplicate values for different
+        /// types, e.g. one enum type with index 0 and one message type with index 0.)
+        /// </remarks>
+        public int Index
+        {
+            get { return index; }
+        }
+
+        /// <summary>
+        /// Returns the name of the entity (field, message etc) being described.
+        /// </summary>
+        public abstract string Name { get; }
+
+        /// <summary>
+        /// The fully qualified name of the descriptor's target.
+        /// </summary>
+        public string FullName
+        {
+            get { return fullName; }
+        }
+
+        /// <value>
+        /// The file this descriptor was declared in.
+        /// </value>
+        public FileDescriptor File
+        {
+            get { return file; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs
new file mode 100644
index 0000000..99ca4bf
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs
@@ -0,0 +1,368 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Contains lookup tables containing all the descriptors defined in a particular file.
+    /// </summary>
+    internal sealed class DescriptorPool
+    {
+        private readonly IDictionary<string, IDescriptor> descriptorsByName =
+            new Dictionary<string, IDescriptor>();
+
+        private readonly IDictionary<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
+            new Dictionary<DescriptorIntPair, FieldDescriptor>();
+
+        private readonly IDictionary<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber =
+            new Dictionary<DescriptorIntPair, EnumValueDescriptor>();
+
+        private readonly HashSet<FileDescriptor> dependencies;
+
+        internal DescriptorPool(FileDescriptor[] dependencyFiles)
+        {
+            dependencies = new HashSet<FileDescriptor>();
+            for (int i = 0; i < dependencyFiles.Length; i++)
+            {
+                dependencies.Add(dependencyFiles[i]);
+                ImportPublicDependencies(dependencyFiles[i]);
+            }
+
+            foreach (FileDescriptor dependency in dependencyFiles)
+            {
+                AddPackage(dependency.Package, dependency);
+            }
+        }
+
+        private void ImportPublicDependencies(FileDescriptor file)
+        {
+            foreach (FileDescriptor dependency in file.PublicDependencies)
+            {
+                if (dependencies.Add(dependency))
+                {
+                    ImportPublicDependencies(dependency);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Finds a symbol of the given name within the pool.
+        /// </summary>
+        /// <typeparam name="T">The type of symbol to look for</typeparam>
+        /// <param name="fullName">Fully-qualified name to look up</param>
+        /// <returns>The symbol with the given name and type,
+        /// or null if the symbol doesn't exist or has the wrong type</returns>
+        internal T FindSymbol<T>(string fullName) where T : class
+        {
+            IDescriptor result;
+            descriptorsByName.TryGetValue(fullName, out result);
+            T descriptor = result as T;
+            if (descriptor != null)
+            {
+                return descriptor;
+            }
+
+            // dependencies contains direct dependencies and any *public* dependencies
+            // of those dependencies (transitively)... so we don't need to recurse here.
+            foreach (FileDescriptor dependency in dependencies)
+            {
+                dependency.DescriptorPool.descriptorsByName.TryGetValue(fullName, out result);
+                descriptor = result as T;
+                if (descriptor != null)
+                {
+                    return descriptor;
+                }
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Adds a package to the symbol tables. If a package by the same name
+        /// already exists, that is fine, but if some other kind of symbol
+        /// exists under the same name, an exception is thrown. If the package
+        /// has multiple components, this also adds the parent package(s).
+        /// </summary>
+        internal void AddPackage(string fullName, FileDescriptor file)
+        {
+            int dotpos = fullName.LastIndexOf('.');
+            String name;
+            if (dotpos != -1)
+            {
+                AddPackage(fullName.Substring(0, dotpos), file);
+                name = fullName.Substring(dotpos + 1);
+            }
+            else
+            {
+                name = fullName;
+            }
+
+            IDescriptor old;
+            if (descriptorsByName.TryGetValue(fullName, out old))
+            {
+                if (!(old is PackageDescriptor))
+                {
+                    throw new DescriptorValidationException(file,
+                                                            "\"" + name +
+                                                            "\" is already defined (as something other than a " +
+                                                            "package) in file \"" + old.File.Name + "\".");
+                }
+            }
+            descriptorsByName[fullName] = new PackageDescriptor(name, fullName, file);
+        }
+
+        /// <summary>
+        /// Adds a symbol to the symbol table.
+        /// </summary>
+        /// <exception cref="DescriptorValidationException">The symbol already existed
+        /// in the symbol table.</exception>
+        internal void AddSymbol(IDescriptor descriptor)
+        {
+            ValidateSymbolName(descriptor);
+            String fullName = descriptor.FullName;
+
+            IDescriptor old;
+            if (descriptorsByName.TryGetValue(fullName, out old))
+            {
+                int dotPos = fullName.LastIndexOf('.');
+                string message;
+                if (descriptor.File == old.File)
+                {
+                    if (dotPos == -1)
+                    {
+                        message = "\"" + fullName + "\" is already defined.";
+                    }
+                    else
+                    {
+                        message = "\"" + fullName.Substring(dotPos + 1) + "\" is already defined in \"" +
+                                  fullName.Substring(0, dotPos) + "\".";
+                    }
+                }
+                else
+                {
+                    message = "\"" + fullName + "\" is already defined in file \"" + old.File.Name + "\".";
+                }
+                throw new DescriptorValidationException(descriptor, message);
+            }
+            descriptorsByName[fullName] = descriptor;
+        }
+
+        private static readonly Regex ValidationRegex = new Regex("^[_A-Za-z][_A-Za-z0-9]*$",
+                                                                  FrameworkPortability.CompiledRegexWhereAvailable);
+
+        /// <summary>
+        /// Verifies that the descriptor's name is valid (i.e. it contains
+        /// only letters, digits and underscores, and does not start with a digit).
+        /// </summary>
+        /// <param name="descriptor"></param>
+        private static void ValidateSymbolName(IDescriptor descriptor)
+        {
+            if (descriptor.Name == "")
+            {
+                throw new DescriptorValidationException(descriptor, "Missing name.");
+            }
+            if (!ValidationRegex.IsMatch(descriptor.Name))
+            {
+                throw new DescriptorValidationException(descriptor,
+                                                        "\"" + descriptor.Name + "\" is not a valid identifier.");
+            }
+        }
+
+        /// <summary>
+        /// Returns the field with the given number in the given descriptor,
+        /// or null if it can't be found.
+        /// </summary>
+        internal FieldDescriptor FindFieldByNumber(MessageDescriptor messageDescriptor, int number)
+        {
+            FieldDescriptor ret;
+            fieldsByNumber.TryGetValue(new DescriptorIntPair(messageDescriptor, number), out ret);
+            return ret;
+        }
+
+        internal EnumValueDescriptor FindEnumValueByNumber(EnumDescriptor enumDescriptor, int number)
+        {
+            EnumValueDescriptor ret;
+            enumValuesByNumber.TryGetValue(new DescriptorIntPair(enumDescriptor, number), out ret);
+            return ret;
+        }
+
+        /// <summary>
+        /// Adds a field to the fieldsByNumber table.
+        /// </summary>
+        /// <exception cref="DescriptorValidationException">A field with the same
+        /// containing type and number already exists.</exception>
+        internal void AddFieldByNumber(FieldDescriptor field)
+        {
+            DescriptorIntPair key = new DescriptorIntPair(field.ContainingType, field.FieldNumber);
+            FieldDescriptor old;
+            if (fieldsByNumber.TryGetValue(key, out old))
+            {
+                throw new DescriptorValidationException(field, "Field number " + field.FieldNumber +
+                                                               "has already been used in \"" +
+                                                               field.ContainingType.FullName +
+                                                               "\" by field \"" + old.Name + "\".");
+            }
+            fieldsByNumber[key] = field;
+        }
+
+        /// <summary>
+        /// Adds an enum value to the enumValuesByNumber table. If an enum value
+        /// with the same type and number already exists, this method does nothing.
+        /// (This is allowed; the first value defined with the number takes precedence.)
+        /// </summary>
+        internal void AddEnumValueByNumber(EnumValueDescriptor enumValue)
+        {
+            DescriptorIntPair key = new DescriptorIntPair(enumValue.EnumDescriptor, enumValue.Number);
+            if (!enumValuesByNumber.ContainsKey(key))
+            {
+                enumValuesByNumber[key] = enumValue;
+            }
+        }
+
+        /// <summary>
+        /// Looks up a descriptor by name, relative to some other descriptor.
+        /// The name may be fully-qualified (with a leading '.'), partially-qualified,
+        /// or unqualified. C++-like name lookup semantics are used to search for the
+        /// matching descriptor.
+        /// </summary>
+        /// <remarks>
+        /// This isn't heavily optimized, but it's only used during cross linking anyway.
+        /// If it starts being used more widely, we should look at performance more carefully.
+        /// </remarks>
+        internal IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
+        {
+            IDescriptor result;
+            if (name.StartsWith("."))
+            {
+                // Fully-qualified name.
+                result = FindSymbol<IDescriptor>(name.Substring(1));
+            }
+            else
+            {
+                // If "name" is a compound identifier, we want to search for the
+                // first component of it, then search within it for the rest.
+                int firstPartLength = name.IndexOf('.');
+                string firstPart = firstPartLength == -1 ? name : name.Substring(0, firstPartLength);
+
+                // We will search each parent scope of "relativeTo" looking for the
+                // symbol.
+                StringBuilder scopeToTry = new StringBuilder(relativeTo.FullName);
+
+                while (true)
+                {
+                    // Chop off the last component of the scope.
+
+                    int dotpos = scopeToTry.ToString().LastIndexOf(".");
+                    if (dotpos == -1)
+                    {
+                        result = FindSymbol<IDescriptor>(name);
+                        break;
+                    }
+                    else
+                    {
+                        scopeToTry.Length = dotpos + 1;
+
+                        // Append firstPart and try to find.
+                        scopeToTry.Append(firstPart);
+                        result = FindSymbol<IDescriptor>(scopeToTry.ToString());
+
+                        if (result != null)
+                        {
+                            if (firstPartLength != -1)
+                            {
+                                // We only found the first part of the symbol.  Now look for
+                                // the whole thing.  If this fails, we *don't* want to keep
+                                // searching parent scopes.
+                                scopeToTry.Length = dotpos + 1;
+                                scopeToTry.Append(name);
+                                result = FindSymbol<IDescriptor>(scopeToTry.ToString());
+                            }
+                            break;
+                        }
+
+                        // Not found.  Remove the name so we can try again.
+                        scopeToTry.Length = dotpos;
+                    }
+                }
+            }
+
+            if (result == null)
+            {
+                throw new DescriptorValidationException(relativeTo, "\"" + name + "\" is not defined.");
+            }
+            else
+            {
+                return result;
+            }
+        }
+
+        /// <summary>
+        /// Struct used to hold the keys for the fieldByNumber table.
+        /// </summary>
+        private struct DescriptorIntPair : IEquatable<DescriptorIntPair>
+        {
+            private readonly int number;
+            private readonly IDescriptor descriptor;
+
+            internal DescriptorIntPair(IDescriptor descriptor, int number)
+            {
+                this.number = number;
+                this.descriptor = descriptor;
+            }
+
+            public bool Equals(DescriptorIntPair other)
+            {
+                return descriptor == other.descriptor
+                       && number == other.number;
+            }
+
+            public override bool Equals(object obj)
+            {
+                if (obj is DescriptorIntPair)
+                {
+                    return Equals((DescriptorIntPair) obj);
+                }
+                return false;
+            }
+
+            public override int GetHashCode()
+            {
+                return descriptor.GetHashCode()*((1 << 16) - 1) + number;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs
new file mode 100644
index 0000000..f5570fc
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Internal class containing utility methods when working with descriptors.
+    /// </summary>
+    internal static class DescriptorUtil
+    {
+        /// <summary>
+        /// Equivalent to Func[TInput, int, TOutput] but usable in .NET 2.0. Only used to convert
+        /// arrays.
+        /// </summary>
+        internal delegate TOutput IndexedConverter<TInput, TOutput>(TInput element, int index);
+
+        /// <summary>
+        /// Converts the given array into a read-only list, applying the specified conversion to
+        /// each input element.
+        /// </summary>
+        internal static IList<TOutput> ConvertAndMakeReadOnly<TInput, TOutput>
+            (IList<TInput> input, IndexedConverter<TInput, TOutput> converter)
+        {
+            TOutput[] array = new TOutput[input.Count];
+            for (int i = 0; i < array.Length; i++)
+            {
+                array[i] = converter(input[i], i);
+            }
+            return new ReadOnlyCollection<TOutput>(array);
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs
new file mode 100644
index 0000000..143671d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs
@@ -0,0 +1,80 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Thrown when building descriptors fails because the source DescriptorProtos
+    /// are not valid.
+    /// </summary>
+    public sealed class DescriptorValidationException : Exception
+    {
+        private readonly String name;
+        private readonly string description;
+
+        /// <value>
+        /// The full name of the descriptor where the error occurred.
+        /// </value>
+        public String ProblemSymbolName
+        {
+            get { return name; }
+        }
+
+        /// <value>
+        /// A human-readable description of the error. (The Message property
+        /// is made up of the descriptor's name and this description.)
+        /// </value>
+        public string Description
+        {
+            get { return description; }
+        }
+
+        internal DescriptorValidationException(IDescriptor problemDescriptor, string description) :
+            base(problemDescriptor.FullName + ": " + description)
+        {
+            // Note that problemDescriptor may be partially uninitialized, so we
+            // don't want to expose it directly to the user.  So, we only provide
+            // the name and the original proto.
+            name = problemDescriptor.FullName;
+            this.description = description;
+        }
+
+        internal DescriptorValidationException(IDescriptor problemDescriptor, string description, Exception cause) :
+            base(problemDescriptor.FullName + ": " + description, cause)
+        {
+            name = problemDescriptor.FullName;
+            this.description = description;
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
new file mode 100644
index 0000000..c732c93
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
@@ -0,0 +1,116 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Descriptor for an enum type in a .proto file.
+    /// </summary>
+    public sealed class EnumDescriptor : DescriptorBase
+    {
+        private readonly EnumDescriptorProto proto;
+        private readonly MessageDescriptor containingType;
+        private readonly IList<EnumValueDescriptor> values;
+        private readonly Type clrType;
+
+        internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type clrType)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
+        {
+            this.proto = proto;
+            this.clrType = clrType;
+            containingType = parent;
+
+            if (proto.Value.Count == 0)
+            {
+                // We cannot allow enums with no values because this would mean there
+                // would be no valid default value for fields of this type.
+                throw new DescriptorValidationException(this, "Enums must contain at least one value.");
+            }
+
+            values = DescriptorUtil.ConvertAndMakeReadOnly(proto.Value,
+                                                           (value, i) => new EnumValueDescriptor(value, file, this, i));
+
+            File.DescriptorPool.AddSymbol(this);
+        }
+
+        internal EnumDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        /// <summary>
+        /// The CLR type for this enum. For generated code, this will be a CLR enum type.
+        /// </summary>
+        public Type ClrType { get { return clrType; } }
+
+        /// <value>
+        /// If this is a nested type, get the outer descriptor, otherwise null.
+        /// </value>
+        public MessageDescriptor ContainingType
+        {
+            get { return containingType; }
+        }
+
+        /// <value>
+        /// An unmodifiable list of defined value descriptors for this enum.
+        /// </value>
+        public IList<EnumValueDescriptor> Values
+        {
+            get { return values; }
+        }
+
+        /// <summary>
+        /// Finds an enum value by number. If multiple enum values have the
+        /// same number, this returns the first defined value with that number.
+        /// If there is no value for the given number, this returns <c>null</c>.
+        /// </summary>
+        public EnumValueDescriptor FindValueByNumber(int number)
+        {
+            return File.DescriptorPool.FindEnumValueByNumber(this, number);
+        }
+
+        /// <summary>
+        /// Finds an enum value by name.
+        /// </summary>
+        /// <param name="name">The unqualified name of the value (e.g. "FOO").</param>
+        /// <returns>The value's descriptor, or null if not found.</returns>
+        public EnumValueDescriptor FindValueByName(string name)
+        {
+            return File.DescriptorPool.FindSymbol<EnumValueDescriptor>(FullName + "." + name);
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
new file mode 100644
index 0000000..b212ce9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
@@ -0,0 +1,70 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Descriptor for a single enum value within an enum in a .proto file.
+    /// </summary>
+    public sealed class EnumValueDescriptor : DescriptorBase                                            
+    {
+        private readonly EnumDescriptor enumDescriptor;
+        private readonly EnumValueDescriptorProto proto;
+
+        internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file,
+                                     EnumDescriptor parent, int index)
+            : base(file, parent.FullName + "." + proto.Name, index)
+        {
+            this.proto = proto;
+            enumDescriptor = parent;
+            file.DescriptorPool.AddSymbol(this);
+            file.DescriptorPool.AddEnumValueByNumber(this);
+        }
+
+        internal EnumValueDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// Returns the name of the enum value described by this object.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        /// <summary>
+        /// Returns the number associated with this enum value.
+        /// </summary>
+        public int Number { get { return Proto.Number; } }
+
+        /// <summary>
+        /// Returns the enum descriptor that this value is part of.
+        /// </summary>
+        public EnumDescriptor EnumDescriptor { get { return enumDescriptor; } }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs
new file mode 100644
index 0000000..82ce505
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs
@@ -0,0 +1,63 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Base class for field accessors.
+    /// </summary>
+    internal abstract class FieldAccessorBase : IFieldAccessor
+    {
+        private readonly Func<IMessage, object> getValueDelegate;
+        private readonly FieldDescriptor descriptor;
+
+        internal FieldAccessorBase(PropertyInfo property, FieldDescriptor descriptor)
+        {
+            this.descriptor = descriptor;
+            getValueDelegate = ReflectionUtil.CreateFuncIMessageObject(property.GetGetMethod());
+        }
+
+        public FieldDescriptor Descriptor { get { return descriptor; } }
+
+        public object GetValue(IMessage message)
+        {
+            return getValueDelegate(message);
+        }
+
+        public abstract void Clear(IMessage message);
+        public abstract void SetValue(IMessage message, object value);
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
new file mode 100644
index 0000000..c6caaec
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
@@ -0,0 +1,359 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Linq;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Descriptor for a field or extension within a message in a .proto file.
+    /// </summary>
+    public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
+    {
+        private readonly FieldDescriptorProto proto;
+        private EnumDescriptor enumType;
+        private MessageDescriptor messageType;
+        private readonly MessageDescriptor containingType;
+        private readonly OneofDescriptor containingOneof;
+        private FieldType fieldType;
+        private readonly string propertyName; // Annoyingly, needed in Crosslink.
+        private IFieldAccessor accessor;
+
+        internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
+                                 MessageDescriptor parent, int index, string propertyName)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
+        {
+            this.proto = proto;
+            if (proto.Type != 0)
+            {
+                fieldType = GetFieldTypeFromProtoType(proto.Type);
+            }
+
+            if (FieldNumber <= 0)
+            {
+                throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
+            }
+            containingType = parent;
+            // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
+            if (proto.OneofIndex != -1)
+            {
+                if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
+                {
+                    throw new DescriptorValidationException(this,
+                        $"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}");
+                }
+                containingOneof = parent.Oneofs[proto.OneofIndex];
+            }
+
+            file.DescriptorPool.AddSymbol(this);
+            // We can't create the accessor until we've cross-linked, unfortunately, as we
+            // may not know whether the type of the field is a map or not. Remember the property name
+            // for later.
+            // We could trust the generated code and check whether the type of the property is
+            // a MapField, but that feels a tad nasty.
+            this.propertyName = propertyName;
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal FieldDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// Returns the accessor for this field.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// While a <see cref="FieldDescriptor"/> describes the field, it does not provide
+        /// any way of obtaining or changing the value of the field within a specific message;
+        /// that is the responsibility of the accessor.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, and the value of the map field itself is represented by a dictionary in the
+        /// reflection API. There are never instances of those "hidden" messages, so no accessor is provided
+        /// and this property will return null.
+        /// </para>
+        /// </remarks>
+        public IFieldAccessor Accessor { get { return accessor; } }
+        
+        /// <summary>
+        /// Maps a field type as included in the .proto file to a FieldType.
+        /// </summary>
+        private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.Types.Type type)
+        {
+            switch (type)
+            {
+                case FieldDescriptorProto.Types.Type.TYPE_DOUBLE:
+                    return FieldType.Double;
+                case FieldDescriptorProto.Types.Type.TYPE_FLOAT:
+                    return FieldType.Float;
+                case FieldDescriptorProto.Types.Type.TYPE_INT64:
+                    return FieldType.Int64;
+                case FieldDescriptorProto.Types.Type.TYPE_UINT64:
+                    return FieldType.UInt64;
+                case FieldDescriptorProto.Types.Type.TYPE_INT32:
+                    return FieldType.Int32;
+                case FieldDescriptorProto.Types.Type.TYPE_FIXED64:
+                    return FieldType.Fixed64;
+                case FieldDescriptorProto.Types.Type.TYPE_FIXED32:
+                    return FieldType.Fixed32;
+                case FieldDescriptorProto.Types.Type.TYPE_BOOL:
+                    return FieldType.Bool;
+                case FieldDescriptorProto.Types.Type.TYPE_STRING:
+                    return FieldType.String;
+                case FieldDescriptorProto.Types.Type.TYPE_GROUP:
+                    return FieldType.Group;
+                case FieldDescriptorProto.Types.Type.TYPE_MESSAGE:
+                    return FieldType.Message;
+                case FieldDescriptorProto.Types.Type.TYPE_BYTES:
+                    return FieldType.Bytes;
+                case FieldDescriptorProto.Types.Type.TYPE_UINT32:
+                    return FieldType.UInt32;
+                case FieldDescriptorProto.Types.Type.TYPE_ENUM:
+                    return FieldType.Enum;
+                case FieldDescriptorProto.Types.Type.TYPE_SFIXED32:
+                    return FieldType.SFixed32;
+                case FieldDescriptorProto.Types.Type.TYPE_SFIXED64:
+                    return FieldType.SFixed64;
+                case FieldDescriptorProto.Types.Type.TYPE_SINT32:
+                    return FieldType.SInt32;
+                case FieldDescriptorProto.Types.Type.TYPE_SINT64:
+                    return FieldType.SInt64;
+                default:
+                    throw new ArgumentException("Invalid type specified");
+            }
+        }
+
+        /// <summary>
+        /// Returns <c>true</c> if this field is a repeated field; <c>false</c> otherwise.
+        /// </summary>
+        public bool IsRepeated
+        {
+            get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
+        }
+
+        /// <summary>
+        /// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
+        /// </summary>
+        public bool IsMap
+        {
+            get { return fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry; }
+        }
+
+        /// <summary>
+        /// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
+        /// </summary>
+        public bool IsPacked
+        {
+            // Note the || rather than && here - we're effectively defaulting to packed, because that *is*
+            // the default in proto3, which is all we support. We may give the wrong result for the protos
+            // within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
+            // within the runtime.
+            get { return Proto.Options == null || Proto.Options.Packed; }
+        }        
+
+        /// <summary>
+        /// Get the field's containing message type.
+        /// </summary>
+        public MessageDescriptor ContainingType
+        {
+            get { return containingType; }
+        }
+
+        /// <summary>
+        /// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
+        /// </summary>
+        public OneofDescriptor ContainingOneof
+        {
+            get { return containingOneof; }
+        }
+
+        /// <summary>
+        /// Returns the type of the field.
+        /// </summary>
+        public FieldType FieldType
+        {
+            get { return fieldType; }
+        }
+
+        /// <summary>
+        /// Returns the field number declared in the proto file.
+        /// </summary>
+        public int FieldNumber
+        {
+            get { return Proto.Number; }
+        }
+
+        /// <summary>
+        /// Compares this descriptor with another one, ordering in "canonical" order
+        /// which simply means ascending order by field number. <paramref name="other"/>
+        /// must be a field of the same type, i.e. the <see cref="ContainingType"/> of
+        /// both fields must be the same.
+        /// </summary>
+        public int CompareTo(FieldDescriptor other)
+        {
+            if (other.containingType != containingType)
+            {
+                throw new ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " +
+                                            "for fields of the same message type.");
+            }
+            return FieldNumber - other.FieldNumber;
+        }
+
+        /// <summary>
+        /// For enum fields, returns the field's type.
+        /// </summary>
+        public EnumDescriptor EnumType
+        {
+            get
+            {
+                if (fieldType != FieldType.Enum)
+                {
+                    throw new InvalidOperationException("EnumType is only valid for enum fields.");
+                }
+                return enumType;
+            }
+        }
+
+        /// <summary>
+        /// For embedded message and group fields, returns the field's type.
+        /// </summary>
+        public MessageDescriptor MessageType
+        {
+            get
+            {
+                if (fieldType != FieldType.Message)
+                {
+                    throw new InvalidOperationException("MessageType is only valid for message fields.");
+                }
+                return messageType;
+            }
+        }
+
+        /// <summary>
+        /// Look up and cross-link all field types etc.
+        /// </summary>
+        internal void CrossLink()
+        {
+            if (Proto.TypeName != "")
+            {
+                IDescriptor typeDescriptor =
+                    File.DescriptorPool.LookupSymbol(Proto.TypeName, this);
+
+                if (Proto.Type != 0)
+                {
+                    // Choose field type based on symbol.
+                    if (typeDescriptor is MessageDescriptor)
+                    {
+                        fieldType = FieldType.Message;
+                    }
+                    else if (typeDescriptor is EnumDescriptor)
+                    {
+                        fieldType = FieldType.Enum;
+                    }
+                    else
+                    {
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a type.");
+                    }
+                }
+
+                if (fieldType == FieldType.Message)
+                {
+                    if (!(typeDescriptor is MessageDescriptor))
+                    {
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a message type.");
+                    }
+                    messageType = (MessageDescriptor) typeDescriptor;
+
+                    if (Proto.DefaultValue != "")
+                    {
+                        throw new DescriptorValidationException(this, "Messages can't have default values.");
+                    }
+                }
+                else if (fieldType == FieldType.Enum)
+                {
+                    if (!(typeDescriptor is EnumDescriptor))
+                    {
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not an enum type.");
+                    }
+                    enumType = (EnumDescriptor) typeDescriptor;
+                }
+                else
+                {
+                    throw new DescriptorValidationException(this, "Field with primitive type has type_name.");
+                }
+            }
+            else
+            {
+                if (fieldType == FieldType.Message || fieldType == FieldType.Enum)
+                {
+                    throw new DescriptorValidationException(this, "Field with message or enum type missing type_name.");
+                }
+            }
+
+            // Note: no attempt to perform any default value parsing
+
+            File.DescriptorPool.AddFieldByNumber(this);
+
+            if (containingType != null && containingType.Proto.Options != null && containingType.Proto.Options.MessageSetWireFormat)
+            {
+                throw new DescriptorValidationException(this, "MessageSet format is not supported.");
+            }
+            accessor = CreateAccessor(propertyName);
+        }
+
+        private IFieldAccessor CreateAccessor(string propertyName)
+        {
+            // If we're given no property name, that's because we really don't want an accessor.
+            // (At the moment, that means it's a map entry message...)
+            if (propertyName == null)
+            {
+                return null;
+            }
+            var property = containingType.ClrType.GetProperty(propertyName);
+            if (property == null)
+            {
+                throw new DescriptorValidationException(this, $"Property {propertyName} not found in {containingType.ClrType}");
+            }
+            return IsMap ? new MapFieldAccessor(property, this)
+                : IsRepeated ? new RepeatedFieldAccessor(property, this)
+                : (IFieldAccessor) new SingleFieldAccessor(property, this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldType.cs b/csharp/src/Google.Protobuf/Reflection/FieldType.cs
new file mode 100644
index 0000000..1658e34
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FieldType.cs
@@ -0,0 +1,113 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Enumeration of all the possible field types.
+    /// </summary>
+    public enum FieldType
+    {
+        /// <summary>
+        /// The <c>double</c> field type.
+        /// </summary>
+        Double,
+        /// <summary>
+        /// The <c>float</c> field type.
+        /// </summary>
+        Float,
+        /// <summary>
+        /// The <c>int64</c> field type.
+        /// </summary>
+        Int64,
+        /// <summary>
+        /// The <c>uint64</c> field type.
+        /// </summary>
+        UInt64,
+        /// <summary>
+        /// The <c>int32</c> field type.
+        /// </summary>
+        Int32,
+        /// <summary>
+        /// The <c>fixed64</c> field type.
+        /// </summary>
+        Fixed64,
+        /// <summary>
+        /// The <c>fixed32</c> field type.
+        /// </summary>
+        Fixed32,
+        /// <summary>
+        /// The <c>bool</c> field type.
+        /// </summary>
+        Bool,
+        /// <summary>
+        /// The <c>string</c> field type.
+        /// </summary>
+        String,
+        /// <summary>
+        /// The field type used for groups (not supported in this implementation).
+        /// </summary>
+        Group,
+        /// <summary>
+        /// The field type used for message fields.
+        /// </summary>
+        Message,
+        /// <summary>
+        /// The <c>bytes</c> field type.
+        /// </summary>
+        Bytes,
+        /// <summary>
+        /// The <c>uint32</c> field type.
+        /// </summary>
+        UInt32,
+        /// <summary>
+        /// The <c>sfixed32</c> field type.
+        /// </summary>
+        SFixed32,
+        /// <summary>
+        /// The <c>sfixed64</c> field type.
+        /// </summary>
+        SFixed64,
+        /// <summary>
+        /// The <c>sint32</c> field type.
+        /// </summary>
+        SInt32,
+        /// <summary>
+        /// The <c>sint64</c> field type.
+        /// </summary>
+        SInt64,
+        /// <summary>
+        /// The field type used for enum fields.
+        /// </summary>
+        Enum
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
new file mode 100644
index 0000000..ab7cd92
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -0,0 +1,344 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a .proto file, including everything defined within.
+    /// IDescriptor is implemented such that the File property returns this descriptor,
+    /// and the FullName is the same as the Name.
+    /// </summary>
+    public sealed class FileDescriptor : IDescriptor
+    {
+        private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
+        {
+            SerializedData = descriptorData;
+            DescriptorPool = pool;
+            Proto = proto;
+            Dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
+
+            PublicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
+
+            pool.AddPackage(Package, this);
+
+            MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
+                                                                 (message, index) =>
+                                                                 new MessageDescriptor(message, this, null, index, generatedCodeInfo.NestedTypes[index]));
+
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
+                                                              (enumType, index) =>
+                                                              new EnumDescriptor(enumType, this, null, index, generatedCodeInfo.NestedEnums[index]));
+
+            Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
+                                                             (service, index) =>
+                                                             new ServiceDescriptor(service, this, index));
+        }
+
+        /// <summary>
+        /// Computes the full name of a descriptor within this file, with an optional parent message.
+        /// </summary>
+        internal string ComputeFullName(MessageDescriptor parent, string name)
+        {
+            if (parent != null)
+            {
+                return parent.FullName + "." + name;
+            }
+            if (Package.Length > 0)
+            {
+                return Package + "." + name;
+            }
+            return name;
+        }
+
+        /// <summary>
+        /// Extracts public dependencies from direct dependencies. This is a static method despite its
+        /// first parameter, as the value we're in the middle of constructing is only used for exceptions.
+        /// </summary>
+        private static IList<FileDescriptor> DeterminePublicDependencies(FileDescriptor @this, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies)
+        {
+            var nameToFileMap = new Dictionary<string, FileDescriptor>();
+            foreach (var file in dependencies)
+            {
+                nameToFileMap[file.Name] = file;
+            }
+            var publicDependencies = new List<FileDescriptor>();
+            for (int i = 0; i < proto.PublicDependency.Count; i++)
+            {
+                int index = proto.PublicDependency[i];
+                if (index < 0 || index >= proto.Dependency.Count)
+                {
+                    throw new DescriptorValidationException(@this, "Invalid public dependency index.");
+                }
+                string name = proto.Dependency[index];
+                FileDescriptor file = nameToFileMap[name];
+                if (file == null)
+                {
+                    if (!allowUnknownDependencies)
+                    {
+                        throw new DescriptorValidationException(@this, "Invalid public dependency: " + name);
+                    }
+                    // Ignore unknown dependencies.
+                }
+                else
+                {
+                    publicDependencies.Add(file);
+                }
+            }
+            return new ReadOnlyCollection<FileDescriptor>(publicDependencies);
+        }
+
+        /// <value>
+        /// The descriptor in its protocol message representation.
+        /// </value>
+        internal FileDescriptorProto Proto { get; }
+
+        /// <value>
+        /// The file name.
+        /// </value>
+        public string Name => Proto.Name;
+
+        /// <summary>
+        /// The package as declared in the .proto file. This may or may not
+        /// be equivalent to the .NET namespace of the generated classes.
+        /// </summary>
+        public string Package => Proto.Package;
+
+        /// <value>
+        /// Unmodifiable list of top-level message types declared in this file.
+        /// </value>
+        public IList<MessageDescriptor> MessageTypes { get; }
+
+        /// <value>
+        /// Unmodifiable list of top-level enum types declared in this file.
+        /// </value>
+        public IList<EnumDescriptor> EnumTypes { get; }
+
+        /// <value>
+        /// Unmodifiable list of top-level services declared in this file.
+        /// </value>
+        public IList<ServiceDescriptor> Services { get; }
+
+        /// <value>
+        /// Unmodifiable list of this file's dependencies (imports).
+        /// </value>
+        public IList<FileDescriptor> Dependencies { get; }
+
+        /// <value>
+        /// Unmodifiable list of this file's public dependencies (public imports).
+        /// </value>
+        public IList<FileDescriptor> PublicDependencies { get; }
+
+        /// <value>
+        /// The original serialized binary form of this descriptor.
+        /// </value>
+        public ByteString SerializedData { get; }
+
+        /// <value>
+        /// Implementation of IDescriptor.FullName - just returns the same as Name.
+        /// </value>
+        string IDescriptor.FullName => Name;
+
+        /// <value>
+        /// Implementation of IDescriptor.File - just returns this descriptor.
+        /// </value>
+        FileDescriptor IDescriptor.File => this;
+
+        /// <value>
+        /// Pool containing symbol descriptors.
+        /// </value>
+        internal DescriptorPool DescriptorPool { get; }
+
+        /// <summary>
+        /// Finds a type (message, enum, service or extension) in the file by name. Does not find nested types.
+        /// </summary>
+        /// <param name="name">The unqualified type name to look for.</param>
+        /// <typeparam name="T">The type of descriptor to look for</typeparam>
+        /// <returns>The type's descriptor, or null if not found.</returns>
+        public T FindTypeByName<T>(String name)
+            where T : class, IDescriptor
+        {
+            // Don't allow looking up nested types.  This will make optimization
+            // easier later.
+            if (name.IndexOf('.') != -1)
+            {
+                return null;
+            }
+            if (Package.Length > 0)
+            {
+                name = Package + "." + name;
+            }
+            T result = DescriptorPool.FindSymbol<T>(name);
+            if (result != null && result.File == this)
+            {
+                return result;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Builds a FileDescriptor from its protocol buffer representation.
+        /// </summary>
+        /// <param name="descriptorData">The original serialized descriptor data.
+        /// We have only limited proto2 support, so serializing FileDescriptorProto
+        /// would not necessarily give us this.</param>
+        /// <param name="proto">The protocol message form of the FileDescriptor.</param>
+        /// <param name="dependencies">FileDescriptors corresponding to all of the
+        /// file's dependencies, in the exact order listed in the .proto file. May be null,
+        /// in which case it is treated as an empty array.</param>
+        /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
+        /// <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param>
+        /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
+        /// a valid descriptor. This can occur for a number of reasons, such as a field
+        /// having an undefined type or because two messages were defined with the same name.</exception>
+        private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
+        {
+            // Building descriptors involves two steps: translating and linking.
+            // In the translation step (implemented by FileDescriptor's
+            // constructor), we build an object tree mirroring the
+            // FileDescriptorProto's tree and put all of the descriptors into the
+            // DescriptorPool's lookup tables.  In the linking step, we look up all
+            // type references in the DescriptorPool, so that, for example, a
+            // FieldDescriptor for an embedded message contains a pointer directly
+            // to the Descriptor for that message's type.  We also detect undefined
+            // types in the linking step.
+            if (dependencies == null)
+            {
+                dependencies = new FileDescriptor[0];
+            }
+
+            DescriptorPool pool = new DescriptorPool(dependencies);
+            FileDescriptor result = new FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo);
+
+            // Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we
+            // need.
+            if (dependencies.Length != proto.Dependency.Count)
+            {
+                throw new DescriptorValidationException(
+                    result,
+                    "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
+                    "those listed in the FileDescriptorProto.");
+            }
+            for (int i = 0; i < proto.Dependency.Count; i++)
+            {
+                if (dependencies[i].Name != proto.Dependency[i])
+                {
+                    throw new DescriptorValidationException(
+                        result,
+                        "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
+                        "those listed in the FileDescriptorProto. Expected: " +
+                        proto.Dependency[i] + " but was: " + dependencies[i].Name);
+                }
+            }
+
+            result.CrossLink();
+            return result;
+        }
+
+        private void CrossLink()
+        {
+            foreach (MessageDescriptor message in MessageTypes)
+            {
+                message.CrossLink();
+            }
+
+            foreach (ServiceDescriptor service in Services)
+            {
+                service.CrossLink();
+            }
+        }
+
+        /// <summary>
+        /// Creates a descriptor for generated code.
+        /// </summary>
+        /// <remarks>
+        /// This method is only designed to be used by the results of generating code with protoc,
+        /// which creates the appropriate dependencies etc. It has to be public because the generated
+        /// code is "external", but should not be called directly by end users.
+        /// </remarks>
+        public static FileDescriptor FromGeneratedCode(
+            byte[] descriptorData,
+            FileDescriptor[] dependencies,
+            GeneratedClrTypeInfo generatedCodeInfo)
+        {
+            FileDescriptorProto proto;
+            try
+            {
+                proto = FileDescriptorProto.Parser.ParseFrom(descriptorData);
+            }
+            catch (InvalidProtocolBufferException e)
+            {
+                throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e);
+            }
+
+            try
+            {
+                // When building descriptors for generated code, we allow unknown
+                // dependencies by default.
+                return BuildFrom(ByteString.CopyFrom(descriptorData), proto, dependencies, true, generatedCodeInfo);
+            }
+            catch (DescriptorValidationException e)
+            {
+                throw new ArgumentException($"Invalid embedded descriptor for \"{proto.Name}\".", e);
+            }
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String" /> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String" /> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return $"FileDescriptor for {Name}";
+        }
+
+        /// <summary>
+        /// Returns the file descriptor for descriptor.proto.
+        /// </summary>
+        /// <remarks>
+        /// This is used for protos which take a direct dependency on <c>descriptor.proto</c>, typically for
+        /// annotations. While <c>descriptor.proto</c> is a proto2 file, it is built into the Google.Protobuf
+        /// runtime for reflection purposes. The messages are internal to the runtime as they would require
+        /// proto2 semantics for full support, but the file descriptor is available via this property. The
+        /// C# codegen in protoc automatically uses this property when it detects a dependency on <c>descriptor.proto</c>.
+        /// </remarks>
+        /// <value>
+        /// The file descriptor for <c>descriptor.proto</c>.
+        /// </value>
+        public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
new file mode 100644
index 0000000..fe5db65
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
@@ -0,0 +1,103 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Extra information provided by generated code when initializing a message or file descriptor.
+    /// These are constructed as required, and are not long-lived. Hand-written code should
+    /// never need to use this type.
+    /// </summary>
+    public sealed class GeneratedClrTypeInfo
+    {
+        private static readonly string[] EmptyNames = new string[0];
+        private static readonly GeneratedClrTypeInfo[] EmptyCodeInfo = new GeneratedClrTypeInfo[0];
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
+        /// </summary>
+        public Type ClrType { get; private set; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the parser for message descriptors.
+        /// </summary>
+        public MessageParser Parser { get; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
+        /// for fields in the message for message descriptors.
+        /// </summary>
+        public string[] PropertyNames { get; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
+        /// for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
+        /// there will be a "FooCase" property and a "ClearFoo" method.
+        /// </summary>
+        public string[] OneofNames { get; }
+
+        /// <summary>
+        /// The reflection information for types within this file/message descriptor. Elements may be null
+        /// if there is no corresponding generated type, e.g. for map entry types.
+        /// </summary>
+        public GeneratedClrTypeInfo[] NestedTypes { get; }
+
+        /// <summary>
+        /// The CLR types for enums within this file/message descriptor.
+        /// </summary>
+        public Type[] NestedEnums { get; }
+
+        /// <summary>
+        /// Creates a GeneratedClrTypeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.
+        /// Each array parameter may be null, to indicate a lack of values.
+        /// The parameter order is designed to make it feasible to format the generated code readably.
+        /// </summary>
+        public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
+        {
+            NestedTypes = nestedTypes ?? EmptyCodeInfo;
+            NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
+            ClrType = clrType;
+            Parser = parser;
+            PropertyNames = propertyNames ?? EmptyNames;
+            OneofNames = oneofNames ?? EmptyNames;
+        }
+
+        /// <summary>
+        /// Creates a GeneratedClrTypeInfo for a file descriptor, with only types and enums.
+        /// </summary>
+        public GeneratedClrTypeInfo(Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
+            : this(null, null, null, null, nestedEnums, nestedTypes)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/IDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/IDescriptor.cs
new file mode 100644
index 0000000..318d58c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/IDescriptor.cs
@@ -0,0 +1,55 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Interface implemented by all descriptor types.
+    /// </summary>
+    public interface IDescriptor
+    {
+        /// <summary>
+        /// Returns the name of the entity (message, field etc) being described.
+        /// </summary>
+        string Name { get; }
+
+        /// <summary>
+        /// Returns the fully-qualified name of the entity being described.
+        /// </summary>
+        string FullName { get; }
+
+        /// <summary>
+        /// Returns the descriptor for the .proto file that this entity is part of.
+        /// </summary>
+        FileDescriptor File { get; }
+    }    
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
new file mode 100644
index 0000000..cfe56fd
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
@@ -0,0 +1,71 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Allows fields to be reflectively accessed.
+    /// </summary>
+    public interface IFieldAccessor
+    {
+        /// <summary>
+        /// Returns the descriptor associated with this field.
+        /// </summary>
+        FieldDescriptor Descriptor { get; }
+
+        /// <summary>
+        /// Clears the field in the specified message. (For repeated fields,
+        /// this clears the list.)
+        /// </summary>
+        void Clear(IMessage message);
+
+        /// <summary>
+        /// Fetches the field value. For repeated values, this will be an
+        /// <see cref="IList"/> implementation. For map values, this will be an
+        /// <see cref="IDictionary"/> implementation.
+        /// </summary>
+        object GetValue(IMessage message);
+
+        /// <summary>
+        /// Mutator for single "simple" fields only.
+        /// </summary>
+        /// <remarks>
+        /// Repeated fields are mutated by fetching the value and manipulating it as a list.
+        /// Map fields are mutated by fetching the value and manipulating it as a dictionary.
+        /// </remarks>
+        /// <exception cref="InvalidOperationException">The field is not a "simple" field.</exception>
+        void SetValue(IMessage message, object value);
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs
new file mode 100644
index 0000000..9ed7f8c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Accessor for map fields.
+    /// </summary>
+    internal sealed class MapFieldAccessor : FieldAccessorBase
+    {
+        internal MapFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
+        {
+        }
+
+        public override void Clear(IMessage message)
+        {
+            IDictionary list = (IDictionary) GetValue(message);
+            list.Clear();
+        }
+
+        public override void SetValue(IMessage message, object value)
+        {
+            throw new InvalidOperationException("SetValue is not implemented for map fields");
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
new file mode 100644
index 0000000..f5798d1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
@@ -0,0 +1,317 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a message type.
+    /// </summary>
+    public sealed class MessageDescriptor : DescriptorBase
+    {
+        private static readonly HashSet<string> WellKnownTypeNames = new HashSet<string>
+        {
+            "google/protobuf/any.proto",
+            "google/protobuf/api.proto",
+            "google/protobuf/duration.proto",
+            "google/protobuf/empty.proto",
+            "google/protobuf/wrappers.proto",
+            "google/protobuf/timestamp.proto",
+            "google/protobuf/field_mask.proto",
+            "google/protobuf/source_context.proto",
+            "google/protobuf/struct.proto",
+            "google/protobuf/type.proto",
+        };
+
+        private readonly IList<FieldDescriptor> fieldsInDeclarationOrder;
+        private readonly IList<FieldDescriptor> fieldsInNumberOrder;
+        private readonly IDictionary<string, FieldDescriptor> jsonFieldMap;
+        
+        internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedClrTypeInfo generatedCodeInfo)
+            : base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
+        {
+            Proto = proto;
+            Parser = generatedCodeInfo?.Parser;
+            ClrType = generatedCodeInfo?.ClrType;
+            ContainingType = parent;
+
+            // Note use of generatedCodeInfo. rather than generatedCodeInfo?. here... we don't expect
+            // to see any nested oneofs, types or enums in "not actually generated" code... we do
+            // expect fields though (for map entry messages).
+            Oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.OneofDecl,
+                (oneof, index) =>
+                new OneofDescriptor(oneof, file, this, index, generatedCodeInfo.OneofNames[index]));
+
+            NestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.NestedType,
+                (type, index) =>
+                new MessageDescriptor(type, file, this, index, generatedCodeInfo.NestedTypes[index]));
+
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.EnumType,
+                (type, index) =>
+                new EnumDescriptor(type, file, this, index, generatedCodeInfo.NestedEnums[index]));
+
+            fieldsInDeclarationOrder = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.Field,
+                (field, index) =>
+                new FieldDescriptor(field, file, this, index, generatedCodeInfo?.PropertyNames[index]));
+            fieldsInNumberOrder = new ReadOnlyCollection<FieldDescriptor>(fieldsInDeclarationOrder.OrderBy(field => field.FieldNumber).ToArray());
+            // TODO: Use field => field.Proto.JsonName when we're confident it's appropriate. (And then use it in the formatter, too.)
+            jsonFieldMap = CreateJsonFieldMap(fieldsInNumberOrder);
+            file.DescriptorPool.AddSymbol(this);
+            Fields = new FieldCollection(this);
+        }
+
+        private static ReadOnlyDictionary<string, FieldDescriptor> CreateJsonFieldMap(IList<FieldDescriptor> fields)
+        {
+            var map = new Dictionary<string, FieldDescriptor>();
+            foreach (var field in fields)
+            {
+                map[JsonFormatter.ToCamelCase(field.Name)] = field;
+                map[field.Name] = field;
+            }
+            return new ReadOnlyDictionary<string, FieldDescriptor>(map);
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name => Proto.Name;
+
+        internal DescriptorProto Proto { get; }
+
+        /// <summary>
+        /// The CLR type used to represent message instances from this descriptor.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the type returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
+        /// </remarks>
+        public Type ClrType { get; }
+
+        /// <summary>
+        /// A parser for this message type.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// As <see cref="MessageDescriptor"/> is not generic, this cannot be statically
+        /// typed to the relevant type, but it should produce objects of a type compatible with <see cref="ClrType"/>.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. No message parser object is created for
+        /// such messages, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the parser returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
+        /// </remarks>
+        public MessageParser Parser { get; }
+
+        /// <summary>
+        /// Returns whether this message is one of the "well known types" which may have runtime/protoc support.
+        /// </summary>
+        internal bool IsWellKnownType => File.Package == "google.protobuf" && WellKnownTypeNames.Contains(File.Name);
+
+        /// <summary>
+        /// Returns whether this message is one of the "wrapper types" used for fields which represent primitive values
+        /// with the addition of presence.
+        /// </summary>
+        internal bool IsWrapperType => File.Package == "google.protobuf" && File.Name == "google/protobuf/wrappers.proto";
+
+        /// <value>
+        /// If this is a nested type, get the outer descriptor, otherwise null.
+        /// </value>
+        public MessageDescriptor ContainingType { get; }
+
+        /// <value>
+        /// A collection of fields, which can be retrieved by name or field number.
+        /// </value>
+        public FieldCollection Fields { get; }
+
+        /// <value>
+        /// An unmodifiable list of this message type's nested types.
+        /// </value>
+        public IList<MessageDescriptor> NestedTypes { get; }
+
+        /// <value>
+        /// An unmodifiable list of this message type's enum types.
+        /// </value>
+        public IList<EnumDescriptor> EnumTypes { get; }
+
+        /// <value>
+        /// An unmodifiable list of the "oneof" field collections in this message type.
+        /// </value>
+        public IList<OneofDescriptor> Oneofs { get; }
+
+        /// <summary>
+        /// Finds a field by field name.
+        /// </summary>
+        /// <param name="name">The unqualified name of the field (e.g. "foo").</param>
+        /// <returns>The field's descriptor, or null if not found.</returns>
+        public FieldDescriptor FindFieldByName(String name) => File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
+
+        /// <summary>
+        /// Finds a field by field number.
+        /// </summary>
+        /// <param name="number">The field number within this message type.</param>
+        /// <returns>The field's descriptor, or null if not found.</returns>
+        public FieldDescriptor FindFieldByNumber(int number) => File.DescriptorPool.FindFieldByNumber(this, number);
+
+        /// <summary>
+        /// Finds a nested descriptor by name. The is valid for fields, nested
+        /// message types, oneofs and enums.
+        /// </summary>
+        /// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
+        /// <returns>The descriptor, or null if not found.</returns>
+        public T FindDescriptor<T>(string name)  where T : class, IDescriptor =>
+            File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
+
+        /// <summary>
+        /// Looks up and cross-links all fields and nested types.
+        /// </summary>
+        internal void CrossLink()
+        {
+            foreach (MessageDescriptor message in NestedTypes)
+            {
+                message.CrossLink();
+            }
+
+            foreach (FieldDescriptor field in fieldsInDeclarationOrder)
+            {
+                field.CrossLink();
+            }
+
+            foreach (OneofDescriptor oneof in Oneofs)
+            {
+                oneof.CrossLink();
+            }
+        }
+
+        /// <summary>
+        /// A collection to simplify retrieving the field accessor for a particular field.
+        /// </summary>
+        public sealed class FieldCollection
+        {
+            private readonly MessageDescriptor messageDescriptor;
+
+            internal FieldCollection(MessageDescriptor messageDescriptor)
+            {
+                this.messageDescriptor = messageDescriptor;
+            }
+
+            /// <value>
+            /// Returns the fields in the message as an immutable list, in the order in which they
+            /// are declared in the source .proto file.
+            /// </value>
+            public IList<FieldDescriptor> InDeclarationOrder() => messageDescriptor.fieldsInDeclarationOrder;
+
+            /// <value>
+            /// Returns the fields in the message as an immutable list, in ascending field number
+            /// order. Field numbers need not be contiguous, so there is no direct mapping from the
+            /// index in the list to the field number; to retrieve a field by field number, it is better
+            /// to use the <see cref="FieldCollection"/> indexer.
+            /// </value>
+            public IList<FieldDescriptor> InFieldNumberOrder() => messageDescriptor.fieldsInNumberOrder;
+
+            // TODO: consider making this public in the future. (Being conservative for now...)
+
+            /// <value>
+            /// Returns a read-only dictionary mapping the field names in this message as they're available
+            /// in the JSON representation to the field descriptors. For example, a field <c>foo_bar</c>
+            /// in the message would result two entries, one with a key <c>fooBar</c> and one with a key
+            /// <c>foo_bar</c>, both referring to the same field.
+            /// </value>
+            internal IDictionary<string, FieldDescriptor> ByJsonName() => messageDescriptor.jsonFieldMap;
+
+            /// <summary>
+            /// Retrieves the descriptor for the field with the given number.
+            /// </summary>
+            /// <param name="number">Number of the field to retrieve the descriptor for</param>
+            /// <returns>The accessor for the given field</returns>
+            /// <exception cref="KeyNotFoundException">The message descriptor does not contain a field
+            /// with the given number</exception>
+            public FieldDescriptor this[int number]
+            {
+                get
+                {
+                    var fieldDescriptor = messageDescriptor.FindFieldByNumber(number);
+                    if (fieldDescriptor == null)
+                    {
+                        throw new KeyNotFoundException("No such field number");
+                    }
+                    return fieldDescriptor;
+                }
+            }
+
+            /// <summary>
+            /// Retrieves the descriptor for the field with the given name.
+            /// </summary>
+            /// <param name="name">Name of the field to retrieve the descriptor for</param>
+            /// <returns>The descriptor for the given field</returns>
+            /// <exception cref="KeyNotFoundException">The message descriptor does not contain a field
+            /// with the given name</exception>
+            public FieldDescriptor this[string name]
+            {
+                get
+                {
+                    var fieldDescriptor = messageDescriptor.FindFieldByName(name);
+                    if (fieldDescriptor == null)
+                    {
+                        throw new KeyNotFoundException("No such field name");
+                    }
+                    return fieldDescriptor;
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
new file mode 100644
index 0000000..f9539f6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
@@ -0,0 +1,103 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a single method in a service.
+    /// </summary>
+    public sealed class MethodDescriptor : DescriptorBase
+    {
+        private readonly MethodDescriptorProto proto;
+        private readonly ServiceDescriptor service;
+        private MessageDescriptor inputType;
+        private MessageDescriptor outputType;
+
+        /// <value>
+        /// The service this method belongs to.
+        /// </value>
+        public ServiceDescriptor Service { get { return service; } }
+
+        /// <value>
+        /// The method's input type.
+        /// </value>
+        public MessageDescriptor InputType { get { return inputType; } }
+
+        /// <value>
+        /// The method's input type.
+        /// </value>
+        public MessageDescriptor OutputType { get { return outputType; } }
+
+        /// <value>
+        /// Indicates if client streams multiple requests.
+        /// </value>
+        public bool IsClientStreaming { get { return proto.ClientStreaming; } }
+
+        /// <value>
+        /// Indicates if server streams multiple responses.
+        /// </value>
+        public bool IsServerStreaming { get { return proto.ServerStreaming; } }
+
+        internal MethodDescriptor(MethodDescriptorProto proto, FileDescriptor file,
+                                  ServiceDescriptor parent, int index)
+            : base(file, parent.FullName + "." + proto.Name, index)
+        {
+            this.proto = proto;
+            service = parent;
+            file.DescriptorPool.AddSymbol(this);
+        }
+
+        internal MethodDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal void CrossLink()
+        {
+            IDescriptor lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, this);
+            if (!(lookup is MessageDescriptor))
+            {
+                throw new DescriptorValidationException(this, "\"" + Proto.InputType + "\" is not a message type.");
+            }
+            inputType = (MessageDescriptor) lookup;
+
+            lookup = File.DescriptorPool.LookupSymbol(Proto.OutputType, this);
+            if (!(lookup is MessageDescriptor))
+            {
+                throw new DescriptorValidationException(this, "\"" + Proto.OutputType + "\" is not a message type.");
+            }
+            outputType = (MessageDescriptor) lookup;
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs b/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs
new file mode 100644
index 0000000..8714ab1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs
@@ -0,0 +1,90 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Reflection access for a oneof, allowing clear and "get case" actions.
+    /// </summary>
+    public sealed class OneofAccessor
+    {
+        private readonly Func<IMessage, int> caseDelegate;
+        private readonly Action<IMessage> clearDelegate;
+        private OneofDescriptor descriptor;
+
+        internal OneofAccessor(PropertyInfo caseProperty, MethodInfo clearMethod, OneofDescriptor descriptor) 
+        {
+            if (!caseProperty.CanRead)
+            {
+                throw new ArgumentException("Cannot read from property");
+            }
+            this.descriptor = descriptor;
+            caseDelegate = ReflectionUtil.CreateFuncIMessageT<int>(caseProperty.GetGetMethod());
+
+            this.descriptor = descriptor;
+            clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod);
+        }
+
+        /// <summary>
+        /// Gets the descriptor for this oneof.
+        /// </summary>
+        /// <value>
+        /// The descriptor of the oneof.
+        /// </value>
+        public OneofDescriptor Descriptor { get { return descriptor; } }
+
+        /// <summary>
+        /// Clears the oneof in the specified message.
+        /// </summary>
+        public void Clear(IMessage message)
+        {
+            clearDelegate(message);
+        }
+
+        /// <summary>
+        /// Indicates which field in the oneof is set for specified message
+        /// </summary>
+        public FieldDescriptor GetCaseFieldDescriptor(IMessage message)
+        {
+            int fieldNumber = caseDelegate(message);
+            if (fieldNumber > 0)
+            {
+                return descriptor.ContainingType.FindFieldByNumber(fieldNumber);
+            }
+            return null;
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
new file mode 100644
index 0000000..22020ac
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
@@ -0,0 +1,122 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a "oneof" field collection in a message type: a set of
+    /// fields of which at most one can be set in any particular message.
+    /// </summary>
+    public sealed class OneofDescriptor : DescriptorBase
+    {
+        private readonly OneofDescriptorProto proto;
+        private MessageDescriptor containingType;
+        private IList<FieldDescriptor> fields;
+        private readonly OneofAccessor accessor;
+
+        internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, string clrName)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
+        {
+            this.proto = proto;
+            containingType = parent;
+
+            file.DescriptorPool.AddSymbol(this);
+            accessor = CreateAccessor(clrName);
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        /// <summary>
+        /// Gets the message type containing this oneof.
+        /// </summary>
+        /// <value>
+        /// The message type containing this oneof.
+        /// </value>
+        public MessageDescriptor ContainingType
+        {
+            get { return containingType; }
+        }
+
+        /// <summary>
+        /// Gets the fields within this oneof, in declaration order.
+        /// </summary>
+        /// <value>
+        /// The fields within this oneof, in declaration order.
+        /// </value>
+        public IList<FieldDescriptor> Fields { get { return fields; } }
+
+        /// <summary>
+        /// Gets an accessor for reflective access to the values associated with the oneof
+        /// in a particular message.
+        /// </summary>
+        /// <value>
+        /// The accessor used for reflective access.
+        /// </value>
+        public OneofAccessor Accessor { get { return accessor; } }
+
+        internal void CrossLink()
+        {
+            List<FieldDescriptor> fieldCollection = new List<FieldDescriptor>();
+            foreach (var field in ContainingType.Fields.InDeclarationOrder())
+            {
+                if (field.ContainingOneof == this)
+                {
+                    fieldCollection.Add(field);
+                }
+            }
+            fields = new ReadOnlyCollection<FieldDescriptor>(fieldCollection);
+        }
+
+        private OneofAccessor CreateAccessor(string clrName)
+        {
+            var caseProperty = containingType.ClrType.GetProperty(clrName + "Case");
+            if (caseProperty == null)
+            {
+                throw new DescriptorValidationException(this, $"Property {clrName}Case not found in {containingType.ClrType}");
+            }
+            var clearMethod = containingType.ClrType.GetMethod("Clear" + clrName);
+            if (clearMethod == null)
+            {
+                throw new DescriptorValidationException(this, $"Method Clear{clrName} not found in {containingType.ClrType}");
+            }
+
+            return new OneofAccessor(caseProperty, clearMethod, this);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs
new file mode 100644
index 0000000..e547d83
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs
@@ -0,0 +1,68 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Represents a package in the symbol table.  We use PackageDescriptors
+    /// just as placeholders so that someone cannot define, say, a message type
+    /// that has the same name as an existing package.
+    /// </summary>
+    internal sealed class PackageDescriptor : IDescriptor
+    {
+        private readonly string name;
+        private readonly string fullName;
+        private readonly FileDescriptor file;
+
+        internal PackageDescriptor(string name, string fullName, FileDescriptor file)
+        {
+            this.file = file;
+            this.fullName = fullName;
+            this.name = name;
+        }
+
+        public string Name
+        {
+            get { return name; }
+        }
+
+        public string FullName
+        {
+            get { return fullName; }
+        }
+
+        public FileDescriptor File
+        {
+            get { return file; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs b/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs
new file mode 100644
index 0000000..8c055d6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+// This file just contains partial classes for any autogenerated classes that need additional support.

+namespace Google.Protobuf.Reflection

+{

+    internal partial class FieldDescriptorProto

+    {

+        // We can't tell the difference between "explicitly set to 0" and "not set"

+        // in proto3, but we need to tell the difference for OneofIndex. descriptor.proto

+        // is really a proto2 file, but the runtime doesn't know about proto2 semantics...

+        // We fake it by defaulting to -1.

+        partial void OnConstruction()

+        {

+            OneofIndex = -1;

+        }

+    }

+

+    internal partial class FieldOptions

+    {

+        // We can't tell the difference between "explicitly set to false" and "not set"

+        // in proto3, but we need to tell the difference for FieldDescriptor.IsPacked.

+        // This won't work if we ever need to support proto2, but at that point we'll be

+        // able to remove this hack and use field presence instead. 

+        partial void OnConstruction()

+        {

+            Packed = true;

+        }

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
new file mode 100644
index 0000000..df820ca
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
@@ -0,0 +1,107 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// The methods in this class are somewhat evil, and should not be tampered with lightly.
+    /// Basically they allow the creation of relatively weakly typed delegates from MethodInfos
+    /// which are more strongly typed. They do this by creating an appropriate strongly typed
+    /// delegate from the MethodInfo, and then calling that within an anonymous method.
+    /// Mind-bending stuff (at least to your humble narrator) but the resulting delegates are
+    /// very fast compared with calling Invoke later on.
+    /// </summary>
+    internal static class ReflectionUtil
+    {
+        /// <summary>
+        /// Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
+        /// </summary>
+        internal static readonly Type[] EmptyTypes = new Type[0];
+
+        /// <summary>
+        /// Creates a delegate which will cast the argument to the appropriate method target type,
+        /// call the method on it, then convert the result to object.
+        /// </summary>
+        internal static Func<IMessage, object> CreateFuncIMessageObject(MethodInfo method)
+        {
+            ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
+            Expression downcast = Expression.Convert(parameter, method.DeclaringType);
+            Expression call = Expression.Call(downcast, method);
+            Expression upcast = Expression.Convert(call, typeof(object));
+            return Expression.Lambda<Func<IMessage, object>>(upcast, parameter).Compile();
+        }
+
+        /// <summary>
+        /// Creates a delegate which will cast the argument to the appropriate method target type,
+        /// call the method on it, then convert the result to the specified type.
+        /// </summary>
+        internal static Func<IMessage, T> CreateFuncIMessageT<T>(MethodInfo method)
+        {
+            ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
+            Expression downcast = Expression.Convert(parameter, method.DeclaringType);
+            Expression call = Expression.Call(downcast, method);
+            Expression upcast = Expression.Convert(call, typeof(T));
+            return Expression.Lambda<Func<IMessage, T>>(upcast, parameter).Compile();
+        }
+
+        /// <summary>
+        /// Creates a delegate which will execute the given method after casting the first argument to
+        /// the target type of the method, and the second argument to the first parameter type of the method.
+        /// </summary>
+        internal static Action<IMessage, object> CreateActionIMessageObject(MethodInfo method)
+        {
+            ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
+            ParameterExpression argParameter = Expression.Parameter(typeof(object), "arg");
+            Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
+            Expression castArgument = Expression.Convert(argParameter, method.GetParameters()[0].ParameterType);
+            Expression call = Expression.Call(castTarget, method, castArgument);
+            return Expression.Lambda<Action<IMessage, object>>(call, targetParameter, argParameter).Compile();
+        }
+
+        /// <summary>
+        /// Creates a delegate which will execute the given method after casting the first argument to
+        /// the target type of the method.
+        /// </summary>
+        internal static Action<IMessage> CreateActionIMessage(MethodInfo method)
+        {
+            ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
+            Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
+            Expression call = Expression.Call(castTarget, method);
+            return Expression.Lambda<Action<IMessage>>(call, targetParameter).Compile();
+        }        
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs
new file mode 100644
index 0000000..bd40847
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs
@@ -0,0 +1,60 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Accessor for repeated fields.
+    /// </summary>
+    internal sealed class RepeatedFieldAccessor : FieldAccessorBase
+    {
+        internal RepeatedFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
+        {
+        }
+
+        public override void Clear(IMessage message)
+        {
+            IList list = (IList) GetValue(message);
+            list.Clear();
+        }
+
+        public override void SetValue(IMessage message, object value)
+        {
+            throw new InvalidOperationException("SetValue is not implemented for repeated fields");
+        }
+
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
new file mode 100644
index 0000000..cc0a501
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
@@ -0,0 +1,89 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Describes a service type.
+    /// </summary>
+    public sealed class ServiceDescriptor : DescriptorBase
+    {
+        private readonly ServiceDescriptorProto proto;
+        private readonly IList<MethodDescriptor> methods;
+
+        internal ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
+            : base(file, file.ComputeFullName(null, proto.Name), index)
+        {
+            this.proto = proto;
+            methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method,
+                                                            (method, i) => new MethodDescriptor(method, file, this, i));
+
+            file.DescriptorPool.AddSymbol(this);
+        }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal ServiceDescriptorProto Proto { get { return proto; } }
+
+        /// <value>
+        /// An unmodifiable list of methods in this service.
+        /// </value>
+        public IList<MethodDescriptor> Methods
+        {
+            get { return methods; }
+        }
+
+        /// <summary>
+        /// Finds a method by name.
+        /// </summary>
+        /// <param name="name">The unqualified name of the method (e.g. "Foo").</param>
+        /// <returns>The method's decsriptor, or null if not found.</returns>
+        public MethodDescriptor FindMethodByName(String name)
+        {
+            return File.DescriptorPool.FindSymbol<MethodDescriptor>(FullName + "." + name);
+        }
+
+        internal void CrossLink()
+        {
+            foreach (MethodDescriptor method in methods)
+            {
+                method.CrossLink();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
new file mode 100644
index 0000000..bbac217
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
@@ -0,0 +1,81 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Reflection;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Accessor for single fields.
+    /// </summary>
+    internal sealed class SingleFieldAccessor : FieldAccessorBase
+    {
+        // All the work here is actually done in the constructor - it creates the appropriate delegates.
+        // There are various cases to consider, based on the property type (message, string/bytes, or "genuine" primitive)
+        // and proto2 vs proto3 for non-message types, as proto3 doesn't support "full" presence detection or default
+        // values.
+
+        private readonly Action<IMessage, object> setValueDelegate;
+        private readonly Action<IMessage> clearDelegate;
+
+        internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
+        {
+            if (!property.CanWrite)
+            {
+                throw new ArgumentException("Not all required properties/methods available");
+            }
+            setValueDelegate = ReflectionUtil.CreateActionIMessageObject(property.GetSetMethod());
+
+            var clrType = property.PropertyType;
+            
+            // TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
+            object defaultValue =
+                descriptor.FieldType == FieldType.Message ? null
+                : clrType == typeof(string) ? ""
+                : clrType == typeof(ByteString) ? ByteString.Empty
+                : Activator.CreateInstance(clrType);
+            clearDelegate = message => SetValue(message, defaultValue);
+        }
+
+        public override void Clear(IMessage message)
+        {
+            clearDelegate(message);
+        }
+
+        public override void SetValue(IMessage message, object value)
+        {
+            setValueDelegate(message, value);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs
new file mode 100644
index 0000000..e94e3e6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs
@@ -0,0 +1,183 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// An immutable registry of types which can be looked up by their full name.
+    /// </summary>
+    public sealed class TypeRegistry
+    {
+        /// <summary>
+        /// An empty type registry, containing no types.
+        /// </summary>
+        public static TypeRegistry Empty { get; } = new TypeRegistry(new Dictionary<string, MessageDescriptor>());
+
+        private readonly Dictionary<string, MessageDescriptor> fullNameToMessageMap;
+
+        private TypeRegistry(Dictionary<string, MessageDescriptor> fullNameToMessageMap)
+        {
+            this.fullNameToMessageMap = fullNameToMessageMap;
+        }
+
+        /// <summary>
+        /// Attempts to find a message descriptor by its full name.
+        /// </summary>
+        /// <param name="fullName">The full name of the message, which is the dot-separated
+        /// combination of package, containing messages and message name</param>
+        /// <returns>The message descriptor corresponding to <paramref name="fullName"/> or null
+        /// if there is no such message descriptor.</returns>
+        public MessageDescriptor Find(string fullName)
+        {
+            MessageDescriptor ret;
+            // Ignore the return value as ret will end up with the right value either way.
+            fullNameToMessageMap.TryGetValue(fullName, out ret);
+            return ret;
+        }
+
+        /// <summary>
+        /// Creates a type registry from the specified set of file descriptors.
+        /// </summary>
+        /// <remarks>
+        /// This is a convenience overload for <see cref="FromFiles(IEnumerable{FileDescriptor})"/>
+        /// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
+        /// </remarks>
+        /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromFiles(params FileDescriptor[] fileDescriptors)
+        {
+            return FromFiles((IEnumerable<FileDescriptor>) fileDescriptors);
+        }
+
+        /// <summary>
+        /// Creates a type registry from the specified set of file descriptors.
+        /// </summary>
+        /// <remarks>
+        /// All message types within all the specified files are added to the registry, and
+        /// the dependencies of the specified files are also added, recursively.
+        /// </remarks>
+        /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromFiles(IEnumerable<FileDescriptor> fileDescriptors)
+        {
+            ProtoPreconditions.CheckNotNull(fileDescriptors, nameof(fileDescriptors));
+            var builder = new Builder();
+            foreach (var file in fileDescriptors)
+            {
+                builder.AddFile(file);
+            }
+            return builder.Build();
+        }
+
+        /// <summary>
+        /// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
+        /// </summary>
+        /// <remarks>
+        /// This is a convenience overload for <see cref="FromMessages(IEnumerable{MessageDescriptor})"/>
+        /// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
+        /// </remarks>
+        /// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
+        /// Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromMessages(params MessageDescriptor[] messageDescriptors)
+        {
+            return FromMessages((IEnumerable<MessageDescriptor>) messageDescriptors);
+        }
+
+        /// <summary>
+        /// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
+        /// </summary>
+        /// <remarks>
+        /// The specified message descriptors are only used to identify their file descriptors; the returned registry
+        /// contains all the types within the file descriptors which contain the specified message descriptors (and
+        /// the dependencies of those files), not just the specified messages.
+        /// </remarks>
+        /// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
+        /// Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromMessages(IEnumerable<MessageDescriptor> messageDescriptors)
+        {
+            ProtoPreconditions.CheckNotNull(messageDescriptors, nameof(messageDescriptors));
+            return FromFiles(messageDescriptors.Select(md => md.File));
+        }
+
+        /// <summary>
+        /// Builder class which isn't exposed, but acts as a convenient alternative to passing round two dictionaries in recursive calls.
+        /// </summary>
+        private class Builder
+        {
+            private readonly Dictionary<string, MessageDescriptor> types;
+            private readonly HashSet<string> fileDescriptorNames;
+
+            internal Builder()
+            {
+                types = new Dictionary<string, MessageDescriptor>();
+                fileDescriptorNames = new HashSet<string>();
+            }
+
+            internal void AddFile(FileDescriptor fileDescriptor)
+            {
+                if (!fileDescriptorNames.Add(fileDescriptor.Name))
+                {
+                    return;
+                }
+                foreach (var dependency in fileDescriptor.Dependencies)
+                {
+                    AddFile(dependency);
+                }
+                foreach (var message in fileDescriptor.MessageTypes)
+                {
+                    AddMessage(message);
+                }
+            }
+
+            private void AddMessage(MessageDescriptor messageDescriptor)
+            {
+                foreach (var nestedType in messageDescriptor.NestedTypes)
+                {
+                    AddMessage(nestedType);
+                }
+                // This will overwrite any previous entry. Given that each file should
+                // only be added once, this could be a problem such as package A.B with type C,
+                // and package A with type B.C... it's unclear what we should do in that case.
+                types[messageDescriptor.FullName] = messageDescriptor;
+            }
+
+            internal TypeRegistry Build()
+            {
+                return new TypeRegistry(types);
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
new file mode 100644
index 0000000..48cd99a
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
@@ -0,0 +1,230 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/any.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class AnyReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/any.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static AnyReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi",
+            "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQksKE2Nv",
+            "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAGgAQGiAgNHUEKqAh5Hb29n",
+            "bGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Any), global::Google.Protobuf.WellKnownTypes.Any.Parser, new[]{ "TypeUrl", "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  `Any` contains an arbitrary serialized message along with a URL
+  ///  that describes the type of the serialized message.
+  ///
+  ///  JSON
+  ///  ====
+  ///  The JSON representation of an `Any` value uses the regular
+  ///  representation of the deserialized, embedded message, with an
+  ///  additional field `@type` which contains the type URL. Example:
+  ///
+  ///      package google.profile;
+  ///      message Person {
+  ///        string first_name = 1;
+  ///        string last_name = 2;
+  ///      }
+  ///
+  ///      {
+  ///        "@type": "type.googleapis.com/google.profile.Person",
+  ///        "firstName": &lt;string>,
+  ///        "lastName": &lt;string>
+  ///      }
+  ///
+  ///  If the embedded message type is well-known and has a custom JSON
+  ///  representation, that representation will be embedded adding a field
+  ///  `value` which holds the custom JSON in addition to the `@type`
+  ///  field. Example (for message [google.protobuf.Duration][]):
+  ///
+  ///      {
+  ///        "@type": "type.googleapis.com/google.protobuf.Duration",
+  ///        "value": "1.212s"
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Any : pb::IMessage<Any> {
+    private static readonly pb::MessageParser<Any> _parser = new pb::MessageParser<Any>(() => new Any());
+    public static pb::MessageParser<Any> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Any() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Any(Any other) : this() {
+      typeUrl_ = other.typeUrl_;
+      value_ = other.value_;
+    }
+
+    public Any Clone() {
+      return new Any(this);
+    }
+
+    /// <summary>Field number for the "type_url" field.</summary>
+    public const int TypeUrlFieldNumber = 1;
+    private string typeUrl_ = "";
+    /// <summary>
+    ///  A URL/resource name whose content describes the type of the
+    ///  serialized message.
+    ///
+    ///  For URLs which use the schema `http`, `https`, or no schema, the
+    ///  following restrictions and interpretations apply:
+    ///
+    ///  * If no schema is provided, `https` is assumed.
+    ///  * The last segment of the URL's path must represent the fully
+    ///    qualified name of the type (as in `path/google.protobuf.Duration`).
+    ///  * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+    ///    value in binary format, or produce an error.
+    ///  * Applications are allowed to cache lookup results based on the
+    ///    URL, or have them precompiled into a binary to avoid any
+    ///    lookup. Therefore, binary compatibility needs to be preserved
+    ///    on changes to types. (Use versioned type names to manage
+    ///    breaking changes.)
+    ///
+    ///  Schemas other than `http`, `https` (or the empty schema) might be
+    ///  used with implementation specific semantics.
+    /// </summary>
+    public string TypeUrl {
+      get { return typeUrl_; }
+      set {
+        typeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 2;
+    private pb::ByteString value_ = pb::ByteString.Empty;
+    /// <summary>
+    ///  Must be valid serialized data of the above specified type.
+    /// </summary>
+    public pb::ByteString Value {
+      get { return value_; }
+      set {
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Any);
+    }
+
+    public bool Equals(Any other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (TypeUrl != other.TypeUrl) return false;
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (TypeUrl.Length != 0) hash ^= TypeUrl.GetHashCode();
+      if (Value.Length != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (TypeUrl.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(TypeUrl);
+      }
+      if (Value.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteBytes(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (TypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeUrl);
+      }
+      if (Value.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Any other) {
+      if (other == null) {
+        return;
+      }
+      if (other.TypeUrl.Length != 0) {
+        TypeUrl = other.TypeUrl;
+      }
+      if (other.Value.Length != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            TypeUrl = input.ReadString();
+            break;
+          }
+          case 18: {
+            Value = input.ReadBytes();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
new file mode 100644
index 0000000..9d43856
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using Google.Protobuf.Reflection;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public partial class Any
+    {
+        // This could be moved to MessageDescriptor if we wanted to, but keeping it here means
+        // all the Any-specific code is in the same place.
+        private static string GetTypeUrl(MessageDescriptor descriptor)
+        {
+            return "type.googleapis.com/" + descriptor.FullName;
+        }
+
+        /// <summary>
+        /// Unpacks the content of this Any message into the target message type,
+        /// which must match the type URL within this Any message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to unpack the content into.</typeparam>
+        /// <returns>The unpacked message.</returns>
+        /// <exception cref="InvalidProtocolBufferException">The target message type doesn't match the type URL in this message</exception>
+        public T Unpack<T>() where T : IMessage, new()
+        {
+            // Note: this doesn't perform as well is it might. We could take a MessageParser<T> in an alternative overload,
+            // which would be expected to perform slightly better... although the difference is likely to be negligible.
+            T target = new T();
+            string targetTypeUrl = GetTypeUrl(target.Descriptor);
+            if (TypeUrl != targetTypeUrl)
+            {
+                throw new InvalidProtocolBufferException(string.Format("Type url for {0} is {1}; Any message's type url is {2}",
+                    target.Descriptor.Name, targetTypeUrl, TypeUrl));
+            }
+            target.MergeFrom(Value);
+            return target;
+        }
+
+        /// <summary>
+        /// Packs the specified message into an Any message.
+        /// </summary>
+        /// <param name="message">The message to pack.</param>
+        /// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
+        public static Any Pack(IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, "message");
+            return new Any { TypeUrl = GetTypeUrl(message.Descriptor), Value = message.ToByteString() };
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
new file mode 100644
index 0000000..de7aea3
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
@@ -0,0 +1,847 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/api.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class ApiReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/api.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static ApiReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chlnb29nbGUvcHJvdG9idWYvYXBpLnByb3RvEg9nb29nbGUucHJvdG9idWYa",
+            "JGdvb2dsZS9wcm90b2J1Zi9zb3VyY2VfY29udGV4dC5wcm90bxoaZ29vZ2xl",
+            "L3Byb3RvYnVmL3R5cGUucHJvdG8igQIKA0FwaRIMCgRuYW1lGAEgASgJEigK",
+            "B21ldGhvZHMYAiADKAsyFy5nb29nbGUucHJvdG9idWYuTWV0aG9kEigKB29w",
+            "dGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9uEg8KB3ZlcnNp",
+            "b24YBCABKAkSNgoOc291cmNlX2NvbnRleHQYBSABKAsyHi5nb29nbGUucHJv",
+            "dG9idWYuU291cmNlQ29udGV4dBImCgZtaXhpbnMYBiADKAsyFi5nb29nbGUu",
+            "cHJvdG9idWYuTWl4aW4SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3Rv",
+            "YnVmLlN5bnRheCLVAQoGTWV0aG9kEgwKBG5hbWUYASABKAkSGAoQcmVxdWVz",
+            "dF90eXBlX3VybBgCIAEoCRIZChFyZXF1ZXN0X3N0cmVhbWluZxgDIAEoCBIZ",
+            "ChFyZXNwb25zZV90eXBlX3VybBgEIAEoCRIaChJyZXNwb25zZV9zdHJlYW1p",
+            "bmcYBSABKAgSKAoHb3B0aW9ucxgGIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5P",
+            "cHRpb24SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3RvYnVmLlN5bnRh",
+            "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCSwoTY29t",
+            "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAaABAaICA0dQQqoCHkdvb2ds",
+            "ZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Api), global::Google.Protobuf.WellKnownTypes.Api.Parser, new[]{ "Name", "Methods", "Options", "Version", "SourceContext", "Mixins", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Method), global::Google.Protobuf.WellKnownTypes.Method.Parser, new[]{ "Name", "RequestTypeUrl", "RequestStreaming", "ResponseTypeUrl", "ResponseStreaming", "Options", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Mixin), global::Google.Protobuf.WellKnownTypes.Mixin.Parser, new[]{ "Name", "Root" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  Api is a light-weight descriptor for a protocol buffer service.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Api : pb::IMessage<Api> {
+    private static readonly pb::MessageParser<Api> _parser = new pb::MessageParser<Api>(() => new Api());
+    public static pb::MessageParser<Api> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Api() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Api(Api other) : this() {
+      name_ = other.name_;
+      methods_ = other.methods_.Clone();
+      options_ = other.options_.Clone();
+      version_ = other.version_;
+      SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      mixins_ = other.mixins_.Clone();
+      syntax_ = other.syntax_;
+    }
+
+    public Api Clone() {
+      return new Api(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The fully qualified name of this api, including package name
+    ///  followed by the api's simple name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "methods" field.</summary>
+    public const int MethodsFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Method> _repeated_methods_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Method.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> methods_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method>();
+    /// <summary>
+    ///  The methods of this api, in unspecified order.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> Methods {
+      get { return methods_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Any metadata attached to the API.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "version" field.</summary>
+    public const int VersionFieldNumber = 4;
+    private string version_ = "";
+    /// <summary>
+    ///  A version string for this api. If specified, must have the form
+    ///  `major-version.minor-version`, as in `1.10`. If the minor version
+    ///  is omitted, it defaults to zero. If the entire version field is
+    ///  empty, the major version is derived from the package name, as
+    ///  outlined below. If the field is not empty, the version in the
+    ///  package name will be verified to be consistent with what is
+    ///  provided here.
+    ///
+    ///  The versioning schema uses [semantic
+    ///  versioning](http://semver.org) where the major version number
+    ///  indicates a breaking change and the minor version an additive,
+    ///  non-breaking change. Both version numbers are signals to users
+    ///  what to expect from different versions, and should be carefully
+    ///  chosen based on the product plan.
+    ///
+    ///  The major version is also reflected in the package name of the
+    ///  API, which must end in `v&lt;major-version>`, as in
+    ///  `google.feature.v1`. For major versions 0 and 1, the suffix can
+    ///  be omitted. Zero major versions must only be used for
+    ///  experimental, none-GA apis.
+    /// </summary>
+    public string Version {
+      get { return version_; }
+      set {
+        version_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "source_context" field.</summary>
+    public const int SourceContextFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  Source context for the protocol buffer service represented by this
+    ///  message.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
+      get { return sourceContext_; }
+      set {
+        sourceContext_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "mixins" field.</summary>
+    public const int MixinsFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Mixin> _repeated_mixins_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Mixin.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> mixins_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin>();
+    /// <summary>
+    ///  Included APIs. See [Mixin][].
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> Mixins {
+      get { return mixins_; }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 7;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax of the service.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Api);
+    }
+
+    public bool Equals(Api other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!methods_.Equals(other.methods_)) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (Version != other.Version) return false;
+      if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if(!mixins_.Equals(other.mixins_)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= methods_.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (Version.Length != 0) hash ^= Version.GetHashCode();
+      if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      hash ^= mixins_.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      methods_.WriteTo(output, _repeated_methods_codec);
+      options_.WriteTo(output, _repeated_options_codec);
+      if (Version.Length != 0) {
+        output.WriteRawTag(34);
+        output.WriteString(Version);
+      }
+      if (sourceContext_ != null) {
+        output.WriteRawTag(42);
+        output.WriteMessage(SourceContext);
+      }
+      mixins_.WriteTo(output, _repeated_mixins_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(56);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += methods_.CalculateSize(_repeated_methods_codec);
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (Version.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Version);
+      }
+      if (sourceContext_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
+      }
+      size += mixins_.CalculateSize(_repeated_mixins_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Api other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      methods_.Add(other.methods_);
+      options_.Add(other.options_);
+      if (other.Version.Length != 0) {
+        Version = other.Version;
+      }
+      if (other.sourceContext_ != null) {
+        if (sourceContext_ == null) {
+          sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+        }
+        SourceContext.MergeFrom(other.SourceContext);
+      }
+      mixins_.Add(other.mixins_);
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            methods_.AddEntriesFrom(input, _repeated_methods_codec);
+            break;
+          }
+          case 26: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 34: {
+            Version = input.ReadString();
+            break;
+          }
+          case 42: {
+            if (sourceContext_ == null) {
+              sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            }
+            input.ReadMessage(sourceContext_);
+            break;
+          }
+          case 50: {
+            mixins_.AddEntriesFrom(input, _repeated_mixins_codec);
+            break;
+          }
+          case 56: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Method represents a method of an api.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Method : pb::IMessage<Method> {
+    private static readonly pb::MessageParser<Method> _parser = new pb::MessageParser<Method>(() => new Method());
+    public static pb::MessageParser<Method> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Method() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Method(Method other) : this() {
+      name_ = other.name_;
+      requestTypeUrl_ = other.requestTypeUrl_;
+      requestStreaming_ = other.requestStreaming_;
+      responseTypeUrl_ = other.responseTypeUrl_;
+      responseStreaming_ = other.responseStreaming_;
+      options_ = other.options_.Clone();
+      syntax_ = other.syntax_;
+    }
+
+    public Method Clone() {
+      return new Method(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The simple name of this method.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "request_type_url" field.</summary>
+    public const int RequestTypeUrlFieldNumber = 2;
+    private string requestTypeUrl_ = "";
+    /// <summary>
+    ///  A URL of the input message type.
+    /// </summary>
+    public string RequestTypeUrl {
+      get { return requestTypeUrl_; }
+      set {
+        requestTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "request_streaming" field.</summary>
+    public const int RequestStreamingFieldNumber = 3;
+    private bool requestStreaming_;
+    /// <summary>
+    ///  If true, the request is streamed.
+    /// </summary>
+    public bool RequestStreaming {
+      get { return requestStreaming_; }
+      set {
+        requestStreaming_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "response_type_url" field.</summary>
+    public const int ResponseTypeUrlFieldNumber = 4;
+    private string responseTypeUrl_ = "";
+    /// <summary>
+    ///  The URL of the output message type.
+    /// </summary>
+    public string ResponseTypeUrl {
+      get { return responseTypeUrl_; }
+      set {
+        responseTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "response_streaming" field.</summary>
+    public const int ResponseStreamingFieldNumber = 5;
+    private bool responseStreaming_;
+    /// <summary>
+    ///  If true, the response is streamed.
+    /// </summary>
+    public bool ResponseStreaming {
+      get { return responseStreaming_; }
+      set {
+        responseStreaming_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Any metadata attached to the method.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 7;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax of this method.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Method);
+    }
+
+    public bool Equals(Method other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (RequestTypeUrl != other.RequestTypeUrl) return false;
+      if (RequestStreaming != other.RequestStreaming) return false;
+      if (ResponseTypeUrl != other.ResponseTypeUrl) return false;
+      if (ResponseStreaming != other.ResponseStreaming) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (RequestTypeUrl.Length != 0) hash ^= RequestTypeUrl.GetHashCode();
+      if (RequestStreaming != false) hash ^= RequestStreaming.GetHashCode();
+      if (ResponseTypeUrl.Length != 0) hash ^= ResponseTypeUrl.GetHashCode();
+      if (ResponseStreaming != false) hash ^= ResponseStreaming.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (RequestTypeUrl.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(RequestTypeUrl);
+      }
+      if (RequestStreaming != false) {
+        output.WriteRawTag(24);
+        output.WriteBool(RequestStreaming);
+      }
+      if (ResponseTypeUrl.Length != 0) {
+        output.WriteRawTag(34);
+        output.WriteString(ResponseTypeUrl);
+      }
+      if (ResponseStreaming != false) {
+        output.WriteRawTag(40);
+        output.WriteBool(ResponseStreaming);
+      }
+      options_.WriteTo(output, _repeated_options_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(56);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (RequestTypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(RequestTypeUrl);
+      }
+      if (RequestStreaming != false) {
+        size += 1 + 1;
+      }
+      if (ResponseTypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(ResponseTypeUrl);
+      }
+      if (ResponseStreaming != false) {
+        size += 1 + 1;
+      }
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Method other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.RequestTypeUrl.Length != 0) {
+        RequestTypeUrl = other.RequestTypeUrl;
+      }
+      if (other.RequestStreaming != false) {
+        RequestStreaming = other.RequestStreaming;
+      }
+      if (other.ResponseTypeUrl.Length != 0) {
+        ResponseTypeUrl = other.ResponseTypeUrl;
+      }
+      if (other.ResponseStreaming != false) {
+        ResponseStreaming = other.ResponseStreaming;
+      }
+      options_.Add(other.options_);
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            RequestTypeUrl = input.ReadString();
+            break;
+          }
+          case 24: {
+            RequestStreaming = input.ReadBool();
+            break;
+          }
+          case 34: {
+            ResponseTypeUrl = input.ReadString();
+            break;
+          }
+          case 40: {
+            ResponseStreaming = input.ReadBool();
+            break;
+          }
+          case 50: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 56: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Declares an API to be included in this API. The including API must
+  ///  redeclare all the methods from the included API, but documentation
+  ///  and options are inherited as follows:
+  ///
+  ///  - If after comment and whitespace stripping, the documentation
+  ///    string of the redeclared method is empty, it will be inherited
+  ///    from the original method.
+  ///
+  ///  - Each annotation belonging to the service config (http,
+  ///    visibility) which is not set in the redeclared method will be
+  ///    inherited.
+  ///
+  ///  - If an http annotation is inherited, the path pattern will be
+  ///    modified as follows. Any version prefix will be replaced by the
+  ///    version of the including API plus the [root][] path if specified.
+  ///
+  ///  Example of a simple mixin:
+  ///
+  ///      package google.acl.v1;
+  ///      service AccessControl {
+  ///        // Get the underlying ACL object.
+  ///        rpc GetAcl(GetAclRequest) returns (Acl) {
+  ///          option (google.api.http).get = "/v1/{resource=**}:getAcl";
+  ///        }
+  ///      }
+  ///
+  ///      package google.storage.v2;
+  ///      service Storage {
+  ///        rpc GetAcl(GetAclRequest) returns (Acl);
+  ///
+  ///        // Get a data record.
+  ///        rpc GetData(GetDataRequest) returns (Data) {
+  ///          option (google.api.http).get = "/v2/{resource=**}";
+  ///        }
+  ///      }
+  ///
+  ///  Example of a mixin configuration:
+  ///
+  ///      apis:
+  ///      - name: google.storage.v2.Storage
+  ///        mixins:
+  ///        - name: google.acl.v1.AccessControl
+  ///
+  ///  The mixin construct implies that all methods in `AccessControl` are
+  ///  also declared with same name and request/response types in
+  ///  `Storage`. A documentation generator or annotation processor will
+  ///  see the effective `Storage.GetAcl` method after inherting
+  ///  documentation and annotations as follows:
+  ///
+  ///      service Storage {
+  ///        // Get the underlying ACL object.
+  ///        rpc GetAcl(GetAclRequest) returns (Acl) {
+  ///          option (google.api.http).get = "/v2/{resource=**}:getAcl";
+  ///        }
+  ///        ...
+  ///      }
+  ///
+  ///  Note how the version in the path pattern changed from `v1` to `v2`.
+  ///
+  ///  If the `root` field in the mixin is specified, it should be a
+  ///  relative path under which inherited HTTP paths are placed. Example:
+  ///
+  ///      apis:
+  ///      - name: google.storage.v2.Storage
+  ///        mixins:
+  ///        - name: google.acl.v1.AccessControl
+  ///          root: acls
+  ///
+  ///  This implies the following inherited HTTP annotation:
+  ///
+  ///      service Storage {
+  ///        // Get the underlying ACL object.
+  ///        rpc GetAcl(GetAclRequest) returns (Acl) {
+  ///          option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
+  ///        }
+  ///        ...
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Mixin : pb::IMessage<Mixin> {
+    private static readonly pb::MessageParser<Mixin> _parser = new pb::MessageParser<Mixin>(() => new Mixin());
+    public static pb::MessageParser<Mixin> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Mixin() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Mixin(Mixin other) : this() {
+      name_ = other.name_;
+      root_ = other.root_;
+    }
+
+    public Mixin Clone() {
+      return new Mixin(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The fully qualified name of the API which is included.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "root" field.</summary>
+    public const int RootFieldNumber = 2;
+    private string root_ = "";
+    /// <summary>
+    ///  If non-empty specifies a path under which inherited HTTP paths
+    ///  are rooted.
+    /// </summary>
+    public string Root {
+      get { return root_; }
+      set {
+        root_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Mixin);
+    }
+
+    public bool Equals(Mixin other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Root != other.Root) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Root.Length != 0) hash ^= Root.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Root.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Root);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Root.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Root);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Mixin other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Root.Length != 0) {
+        Root = other.Root;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Root = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
new file mode 100644
index 0000000..73e221d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
@@ -0,0 +1,229 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/duration.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/duration.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class DurationReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/duration.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static DurationReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90",
+            "b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg",
+            "ASgFQlAKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAaAB",
+            "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
+            "dG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Duration), global::Google.Protobuf.WellKnownTypes.Duration.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  A Duration represents a signed, fixed-length span of time represented
+  ///  as a count of seconds and fractions of seconds at nanosecond
+  ///  resolution. It is independent of any calendar and concepts like "day"
+  ///  or "month". It is related to Timestamp in that the difference between
+  ///  two Timestamp values is a Duration and it can be added or subtracted
+  ///  from a Timestamp. Range is approximately +-10,000 years.
+  ///
+  ///  Example 1: Compute Duration from two Timestamps in pseudo code.
+  ///
+  ///      Timestamp start = ...;
+  ///      Timestamp end = ...;
+  ///      Duration duration = ...;
+  ///
+  ///      duration.seconds = end.seconds - start.seconds;
+  ///      duration.nanos = end.nanos - start.nanos;
+  ///
+  ///      if (duration.seconds &lt; 0 &amp;&amp; duration.nanos > 0) {
+  ///        duration.seconds += 1;
+  ///        duration.nanos -= 1000000000;
+  ///      } else if (durations.seconds > 0 &amp;&amp; duration.nanos &lt; 0) {
+  ///        duration.seconds -= 1;
+  ///        duration.nanos += 1000000000;
+  ///      }
+  ///
+  ///  Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
+  ///
+  ///      Timestamp start = ...;
+  ///      Duration duration = ...;
+  ///      Timestamp end = ...;
+  ///
+  ///      end.seconds = start.seconds + duration.seconds;
+  ///      end.nanos = start.nanos + duration.nanos;
+  ///
+  ///      if (end.nanos &lt; 0) {
+  ///        end.seconds -= 1;
+  ///        end.nanos += 1000000000;
+  ///      } else if (end.nanos >= 1000000000) {
+  ///        end.seconds += 1;
+  ///        end.nanos -= 1000000000;
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Duration : pb::IMessage<Duration> {
+    private static readonly pb::MessageParser<Duration> _parser = new pb::MessageParser<Duration>(() => new Duration());
+    public static pb::MessageParser<Duration> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Duration() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Duration(Duration other) : this() {
+      seconds_ = other.seconds_;
+      nanos_ = other.nanos_;
+    }
+
+    public Duration Clone() {
+      return new Duration(this);
+    }
+
+    /// <summary>Field number for the "seconds" field.</summary>
+    public const int SecondsFieldNumber = 1;
+    private long seconds_;
+    /// <summary>
+    ///  Signed seconds of the span of time. Must be from -315,576,000,000
+    ///  to +315,576,000,000 inclusive.
+    /// </summary>
+    public long Seconds {
+      get { return seconds_; }
+      set {
+        seconds_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "nanos" field.</summary>
+    public const int NanosFieldNumber = 2;
+    private int nanos_;
+    /// <summary>
+    ///  Signed fractions of a second at nanosecond resolution of the span
+    ///  of time. Durations less than one second are represented with a 0
+    ///  `seconds` field and a positive or negative `nanos` field. For durations
+    ///  of one second or more, a non-zero value for the `nanos` field must be
+    ///  of the same sign as the `seconds` field. Must be from -999,999,999
+    ///  to +999,999,999 inclusive.
+    /// </summary>
+    public int Nanos {
+      get { return nanos_; }
+      set {
+        nanos_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Duration);
+    }
+
+    public bool Equals(Duration other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Seconds != other.Seconds) return false;
+      if (Nanos != other.Nanos) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Seconds != 0L) hash ^= Seconds.GetHashCode();
+      if (Nanos != 0) hash ^= Nanos.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Seconds != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Seconds);
+      }
+      if (Nanos != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Nanos);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Seconds != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Seconds);
+      }
+      if (Nanos != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Duration other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Seconds != 0L) {
+        Seconds = other.Seconds;
+      }
+      if (other.Nanos != 0) {
+        Nanos = other.Nanos;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Seconds = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            Nanos = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs
new file mode 100644
index 0000000..f164bfd
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs
@@ -0,0 +1,270 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Globalization;
+using System.Text;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    // Manually-written partial class for the Duration well-known type,
+    // providing a conversion to TimeSpan and convenience operators.
+    public partial class Duration : ICustomDiagnosticMessage
+    {
+        /// <summary>
+        /// The number of nanoseconds in a second.
+        /// </summary>
+        public const int NanosecondsPerSecond = 1000000000;
+        /// <summary>
+        /// The number of nanoseconds in a BCL tick (as used by <see cref="TimeSpan"/> and <see cref="DateTime"/>).
+        /// </summary>
+        public const int NanosecondsPerTick = 100;
+
+        /// <summary>
+        /// The maximum permitted number of seconds.
+        /// </summary>
+        public const long MaxSeconds = 315576000000L;
+
+        /// <summary>
+        /// The minimum permitted number of seconds.
+        /// </summary>
+        public const long MinSeconds = -315576000000L;
+
+        internal const int MaxNanoseconds = NanosecondsPerSecond - 1;
+        internal const int MinNanoseconds = -NanosecondsPerSecond + 1;
+
+        internal static bool IsNormalized(long seconds, int nanoseconds)
+        {
+            // Simple boundaries
+            if (seconds < MinSeconds || seconds > MaxSeconds ||
+                nanoseconds < MinNanoseconds || nanoseconds > MaxNanoseconds)
+            {
+                return false;
+            }
+            // We only have a problem is one is strictly negative and the other is
+            // strictly positive.
+            return Math.Sign(seconds) * Math.Sign(nanoseconds) != -1;
+        }
+
+        /// <summary>
+        /// Converts this <see cref="Duration"/> to a <see cref="TimeSpan"/>.
+        /// </summary>
+        /// <remarks>If the duration is not a precise number of ticks, it is truncated towards 0.</remarks>
+        /// <returns>The value of this duration, as a <c>TimeSpan</c>.</returns>
+        /// <exception cref="InvalidOperationException">This value isn't a valid normalized duration, as
+        /// described in the documentation.</exception>
+        public TimeSpan ToTimeSpan()
+        {
+            checked
+            {
+                if (!IsNormalized(Seconds, Nanos))
+                {
+                    throw new InvalidOperationException("Duration was not a valid normalized duration");
+                }
+                long ticks = Seconds * TimeSpan.TicksPerSecond + Nanos / NanosecondsPerTick;
+                return TimeSpan.FromTicks(ticks);
+            }
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
+        /// </summary>
+        /// <param name="timeSpan">The <c>TimeSpan</c> to convert.</param>
+        /// <returns>The value of the given <c>TimeSpan</c>, as a <c>Duration</c>.</returns>
+        public static Duration FromTimeSpan(TimeSpan timeSpan)
+        {
+            checked
+            {
+                long ticks = timeSpan.Ticks;
+                long seconds = ticks / TimeSpan.TicksPerSecond;
+                int nanos = (int) (ticks % TimeSpan.TicksPerSecond) * NanosecondsPerTick;
+                return new Duration { Seconds = seconds, Nanos = nanos };
+            }
+        }
+
+        /// <summary>
+        /// Returns the result of negating the duration. For example, the negation of 5 minutes is -5 minutes.
+        /// </summary>
+        /// <param name="value">The duration to negate. Must not be null.</param>
+        /// <returns>The negated value of this duration.</returns>
+        public static Duration operator -(Duration value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            checked
+            {
+                return Normalize(-value.Seconds, -value.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Adds the two specified <see cref="Duration"/> values together.
+        /// </summary>
+        /// <param name="lhs">The first value to add. Must not be null.</param>
+        /// <param name="rhs">The second value to add. Must not be null.</param>
+        /// <returns></returns>
+        public static Duration operator +(Duration lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Subtracts one <see cref="Duration"/> from another.
+        /// </summary>
+        /// <param name="lhs">The duration to subtract from. Must not be null.</param>
+        /// <param name="rhs">The duration to subtract. Must not be null.</param>
+        /// <returns>The difference between the two specified durations.</returns>
+        public static Duration operator -(Duration lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
+            }
+        }
+        
+        /// <summary>
+        /// Creates a duration with the normalized values from the given number of seconds and
+        /// nanoseconds, conforming with the description in the proto file.
+        /// </summary>
+        internal static Duration Normalize(long seconds, int nanoseconds)
+        {
+            // Ensure that nanoseconds is in the range (-1,000,000,000, +1,000,000,000)
+            int extraSeconds = nanoseconds / NanosecondsPerSecond;
+            seconds += extraSeconds;
+            nanoseconds -= extraSeconds * NanosecondsPerSecond;
+
+            // Now make sure that Sign(seconds) == Sign(nanoseconds) if Sign(seconds) != 0.
+            if (seconds < 0 && nanoseconds > 0)
+            {
+                seconds += 1;
+                nanoseconds -= NanosecondsPerSecond;
+            }
+            else if (seconds > 0 && nanoseconds < 0)
+            {
+                seconds -= 1;
+                nanoseconds += NanosecondsPerSecond;
+            }
+            return new Duration { Seconds = seconds, Nanos = nanoseconds };
+        }
+
+        /// <summary>
+        /// Converts a duration specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>duration.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="seconds">Seconds portion of the duration.</param>
+        /// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
+        {
+            if (IsNormalized(seconds, nanoseconds))
+            {
+                var builder = new StringBuilder();
+                builder.Append('"');
+                // The seconds part will normally provide the minus sign if we need it, but not if it's 0...
+                if (seconds == 0 && nanoseconds < 0)
+                {
+                    builder.Append('-');
+                }
+
+                builder.Append(seconds.ToString("d", CultureInfo.InvariantCulture));
+                AppendNanoseconds(builder, Math.Abs(nanoseconds));
+                builder.Append("s\"");
+                return builder.ToString();
+            }
+            if (diagnosticOnly)
+            {
+                // Note: the double braces here are escaping for braces in format strings.
+                return string.Format(CultureInfo.InvariantCulture,
+                    "{{ \"@warning\": \"Invalid Duration\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
+                    seconds,
+                    nanoseconds);
+            }
+            else
+            {
+                throw new InvalidOperationException("Non-normalized duration value");
+            }
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="Duration"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Seconds, Nanos, true);
+        }
+
+        /// <summary>
+        /// Appends a number of nanoseconds to a StringBuilder. Either 0 digits are added (in which
+        /// case no "." is appended), or 3 6 or 9 digits. This is internal for use in Timestamp as well
+        /// as Duration.
+        /// </summary>
+        internal static void AppendNanoseconds(StringBuilder builder, int nanos)
+        {
+            if (nanos != 0)
+            {
+                builder.Append('.');
+                // Output to 3, 6 or 9 digits.
+                if (nanos % 1000000 == 0)
+                {
+                    builder.Append((nanos / 1000000).ToString("d3", CultureInfo.InvariantCulture));
+                }
+                else if (nanos % 1000 == 0)
+                {
+                    builder.Append((nanos / 1000).ToString("d6", CultureInfo.InvariantCulture));
+                }
+                else
+                {
+                    builder.Append(nanos.ToString("d9", CultureInfo.InvariantCulture));
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
new file mode 100644
index 0000000..6cad412
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
@@ -0,0 +1,131 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/empty.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class EmptyReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/empty.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static EmptyReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1",
+            "ZiIHCgVFbXB0eUJQChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
+            "UAGgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw",
+            "ZXNiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Empty), global::Google.Protobuf.WellKnownTypes.Empty.Parser, null, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  A generic empty message that you can re-use to avoid defining duplicated
+  ///  empty messages in your APIs. A typical example is to use it as the request
+  ///  or the response type of an API method. For instance:
+  ///
+  ///      service Foo {
+  ///        rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+  ///      }
+  ///
+  ///  The JSON representation for `Empty` is empty JSON object `{}`.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Empty : pb::IMessage<Empty> {
+    private static readonly pb::MessageParser<Empty> _parser = new pb::MessageParser<Empty>(() => new Empty());
+    public static pb::MessageParser<Empty> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Empty() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Empty(Empty other) : this() {
+    }
+
+    public Empty Clone() {
+      return new Empty(this);
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Empty);
+    }
+
+    public bool Equals(Empty other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(Empty other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
new file mode 100644
index 0000000..2ba2b96
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
@@ -0,0 +1,265 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/field_mask.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class FieldMaskReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/field_mask.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static FieldMaskReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy",
+            "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJRChNjb20uZ29v",
+            "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABoAEBogIDR1BCqgIeR29v",
+            "Z2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FieldMask), global::Google.Protobuf.WellKnownTypes.FieldMask.Parser, new[]{ "Paths" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  `FieldMask` represents a set of symbolic field paths, for example:
+  ///
+  ///      paths: "f.a"
+  ///      paths: "f.b.d"
+  ///
+  ///  Here `f` represents a field in some root message, `a` and `b`
+  ///  fields in the message found in `f`, and `d` a field found in the
+  ///  message in `f.b`.
+  ///
+  ///  Field masks are used to specify a subset of fields that should be
+  ///  returned by a get operation or modified by an update operation.
+  ///  Field masks also have a custom JSON encoding (see below).
+  ///
+  ///  # Field Masks in Projections
+  ///
+  ///  When used in the context of a projection, a response message or
+  ///  sub-message is filtered by the API to only contain those fields as
+  ///  specified in the mask. For example, if the mask in the previous
+  ///  example is applied to a response message as follows:
+  ///
+  ///      f {
+  ///        a : 22
+  ///        b {
+  ///          d : 1
+  ///          x : 2
+  ///        }
+  ///        y : 13
+  ///      }
+  ///      z: 8
+  ///
+  ///  The result will not contain specific values for fields x,y and z
+  ///  (their value will be set to the default, and omitted in proto text
+  ///  output):
+  ///
+  ///      f {
+  ///        a : 22
+  ///        b {
+  ///          d : 1
+  ///        }
+  ///      }
+  ///
+  ///  A repeated field is not allowed except at the last position of a
+  ///  field mask.
+  ///
+  ///  If a FieldMask object is not present in a get operation, the
+  ///  operation applies to all fields (as if a FieldMask of all fields
+  ///  had been specified).
+  ///
+  ///  Note that a field mask does not necessarily applies to the
+  ///  top-level response message. In case of a REST get operation, the
+  ///  field mask applies directly to the response, but in case of a REST
+  ///  list operation, the mask instead applies to each individual message
+  ///  in the returned resource list. In case of a REST custom method,
+  ///  other definitions may be used. Where the mask applies will be
+  ///  clearly documented together with its declaration in the API.  In
+  ///  any case, the effect on the returned resource/resources is required
+  ///  behavior for APIs.
+  ///
+  ///  # Field Masks in Update Operations
+  ///
+  ///  A field mask in update operations specifies which fields of the
+  ///  targeted resource are going to be updated. The API is required
+  ///  to only change the values of the fields as specified in the mask
+  ///  and leave the others untouched. If a resource is passed in to
+  ///  describe the updated values, the API ignores the values of all
+  ///  fields not covered by the mask.
+  ///
+  ///  In order to reset a field's value to the default, the field must
+  ///  be in the mask and set to the default value in the provided resource.
+  ///  Hence, in order to reset all fields of a resource, provide a default
+  ///  instance of the resource and set all fields in the mask, or do
+  ///  not provide a mask as described below.
+  ///
+  ///  If a field mask is not present on update, the operation applies to
+  ///  all fields (as if a field mask of all fields has been specified).
+  ///  Note that in the presence of schema evolution, this may mean that
+  ///  fields the client does not know and has therefore not filled into
+  ///  the request will be reset to their default. If this is unwanted
+  ///  behavior, a specific service may require a client to always specify
+  ///  a field mask, producing an error if not.
+  ///
+  ///  As with get operations, the location of the resource which
+  ///  describes the updated values in the request message depends on the
+  ///  operation kind. In any case, the effect of the field mask is
+  ///  required to be honored by the API.
+  ///
+  ///  ## Considerations for HTTP REST
+  ///
+  ///  The HTTP kind of an update operation which uses a field mask must
+  ///  be set to PATCH instead of PUT in order to satisfy HTTP semantics
+  ///  (PUT must only be used for full updates).
+  ///
+  ///  # JSON Encoding of Field Masks
+  ///
+  ///  In JSON, a field mask is encoded as a single string where paths are
+  ///  separated by a comma. Fields name in each path are converted
+  ///  to/from lower-camel naming conventions.
+  ///
+  ///  As an example, consider the following message declarations:
+  ///
+  ///      message Profile {
+  ///        User user = 1;
+  ///        Photo photo = 2;
+  ///      }
+  ///      message User {
+  ///        string display_name = 1;
+  ///        string address = 2;
+  ///      }
+  ///
+  ///  In proto a field mask for `Profile` may look as such:
+  ///
+  ///      mask {
+  ///        paths: "user.display_name"
+  ///        paths: "photo"
+  ///      }
+  ///
+  ///  In JSON, the same mask is represented as below:
+  ///
+  ///      {
+  ///        mask: "user.displayName,photo"
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FieldMask : pb::IMessage<FieldMask> {
+    private static readonly pb::MessageParser<FieldMask> _parser = new pb::MessageParser<FieldMask>(() => new FieldMask());
+    public static pb::MessageParser<FieldMask> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FieldMask() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FieldMask(FieldMask other) : this() {
+      paths_ = other.paths_.Clone();
+    }
+
+    public FieldMask Clone() {
+      return new FieldMask(this);
+    }
+
+    /// <summary>Field number for the "paths" field.</summary>
+    public const int PathsFieldNumber = 1;
+    private static readonly pb::FieldCodec<string> _repeated_paths_codec
+        = pb::FieldCodec.ForString(10);
+    private readonly pbc::RepeatedField<string> paths_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  The set of field mask paths.
+    /// </summary>
+    public pbc::RepeatedField<string> Paths {
+      get { return paths_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FieldMask);
+    }
+
+    public bool Equals(FieldMask other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!paths_.Equals(other.paths_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= paths_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      paths_.WriteTo(output, _repeated_paths_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += paths_.CalculateSize(_repeated_paths_codec);
+      return size;
+    }
+
+    public void MergeFrom(FieldMask other) {
+      if (other == null) {
+        return;
+      }
+      paths_.Add(other.paths_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            paths_.AddEntriesFrom(input, _repeated_paths_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
new file mode 100644
index 0000000..df1292d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
@@ -0,0 +1,122 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    // Manually-written partial class for the FieldMask well-known type.
+    public partial class FieldMask : ICustomDiagnosticMessage
+    {
+        /// <summary>
+        /// Converts a timestamp  specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>field_mask.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="paths">Paths in the field mask</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(IList<string> paths, bool diagnosticOnly)
+        {
+            var firstInvalid = paths.FirstOrDefault(p => !ValidatePath(p));
+            if (firstInvalid == null)
+            {
+                var builder = new StringBuilder();
+                JsonFormatter.WriteString(builder, string.Join(",", paths.Select(JsonFormatter.ToCamelCase)));
+                return builder.ToString();
+            }
+            else
+            {
+                if (diagnosticOnly)
+                {
+                    var builder = new StringBuilder();
+                    builder.Append("{ \"@warning\": \"Invalid FieldMask\", \"paths\": ");
+                    JsonFormatter.Default.WriteList(builder, (IList) paths);
+                    builder.Append(" }");
+                    return builder.ToString();
+                }
+                else
+                {
+                    throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {firstInvalid}");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Camel-case converter with added strictness for field mask formatting.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
+        private static bool ValidatePath(string input)
+        {
+            for (int i = 0; i < input.Length; i++)
+            {
+                char c = input[i];
+                if (c >= 'A' && c <= 'Z')
+                {
+                    return false;
+                }
+                if (c == '_' && i < input.Length - 1)
+                {
+                    char next = input[i + 1];
+                    if (next < 'a' || next > 'z')
+                    {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="FieldMask"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Paths, true);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
new file mode 100644
index 0000000..a235ece
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
@@ -0,0 +1,156 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/source_context.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class SourceContextReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/source_context.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static SourceContextReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds",
+            "ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo",
+            "CUJVChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q",
+            "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
+            "cHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.SourceContext), global::Google.Protobuf.WellKnownTypes.SourceContext.Parser, new[]{ "FileName" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  `SourceContext` represents information about the source of a
+  ///  protobuf element, like the file in which it is defined.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class SourceContext : pb::IMessage<SourceContext> {
+    private static readonly pb::MessageParser<SourceContext> _parser = new pb::MessageParser<SourceContext>(() => new SourceContext());
+    public static pb::MessageParser<SourceContext> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public SourceContext() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public SourceContext(SourceContext other) : this() {
+      fileName_ = other.fileName_;
+    }
+
+    public SourceContext Clone() {
+      return new SourceContext(this);
+    }
+
+    /// <summary>Field number for the "file_name" field.</summary>
+    public const int FileNameFieldNumber = 1;
+    private string fileName_ = "";
+    /// <summary>
+    ///  The path-qualified name of the .proto file that contained the associated
+    ///  protobuf element.  For example: `"google/protobuf/source.proto"`.
+    /// </summary>
+    public string FileName {
+      get { return fileName_; }
+      set {
+        fileName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as SourceContext);
+    }
+
+    public bool Equals(SourceContext other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (FileName != other.FileName) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (FileName.Length != 0) hash ^= FileName.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (FileName.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(FileName);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (FileName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(FileName);
+      }
+      return size;
+    }
+
+    public void MergeFrom(SourceContext other) {
+      if (other == null) {
+        return;
+      }
+      if (other.FileName.Length != 0) {
+        FileName = other.FileName;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            FileName = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
new file mode 100644
index 0000000..8e2ce8c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
@@ -0,0 +1,599 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/struct.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class StructReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/struct.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static StructReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chxnb29nbGUvcHJvdG9idWYvc3RydWN0LnByb3RvEg9nb29nbGUucHJvdG9i",
+            "dWYihAEKBlN0cnVjdBIzCgZmaWVsZHMYASADKAsyIy5nb29nbGUucHJvdG9i",
+            "dWYuU3RydWN0LkZpZWxkc0VudHJ5GkUKC0ZpZWxkc0VudHJ5EgsKA2tleRgB",
+            "IAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToC",
+            "OAEi6gEKBVZhbHVlEjAKCm51bGxfdmFsdWUYASABKA4yGi5nb29nbGUucHJv",
+            "dG9idWYuTnVsbFZhbHVlSAASFgoMbnVtYmVyX3ZhbHVlGAIgASgBSAASFgoM",
+            "c3RyaW5nX3ZhbHVlGAMgASgJSAASFAoKYm9vbF92YWx1ZRgEIAEoCEgAEi8K",
+            "DHN0cnVjdF92YWx1ZRgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RI",
+            "ABIwCgpsaXN0X3ZhbHVlGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLkxpc3RW",
+            "YWx1ZUgAQgYKBGtpbmQiMwoJTGlzdFZhbHVlEiYKBnZhbHVlcxgBIAMoCzIW",
+            "Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W",
+            "QUxVRRAAQk4KE2NvbS5nb29nbGUucHJvdG9idWZCC1N0cnVjdFByb3RvUAGg",
+            "AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy",
+            "b3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.NullValue), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Struct), global::Google.Protobuf.WellKnownTypes.Struct.Parser, new[]{ "Fields" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Value), global::Google.Protobuf.WellKnownTypes.Value.Parser, new[]{ "NullValue", "NumberValue", "StringValue", "BoolValue", "StructValue", "ListValue" }, new[]{ "Kind" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.ListValue), global::Google.Protobuf.WellKnownTypes.ListValue.Parser, new[]{ "Values" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  /// <summary>
+  ///  `NullValue` is a singleton enumeration to represent the null value for the
+  ///  `Value` type union.
+  ///
+  ///   The JSON representation for `NullValue` is JSON `null`.
+  /// </summary>
+  public enum NullValue {
+    /// <summary>
+    ///  Null value.
+    /// </summary>
+    NULL_VALUE = 0,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  `Struct` represents a structured data value, consisting of fields
+  ///  which map to dynamically typed values. In some languages, `Struct`
+  ///  might be supported by a native representation. For example, in
+  ///  scripting languages like JS a struct is represented as an
+  ///  object. The details of that representation are described together
+  ///  with the proto support for the language.
+  ///
+  ///  The JSON representation for `Struct` is JSON object.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Struct : pb::IMessage<Struct> {
+    private static readonly pb::MessageParser<Struct> _parser = new pb::MessageParser<Struct>(() => new Struct());
+    public static pb::MessageParser<Struct> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Struct() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Struct(Struct other) : this() {
+      fields_ = other.fields_.Clone();
+    }
+
+    public Struct Clone() {
+      return new Struct(this);
+    }
+
+    /// <summary>Field number for the "fields" field.</summary>
+    public const int FieldsFieldNumber = 1;
+    private static readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec _map_fields_codec
+        = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Value.Parser), 10);
+    private readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> fields_ = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>();
+    /// <summary>
+    ///  Map of dynamically typed values.
+    /// </summary>
+    public pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> Fields {
+      get { return fields_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Struct);
+    }
+
+    public bool Equals(Struct other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (!Fields.Equals(other.Fields)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= Fields.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      fields_.WriteTo(output, _map_fields_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += fields_.CalculateSize(_map_fields_codec);
+      return size;
+    }
+
+    public void MergeFrom(Struct other) {
+      if (other == null) {
+        return;
+      }
+      fields_.Add(other.fields_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            fields_.AddEntriesFrom(input, _map_fields_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  `Value` represents a dynamically typed value which can be either
+  ///  null, a number, a string, a boolean, a recursive struct value, or a
+  ///  list of values. A producer of value is expected to set one of that
+  ///  variants, absence of any variant indicates an error.
+  ///
+  ///  The JSON representation for `Value` is JSON value.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Value : pb::IMessage<Value> {
+    private static readonly pb::MessageParser<Value> _parser = new pb::MessageParser<Value>(() => new Value());
+    public static pb::MessageParser<Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Value(Value other) : this() {
+      switch (other.KindCase) {
+        case KindOneofCase.NullValue:
+          NullValue = other.NullValue;
+          break;
+        case KindOneofCase.NumberValue:
+          NumberValue = other.NumberValue;
+          break;
+        case KindOneofCase.StringValue:
+          StringValue = other.StringValue;
+          break;
+        case KindOneofCase.BoolValue:
+          BoolValue = other.BoolValue;
+          break;
+        case KindOneofCase.StructValue:
+          StructValue = other.StructValue.Clone();
+          break;
+        case KindOneofCase.ListValue:
+          ListValue = other.ListValue.Clone();
+          break;
+      }
+
+    }
+
+    public Value Clone() {
+      return new Value(this);
+    }
+
+    /// <summary>Field number for the "null_value" field.</summary>
+    public const int NullValueFieldNumber = 1;
+    /// <summary>
+    ///  Represents a null value.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.NullValue NullValue {
+      get { return kindCase_ == KindOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : global::Google.Protobuf.WellKnownTypes.NullValue.NULL_VALUE; }
+      set {
+        kind_ = value;
+        kindCase_ = KindOneofCase.NullValue;
+      }
+    }
+
+    /// <summary>Field number for the "number_value" field.</summary>
+    public const int NumberValueFieldNumber = 2;
+    /// <summary>
+    ///  Represents a double value.
+    /// </summary>
+    public double NumberValue {
+      get { return kindCase_ == KindOneofCase.NumberValue ? (double) kind_ : 0D; }
+      set {
+        kind_ = value;
+        kindCase_ = KindOneofCase.NumberValue;
+      }
+    }
+
+    /// <summary>Field number for the "string_value" field.</summary>
+    public const int StringValueFieldNumber = 3;
+    /// <summary>
+    ///  Represents a string value.
+    /// </summary>
+    public string StringValue {
+      get { return kindCase_ == KindOneofCase.StringValue ? (string) kind_ : ""; }
+      set {
+        kind_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        kindCase_ = KindOneofCase.StringValue;
+      }
+    }
+
+    /// <summary>Field number for the "bool_value" field.</summary>
+    public const int BoolValueFieldNumber = 4;
+    /// <summary>
+    ///  Represents a boolean value.
+    /// </summary>
+    public bool BoolValue {
+      get { return kindCase_ == KindOneofCase.BoolValue ? (bool) kind_ : false; }
+      set {
+        kind_ = value;
+        kindCase_ = KindOneofCase.BoolValue;
+      }
+    }
+
+    /// <summary>Field number for the "struct_value" field.</summary>
+    public const int StructValueFieldNumber = 5;
+    /// <summary>
+    ///  Represents a structured value.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Struct StructValue {
+      get { return kindCase_ == KindOneofCase.StructValue ? (global::Google.Protobuf.WellKnownTypes.Struct) kind_ : null; }
+      set {
+        kind_ = value;
+        kindCase_ = value == null ? KindOneofCase.None : KindOneofCase.StructValue;
+      }
+    }
+
+    /// <summary>Field number for the "list_value" field.</summary>
+    public const int ListValueFieldNumber = 6;
+    /// <summary>
+    ///  Represents a repeated `Value`.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.ListValue ListValue {
+      get { return kindCase_ == KindOneofCase.ListValue ? (global::Google.Protobuf.WellKnownTypes.ListValue) kind_ : null; }
+      set {
+        kind_ = value;
+        kindCase_ = value == null ? KindOneofCase.None : KindOneofCase.ListValue;
+      }
+    }
+
+    private object kind_;
+    /// <summary>Enum of possible cases for the "kind" oneof.</summary>
+    public enum KindOneofCase {
+      None = 0,
+      NullValue = 1,
+      NumberValue = 2,
+      StringValue = 3,
+      BoolValue = 4,
+      StructValue = 5,
+      ListValue = 6,
+    }
+    private KindOneofCase kindCase_ = KindOneofCase.None;
+    public KindOneofCase KindCase {
+      get { return kindCase_; }
+    }
+
+    public void ClearKind() {
+      kindCase_ = KindOneofCase.None;
+      kind_ = null;
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Value);
+    }
+
+    public bool Equals(Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (NullValue != other.NullValue) return false;
+      if (NumberValue != other.NumberValue) return false;
+      if (StringValue != other.StringValue) return false;
+      if (BoolValue != other.BoolValue) return false;
+      if (!object.Equals(StructValue, other.StructValue)) return false;
+      if (!object.Equals(ListValue, other.ListValue)) return false;
+      if (KindCase != other.KindCase) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (kindCase_ == KindOneofCase.NullValue) hash ^= NullValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.NumberValue) hash ^= NumberValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.StringValue) hash ^= StringValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.BoolValue) hash ^= BoolValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.StructValue) hash ^= StructValue.GetHashCode();
+      if (kindCase_ == KindOneofCase.ListValue) hash ^= ListValue.GetHashCode();
+      hash ^= (int) kindCase_;
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (kindCase_ == KindOneofCase.NullValue) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) NullValue);
+      }
+      if (kindCase_ == KindOneofCase.NumberValue) {
+        output.WriteRawTag(17);
+        output.WriteDouble(NumberValue);
+      }
+      if (kindCase_ == KindOneofCase.StringValue) {
+        output.WriteRawTag(26);
+        output.WriteString(StringValue);
+      }
+      if (kindCase_ == KindOneofCase.BoolValue) {
+        output.WriteRawTag(32);
+        output.WriteBool(BoolValue);
+      }
+      if (kindCase_ == KindOneofCase.StructValue) {
+        output.WriteRawTag(42);
+        output.WriteMessage(StructValue);
+      }
+      if (kindCase_ == KindOneofCase.ListValue) {
+        output.WriteRawTag(50);
+        output.WriteMessage(ListValue);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (kindCase_ == KindOneofCase.NullValue) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) NullValue);
+      }
+      if (kindCase_ == KindOneofCase.NumberValue) {
+        size += 1 + 8;
+      }
+      if (kindCase_ == KindOneofCase.StringValue) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
+      }
+      if (kindCase_ == KindOneofCase.BoolValue) {
+        size += 1 + 1;
+      }
+      if (kindCase_ == KindOneofCase.StructValue) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(StructValue);
+      }
+      if (kindCase_ == KindOneofCase.ListValue) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(ListValue);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Value other) {
+      if (other == null) {
+        return;
+      }
+      switch (other.KindCase) {
+        case KindOneofCase.NullValue:
+          NullValue = other.NullValue;
+          break;
+        case KindOneofCase.NumberValue:
+          NumberValue = other.NumberValue;
+          break;
+        case KindOneofCase.StringValue:
+          StringValue = other.StringValue;
+          break;
+        case KindOneofCase.BoolValue:
+          BoolValue = other.BoolValue;
+          break;
+        case KindOneofCase.StructValue:
+          StructValue = other.StructValue;
+          break;
+        case KindOneofCase.ListValue:
+          ListValue = other.ListValue;
+          break;
+      }
+
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            kind_ = input.ReadEnum();
+            kindCase_ = KindOneofCase.NullValue;
+            break;
+          }
+          case 17: {
+            NumberValue = input.ReadDouble();
+            break;
+          }
+          case 26: {
+            StringValue = input.ReadString();
+            break;
+          }
+          case 32: {
+            BoolValue = input.ReadBool();
+            break;
+          }
+          case 42: {
+            global::Google.Protobuf.WellKnownTypes.Struct subBuilder = new global::Google.Protobuf.WellKnownTypes.Struct();
+            if (kindCase_ == KindOneofCase.StructValue) {
+              subBuilder.MergeFrom(StructValue);
+            }
+            input.ReadMessage(subBuilder);
+            StructValue = subBuilder;
+            break;
+          }
+          case 50: {
+            global::Google.Protobuf.WellKnownTypes.ListValue subBuilder = new global::Google.Protobuf.WellKnownTypes.ListValue();
+            if (kindCase_ == KindOneofCase.ListValue) {
+              subBuilder.MergeFrom(ListValue);
+            }
+            input.ReadMessage(subBuilder);
+            ListValue = subBuilder;
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  `ListValue` is a wrapper around a repeated field of values.
+  ///
+  ///  The JSON representation for `ListValue` is JSON array.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class ListValue : pb::IMessage<ListValue> {
+    private static readonly pb::MessageParser<ListValue> _parser = new pb::MessageParser<ListValue>(() => new ListValue());
+    public static pb::MessageParser<ListValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public ListValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public ListValue(ListValue other) : this() {
+      values_ = other.values_.Clone();
+    }
+
+    public ListValue Clone() {
+      return new ListValue(this);
+    }
+
+    /// <summary>Field number for the "values" field.</summary>
+    public const int ValuesFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Value> _repeated_values_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Value.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> values_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value>();
+    /// <summary>
+    ///  Repeated field of dynamically typed values.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> Values {
+      get { return values_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as ListValue);
+    }
+
+    public bool Equals(ListValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!values_.Equals(other.values_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= values_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      values_.WriteTo(output, _repeated_values_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += values_.CalculateSize(_repeated_values_codec);
+      return size;
+    }
+
+    public void MergeFrom(ListValue other) {
+      if (other == null) {
+        return;
+      }
+      values_.Add(other.values_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            values_.AddEntriesFrom(input, _repeated_values_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs b/csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs
new file mode 100644
index 0000000..dd485d3
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs
@@ -0,0 +1,80 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    /// <summary>
+    /// Extension methods on BCL time-related types, converting to protobuf types.
+    /// </summary>
+    public static class TimeExtensions
+    {
+        /// <summary>
+        /// Converts the given <see cref="DateTime"/> to a <see cref="Timestamp"/>.
+        /// </summary>
+        /// <param name="dateTime">The date and time to convert to a timestamp.</param>
+        /// <exception cref="ArgumentException">The <paramref name="dateTime"/> value has a <see cref="DateTime.Kind"/>other than <c>Utc</c>.</exception>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp ToTimestamp(this DateTime dateTime)
+        {
+            return Timestamp.FromDateTime(dateTime);
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
+        /// </summary>
+        /// <remarks>The offset is taken into consideration when converting the value (so the same instant in time
+        /// is represented) but is not a separate part of the resulting value. In other words, there is no
+        /// roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
+        /// <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp ToTimestamp(this DateTimeOffset dateTimeOffset)
+        {
+            return Timestamp.FromDateTimeOffset(dateTimeOffset);
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
+        /// </summary>
+        /// <param name="timeSpan">The time span to convert.</param>
+        /// <returns>The converted duration.</returns>
+        public static Duration ToDuration(this TimeSpan timeSpan)
+        {
+            return Duration.FromTimeSpan(timeSpan);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
new file mode 100644
index 0000000..318b0f6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
@@ -0,0 +1,240 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/timestamp.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/timestamp.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class TimestampReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/timestamp.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static TimestampReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv",
+            "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY",
+            "AiABKAVCVAoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q",
+            "AaABAfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBl",
+            "c2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Timestamp), global::Google.Protobuf.WellKnownTypes.Timestamp.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  A Timestamp represents a point in time independent of any time zone
+  ///  or calendar, represented as seconds and fractions of seconds at
+  ///  nanosecond resolution in UTC Epoch time. It is encoded using the
+  ///  Proleptic Gregorian Calendar which extends the Gregorian calendar
+  ///  backwards to year one. It is encoded assuming all minutes are 60
+  ///  seconds long, i.e. leap seconds are "smeared" so that no leap second
+  ///  table is needed for interpretation. Range is from
+  ///  0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
+  ///  By restricting to that range, we ensure that we can convert to
+  ///  and from  RFC 3339 date strings.
+  ///  See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
+  ///
+  ///  Example 1: Compute Timestamp from POSIX `time()`.
+  ///
+  ///      Timestamp timestamp;
+  ///      timestamp.set_seconds(time(NULL));
+  ///      timestamp.set_nanos(0);
+  ///
+  ///  Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+  ///
+  ///      struct timeval tv;
+  ///      gettimeofday(&amp;tv, NULL);
+  ///
+  ///      Timestamp timestamp;
+  ///      timestamp.set_seconds(tv.tv_sec);
+  ///      timestamp.set_nanos(tv.tv_usec * 1000);
+  ///
+  ///  Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+  ///
+  ///      FILETIME ft;
+  ///      GetSystemTimeAsFileTime(&amp;ft);
+  ///      UINT64 ticks = (((UINT64)ft.dwHighDateTime) &lt;&lt; 32) | ft.dwLowDateTime;
+  ///
+  ///      // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+  ///      // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+  ///      Timestamp timestamp;
+  ///      timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+  ///      timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+  ///
+  ///  Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+  ///
+  ///      long millis = System.currentTimeMillis();
+  ///
+  ///      Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+  ///          .setNanos((int) ((millis % 1000) * 1000000)).build();
+  ///
+  ///  Example 5: Compute Timestamp from current time in Python.
+  ///
+  ///      now = time.time()
+  ///      seconds = int(now)
+  ///      nanos = int((now - seconds) * 10**9)
+  ///      timestamp = Timestamp(seconds=seconds, nanos=nanos)
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Timestamp : pb::IMessage<Timestamp> {
+    private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());
+    public static pb::MessageParser<Timestamp> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Timestamp() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Timestamp(Timestamp other) : this() {
+      seconds_ = other.seconds_;
+      nanos_ = other.nanos_;
+    }
+
+    public Timestamp Clone() {
+      return new Timestamp(this);
+    }
+
+    /// <summary>Field number for the "seconds" field.</summary>
+    public const int SecondsFieldNumber = 1;
+    private long seconds_;
+    /// <summary>
+    ///  Represents seconds of UTC time since Unix epoch
+    ///  1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+    ///  9999-12-31T23:59:59Z inclusive.
+    /// </summary>
+    public long Seconds {
+      get { return seconds_; }
+      set {
+        seconds_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "nanos" field.</summary>
+    public const int NanosFieldNumber = 2;
+    private int nanos_;
+    /// <summary>
+    ///  Non-negative fractions of a second at nanosecond resolution. Negative
+    ///  second values with fractions must still have non-negative nanos values
+    ///  that count forward in time. Must be from 0 to 999,999,999
+    ///  inclusive.
+    /// </summary>
+    public int Nanos {
+      get { return nanos_; }
+      set {
+        nanos_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Timestamp);
+    }
+
+    public bool Equals(Timestamp other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Seconds != other.Seconds) return false;
+      if (Nanos != other.Nanos) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Seconds != 0L) hash ^= Seconds.GetHashCode();
+      if (Nanos != 0) hash ^= Nanos.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Seconds != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Seconds);
+      }
+      if (Nanos != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Nanos);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Seconds != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Seconds);
+      }
+      if (Nanos != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Timestamp other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Seconds != 0L) {
+        Seconds = other.Seconds;
+      }
+      if (other.Nanos != 0) {
+        Nanos = other.Nanos;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Seconds = input.ReadInt64();
+            break;
+          }
+          case 16: {
+            Nanos = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
new file mode 100644
index 0000000..aa40347
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
@@ -0,0 +1,241 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Globalization;
+using System.Text;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public partial class Timestamp : ICustomDiagnosticMessage
+    {
+        private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+        // Constants determined programmatically, but then hard-coded so they can be constant expressions.
+        private const long BclSecondsAtUnixEpoch = 62135596800;
+        internal const long UnixSecondsAtBclMaxValue = 253402300799;
+        internal const long UnixSecondsAtBclMinValue = -BclSecondsAtUnixEpoch;
+        internal const int MaxNanos = Duration.NanosecondsPerSecond - 1;
+
+        private static bool IsNormalized(long seconds, int nanoseconds) =>
+            nanoseconds >= 0 &&
+            nanoseconds <= MaxNanos &&
+            seconds >= UnixSecondsAtBclMinValue &&
+            seconds <= UnixSecondsAtBclMaxValue;
+
+        /// <summary>
+        /// Returns the difference between one <see cref="Timestamp"/> and another, as a <see cref="Duration"/>.
+        /// </summary>
+        /// <param name="lhs">The timestamp to subtract from. Must not be null.</param>
+        /// <param name="rhs">The timestamp to subtract. Must not be null.</param>
+        /// <returns>The difference between the two specified timestamps.</returns>
+        public static Duration operator -(Timestamp lhs, Timestamp rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Duration.Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Adds a <see cref="Duration"/> to a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
+        /// </summary>
+        /// <param name="lhs">The timestamp to add the duration to. Must not be null.</param>
+        /// <param name="rhs">The duration to add. Must not be null.</param>
+        /// <returns>The result of adding the duration to the timestamp.</returns>
+        public static Timestamp operator +(Timestamp lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Subtracts a <see cref="Duration"/> from a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
+        /// </summary>
+        /// <param name="lhs">The timestamp to subtract the duration from. Must not be null.</param>
+        /// <param name="rhs">The duration to subtract.</param>
+        /// <returns>The result of subtracting the duration from the timestamp.</returns>
+        public static Timestamp operator -(Timestamp lhs, Duration rhs)
+        {
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
+            checked
+            {
+                return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
+            }
+        }
+
+        /// <summary>
+        /// Converts this timestamp into a <see cref="DateTime"/>.
+        /// </summary>
+        /// <remarks>
+        /// The resulting <c>DateTime</c> will always have a <c>Kind</c> of <c>Utc</c>.
+        /// If the timestamp is not a precise number of ticks, it will be truncated towards the start
+        /// of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
+        /// <see cref="DateTime"/> value precisely on a second.
+        /// </remarks>
+        /// <returns>This timestamp as a <c>DateTime</c>.</returns>
+        /// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
+        /// incorrectly normalized or is outside the valid range.</exception>
+        public DateTime ToDateTime()
+        {
+            if (!IsNormalized(Seconds, Nanos))
+            {
+                throw new InvalidOperationException(@"Timestamp contains invalid values: Seconds={Seconds}; Nanos={Nanos}");
+            }
+            return UnixEpoch.AddSeconds(Seconds).AddTicks(Nanos / Duration.NanosecondsPerTick);
+        }
+
+        /// <summary>
+        /// Converts this timestamp into a <see cref="DateTimeOffset"/>.
+        /// </summary>
+        /// <remarks>
+        /// The resulting <c>DateTimeOffset</c> will always have an <c>Offset</c> of zero.
+        /// If the timestamp is not a precise number of ticks, it will be truncated towards the start
+        /// of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
+        /// <see cref="DateTimeOffset"/> value precisely on a second.
+        /// </remarks>
+        /// <returns>This timestamp as a <c>DateTimeOffset</c>.</returns>
+        /// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
+        /// incorrectly normalized or is outside the valid range.</exception>
+        public DateTimeOffset ToDateTimeOffset()
+        {
+            return new DateTimeOffset(ToDateTime(), TimeSpan.Zero);
+        }
+
+        /// <summary>
+        /// Converts the specified <see cref="DateTime"/> to a <see cref="Timestamp"/>.
+        /// </summary>
+        /// <param name="dateTime"></param>
+        /// <exception cref="ArgumentException">The <c>Kind</c> of <paramref name="dateTime"/> is not <c>DateTimeKind.Utc</c>.</exception>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp FromDateTime(DateTime dateTime)
+        {
+            if (dateTime.Kind != DateTimeKind.Utc)
+            {
+                throw new ArgumentException("Conversion from DateTime to Timestamp requires the DateTime kind to be Utc", "dateTime");
+            }
+            // Do the arithmetic using DateTime.Ticks, which is always non-negative, making things simpler.
+            long secondsSinceBclEpoch = dateTime.Ticks / TimeSpan.TicksPerSecond;
+            int nanoseconds = (int)  (dateTime.Ticks % TimeSpan.TicksPerSecond) * Duration.NanosecondsPerTick;
+            return new Timestamp { Seconds = secondsSinceBclEpoch - BclSecondsAtUnixEpoch, Nanos = nanoseconds };
+        }
+
+        /// <summary>
+        /// Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
+        /// </summary>
+        /// <remarks>The offset is taken into consideration when converting the value (so the same instant in time
+        /// is represented) but is not a separate part of the resulting value. In other words, there is no
+        /// roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
+        /// <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
+        /// <returns>The converted timestamp.</returns>
+        public static Timestamp FromDateTimeOffset(DateTimeOffset dateTimeOffset)
+        {
+            // We don't need to worry about this having negative ticks: DateTimeOffset is constrained to handle
+            // values whose *UTC* value is in the range of DateTime.
+            return FromDateTime(dateTimeOffset.UtcDateTime);
+        }
+
+        internal static Timestamp Normalize(long seconds, int nanoseconds)
+        {
+            int extraSeconds = nanoseconds / Duration.NanosecondsPerSecond;
+            seconds += extraSeconds;
+            nanoseconds -= extraSeconds * Duration.NanosecondsPerSecond;
+
+            if (nanoseconds < 0)
+            {
+                nanoseconds += Duration.NanosecondsPerSecond;
+                seconds--;
+            }
+            return new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+        }
+
+        /// <summary>
+        /// Converts a timestamp specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>timestamp.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="seconds">Seconds portion of the duration.</param>
+        /// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
+        {
+            if (IsNormalized(seconds, nanoseconds))
+            {
+                // Use .NET's formatting for the value down to the second, including an opening double quote (as it's a string value)
+                DateTime dateTime = UnixEpoch.AddSeconds(seconds);
+                var builder = new StringBuilder();
+                builder.Append('"');
+                builder.Append(dateTime.ToString("yyyy'-'MM'-'dd'T'HH:mm:ss", CultureInfo.InvariantCulture));
+                Duration.AppendNanoseconds(builder, nanoseconds);
+                builder.Append("Z\"");
+                return builder.ToString();
+            }
+            if (diagnosticOnly)
+            {
+                return string.Format(CultureInfo.InvariantCulture,
+                    "{{ \"@warning\": \"Invalid Timestamp\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
+                    seconds,
+                    nanoseconds);
+            }
+            else
+            {
+                throw new InvalidOperationException("Non-normalized timestamp value");
+            }
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="Timestamp"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Seconds, Nanos, true);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
new file mode 100644
index 0000000..8faa1d1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
@@ -0,0 +1,1347 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/type.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class TypeReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/type.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static TypeReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxIPZ29vZ2xlLnByb3RvYnVm",
+            "Ghlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvGiRnb29nbGUvcHJvdG9idWYv",
+            "c291cmNlX2NvbnRleHQucHJvdG8i1wEKBFR5cGUSDAoEbmFtZRgBIAEoCRIm",
+            "CgZmaWVsZHMYAiADKAsyFi5nb29nbGUucHJvdG9idWYuRmllbGQSDgoGb25l",
+            "b2ZzGAMgAygJEigKB29wdGlvbnMYBCADKAsyFy5nb29nbGUucHJvdG9idWYu",
+            "T3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAUgASgLMh4uZ29vZ2xlLnByb3Rv",
+            "YnVmLlNvdXJjZUNvbnRleHQSJwoGc3ludGF4GAYgASgOMhcuZ29vZ2xlLnBy",
+            "b3RvYnVmLlN5bnRheCLVBQoFRmllbGQSKQoEa2luZBgBIAEoDjIbLmdvb2ds",
+            "ZS5wcm90b2J1Zi5GaWVsZC5LaW5kEjcKC2NhcmRpbmFsaXR5GAIgASgOMiIu",
+            "Z29vZ2xlLnByb3RvYnVmLkZpZWxkLkNhcmRpbmFsaXR5Eg4KBm51bWJlchgD",
+            "IAEoBRIMCgRuYW1lGAQgASgJEhAKCHR5cGVfdXJsGAYgASgJEhMKC29uZW9m",
+            "X2luZGV4GAcgASgFEg4KBnBhY2tlZBgIIAEoCBIoCgdvcHRpb25zGAkgAygL",
+            "MhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhIRCglqc29uX25hbWUYCiABKAkS",
+            "FQoNZGVmYXVsdF92YWx1ZRgLIAEoCSLIAgoES2luZBIQCgxUWVBFX1VOS05P",
+            "V04QABIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBF",
+            "X0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoM",
+            "VFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09M",
+            "EAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9N",
+            "RVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJ",
+            "VFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVE",
+            "NjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIidAoLQ2Fy",
+            "ZGluYWxpdHkSFwoTQ0FSRElOQUxJVFlfVU5LTk9XThAAEhgKFENBUkRJTkFM",
+            "SVRZX09QVElPTkFMEAESGAoUQ0FSRElOQUxJVFlfUkVRVUlSRUQQAhIYChRD",
+            "QVJESU5BTElUWV9SRVBFQVRFRBADIs4BCgRFbnVtEgwKBG5hbWUYASABKAkS",
+            "LQoJZW51bXZhbHVlGAIgAygLMhouZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1",
+            "ZRIoCgdvcHRpb25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhI2",
+            "Cg5zb3VyY2VfY29udGV4dBgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5Tb3Vy",
+            "Y2VDb250ZXh0EicKBnN5bnRheBgFIAEoDjIXLmdvb2dsZS5wcm90b2J1Zi5T",
+            "eW50YXgiUwoJRW51bVZhbHVlEgwKBG5hbWUYASABKAkSDgoGbnVtYmVyGAIg",
+            "ASgFEigKB29wdGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9u",
+            "IjsKBk9wdGlvbhIMCgRuYW1lGAEgASgJEiMKBXZhbHVlGAIgASgLMhQuZ29v",
+            "Z2xlLnByb3RvYnVmLkFueSouCgZTeW50YXgSEQoNU1lOVEFYX1BST1RPMhAA",
+            "EhEKDVNZTlRBWF9QUk9UTzMQAUJMChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
+            "eXBlUHJvdG9QAaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25v",
+            "d25UeXBlc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Field), global::Google.Protobuf.WellKnownTypes.Field.Parser, new[]{ "Kind", "Cardinality", "Number", "Name", "TypeUrl", "OneofIndex", "Packed", "Options", "JsonName", "DefaultValue" }, null, new[]{ typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Kind), typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), global::Google.Protobuf.WellKnownTypes.Enum.Parser, new[]{ "Name", "Enumvalue", "Options", "SourceContext", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.EnumValue), global::Google.Protobuf.WellKnownTypes.EnumValue.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Option), global::Google.Protobuf.WellKnownTypes.Option.Parser, new[]{ "Name", "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Enums
+  /// <summary>
+  ///  The syntax in which a protocol buffer element is defined.
+  /// </summary>
+  public enum Syntax {
+    /// <summary>
+    ///  Syntax `proto2`.
+    /// </summary>
+    SYNTAX_PROTO2 = 0,
+    /// <summary>
+    ///  Syntax `proto3`.
+    /// </summary>
+    SYNTAX_PROTO3 = 1,
+  }
+
+  #endregion
+
+  #region Messages
+  /// <summary>
+  ///  A protocol buffer message type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Type : pb::IMessage<Type> {
+    private static readonly pb::MessageParser<Type> _parser = new pb::MessageParser<Type>(() => new Type());
+    public static pb::MessageParser<Type> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Type() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Type(Type other) : this() {
+      name_ = other.name_;
+      fields_ = other.fields_.Clone();
+      oneofs_ = other.oneofs_.Clone();
+      options_ = other.options_.Clone();
+      SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      syntax_ = other.syntax_;
+    }
+
+    public Type Clone() {
+      return new Type(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The fully qualified message name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "fields" field.</summary>
+    public const int FieldsFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Field> _repeated_fields_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Field.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field> fields_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field>();
+    /// <summary>
+    ///  The list of fields.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field> Fields {
+      get { return fields_; }
+    }
+
+    /// <summary>Field number for the "oneofs" field.</summary>
+    public const int OneofsFieldNumber = 3;
+    private static readonly pb::FieldCodec<string> _repeated_oneofs_codec
+        = pb::FieldCodec.ForString(26);
+    private readonly pbc::RepeatedField<string> oneofs_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  The list of types appearing in `oneof` definitions in this type.
+    /// </summary>
+    public pbc::RepeatedField<string> Oneofs {
+      get { return oneofs_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 4;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  The protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "source_context" field.</summary>
+    public const int SourceContextFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  The source context.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
+      get { return sourceContext_; }
+      set {
+        sourceContext_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 6;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Type);
+    }
+
+    public bool Equals(Type other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!fields_.Equals(other.fields_)) return false;
+      if(!oneofs_.Equals(other.oneofs_)) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= fields_.GetHashCode();
+      hash ^= oneofs_.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      fields_.WriteTo(output, _repeated_fields_codec);
+      oneofs_.WriteTo(output, _repeated_oneofs_codec);
+      options_.WriteTo(output, _repeated_options_codec);
+      if (sourceContext_ != null) {
+        output.WriteRawTag(42);
+        output.WriteMessage(SourceContext);
+      }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(48);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += fields_.CalculateSize(_repeated_fields_codec);
+      size += oneofs_.CalculateSize(_repeated_oneofs_codec);
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (sourceContext_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
+      }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Type other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      fields_.Add(other.fields_);
+      oneofs_.Add(other.oneofs_);
+      options_.Add(other.options_);
+      if (other.sourceContext_ != null) {
+        if (sourceContext_ == null) {
+          sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+        }
+        SourceContext.MergeFrom(other.SourceContext);
+      }
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            fields_.AddEntriesFrom(input, _repeated_fields_codec);
+            break;
+          }
+          case 26: {
+            oneofs_.AddEntriesFrom(input, _repeated_oneofs_codec);
+            break;
+          }
+          case 34: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 42: {
+            if (sourceContext_ == null) {
+              sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            }
+            input.ReadMessage(sourceContext_);
+            break;
+          }
+          case 48: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A single field of a message type.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Field : pb::IMessage<Field> {
+    private static readonly pb::MessageParser<Field> _parser = new pb::MessageParser<Field>(() => new Field());
+    public static pb::MessageParser<Field> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Field() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Field(Field other) : this() {
+      kind_ = other.kind_;
+      cardinality_ = other.cardinality_;
+      number_ = other.number_;
+      name_ = other.name_;
+      typeUrl_ = other.typeUrl_;
+      oneofIndex_ = other.oneofIndex_;
+      packed_ = other.packed_;
+      options_ = other.options_.Clone();
+      jsonName_ = other.jsonName_;
+      defaultValue_ = other.defaultValue_;
+    }
+
+    public Field Clone() {
+      return new Field(this);
+    }
+
+    /// <summary>Field number for the "kind" field.</summary>
+    public const int KindFieldNumber = 1;
+    private global::Google.Protobuf.WellKnownTypes.Field.Types.Kind kind_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN;
+    /// <summary>
+    ///  The field type.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Field.Types.Kind Kind {
+      get { return kind_; }
+      set {
+        kind_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "cardinality" field.</summary>
+    public const int CardinalityFieldNumber = 2;
+    private global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality cardinality_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN;
+    /// <summary>
+    ///  The field cardinality.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality Cardinality {
+      get { return cardinality_; }
+      set {
+        cardinality_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 3;
+    private int number_;
+    /// <summary>
+    ///  The field number.
+    /// </summary>
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 4;
+    private string name_ = "";
+    /// <summary>
+    ///  The field name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "type_url" field.</summary>
+    public const int TypeUrlFieldNumber = 6;
+    private string typeUrl_ = "";
+    /// <summary>
+    ///  The field type URL, without the scheme, for message or enumeration
+    ///  types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
+    /// </summary>
+    public string TypeUrl {
+      get { return typeUrl_; }
+      set {
+        typeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "oneof_index" field.</summary>
+    public const int OneofIndexFieldNumber = 7;
+    private int oneofIndex_;
+    /// <summary>
+    ///  The index of the field type in `Type.oneofs`, for message or enumeration
+    ///  types. The first type has index 1; zero means the type is not in the list.
+    /// </summary>
+    public int OneofIndex {
+      get { return oneofIndex_; }
+      set {
+        oneofIndex_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "packed" field.</summary>
+    public const int PackedFieldNumber = 8;
+    private bool packed_;
+    /// <summary>
+    ///  Whether to use alternative packed wire representation.
+    /// </summary>
+    public bool Packed {
+      get { return packed_; }
+      set {
+        packed_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 9;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  The protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "json_name" field.</summary>
+    public const int JsonNameFieldNumber = 10;
+    private string jsonName_ = "";
+    /// <summary>
+    ///  The field JSON name.
+    /// </summary>
+    public string JsonName {
+      get { return jsonName_; }
+      set {
+        jsonName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "default_value" field.</summary>
+    public const int DefaultValueFieldNumber = 11;
+    private string defaultValue_ = "";
+    /// <summary>
+    ///  The string value of the default value of this field. Proto2 syntax only.
+    /// </summary>
+    public string DefaultValue {
+      get { return defaultValue_; }
+      set {
+        defaultValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Field);
+    }
+
+    public bool Equals(Field other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Kind != other.Kind) return false;
+      if (Cardinality != other.Cardinality) return false;
+      if (Number != other.Number) return false;
+      if (Name != other.Name) return false;
+      if (TypeUrl != other.TypeUrl) return false;
+      if (OneofIndex != other.OneofIndex) return false;
+      if (Packed != other.Packed) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (JsonName != other.JsonName) return false;
+      if (DefaultValue != other.DefaultValue) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) hash ^= Kind.GetHashCode();
+      if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) hash ^= Cardinality.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (TypeUrl.Length != 0) hash ^= TypeUrl.GetHashCode();
+      if (OneofIndex != 0) hash ^= OneofIndex.GetHashCode();
+      if (Packed != false) hash ^= Packed.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (JsonName.Length != 0) hash ^= JsonName.GetHashCode();
+      if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) {
+        output.WriteRawTag(8);
+        output.WriteEnum((int) Kind);
+      }
+      if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) {
+        output.WriteRawTag(16);
+        output.WriteEnum((int) Cardinality);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(24);
+        output.WriteInt32(Number);
+      }
+      if (Name.Length != 0) {
+        output.WriteRawTag(34);
+        output.WriteString(Name);
+      }
+      if (TypeUrl.Length != 0) {
+        output.WriteRawTag(50);
+        output.WriteString(TypeUrl);
+      }
+      if (OneofIndex != 0) {
+        output.WriteRawTag(56);
+        output.WriteInt32(OneofIndex);
+      }
+      if (Packed != false) {
+        output.WriteRawTag(64);
+        output.WriteBool(Packed);
+      }
+      options_.WriteTo(output, _repeated_options_codec);
+      if (JsonName.Length != 0) {
+        output.WriteRawTag(82);
+        output.WriteString(JsonName);
+      }
+      if (DefaultValue.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(DefaultValue);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Kind);
+      }
+      if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Cardinality);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (TypeUrl.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeUrl);
+      }
+      if (OneofIndex != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(OneofIndex);
+      }
+      if (Packed != false) {
+        size += 1 + 1;
+      }
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (JsonName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName);
+      }
+      if (DefaultValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(DefaultValue);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Field other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) {
+        Kind = other.Kind;
+      }
+      if (other.Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) {
+        Cardinality = other.Cardinality;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.TypeUrl.Length != 0) {
+        TypeUrl = other.TypeUrl;
+      }
+      if (other.OneofIndex != 0) {
+        OneofIndex = other.OneofIndex;
+      }
+      if (other.Packed != false) {
+        Packed = other.Packed;
+      }
+      options_.Add(other.options_);
+      if (other.JsonName.Length != 0) {
+        JsonName = other.JsonName;
+      }
+      if (other.DefaultValue.Length != 0) {
+        DefaultValue = other.DefaultValue;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            kind_ = (global::Google.Protobuf.WellKnownTypes.Field.Types.Kind) input.ReadEnum();
+            break;
+          }
+          case 16: {
+            cardinality_ = (global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) input.ReadEnum();
+            break;
+          }
+          case 24: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 34: {
+            Name = input.ReadString();
+            break;
+          }
+          case 50: {
+            TypeUrl = input.ReadString();
+            break;
+          }
+          case 56: {
+            OneofIndex = input.ReadInt32();
+            break;
+          }
+          case 64: {
+            Packed = input.ReadBool();
+            break;
+          }
+          case 74: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 82: {
+            JsonName = input.ReadString();
+            break;
+          }
+          case 90: {
+            DefaultValue = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the Field message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      /// <summary>
+      ///  Basic field types.
+      /// </summary>
+      public enum Kind {
+        /// <summary>
+        ///  Field type unknown.
+        /// </summary>
+        TYPE_UNKNOWN = 0,
+        /// <summary>
+        ///  Field type double.
+        /// </summary>
+        TYPE_DOUBLE = 1,
+        /// <summary>
+        ///  Field type float.
+        /// </summary>
+        TYPE_FLOAT = 2,
+        /// <summary>
+        ///  Field type int64.
+        /// </summary>
+        TYPE_INT64 = 3,
+        /// <summary>
+        ///  Field type uint64.
+        /// </summary>
+        TYPE_UINT64 = 4,
+        /// <summary>
+        ///  Field type int32.
+        /// </summary>
+        TYPE_INT32 = 5,
+        /// <summary>
+        ///  Field type fixed64.
+        /// </summary>
+        TYPE_FIXED64 = 6,
+        /// <summary>
+        ///  Field type fixed32.
+        /// </summary>
+        TYPE_FIXED32 = 7,
+        /// <summary>
+        ///  Field type bool.
+        /// </summary>
+        TYPE_BOOL = 8,
+        /// <summary>
+        ///  Field type string.
+        /// </summary>
+        TYPE_STRING = 9,
+        /// <summary>
+        ///  Field type group. Proto2 syntax only, and deprecated.
+        /// </summary>
+        TYPE_GROUP = 10,
+        /// <summary>
+        ///  Field type message.
+        /// </summary>
+        TYPE_MESSAGE = 11,
+        /// <summary>
+        ///  Field type bytes.
+        /// </summary>
+        TYPE_BYTES = 12,
+        /// <summary>
+        ///  Field type uint32.
+        /// </summary>
+        TYPE_UINT32 = 13,
+        /// <summary>
+        ///  Field type enum.
+        /// </summary>
+        TYPE_ENUM = 14,
+        /// <summary>
+        ///  Field type sfixed32.
+        /// </summary>
+        TYPE_SFIXED32 = 15,
+        /// <summary>
+        ///  Field type sfixed64.
+        /// </summary>
+        TYPE_SFIXED64 = 16,
+        /// <summary>
+        ///  Field type sint32.
+        /// </summary>
+        TYPE_SINT32 = 17,
+        /// <summary>
+        ///  Field type sint64.
+        /// </summary>
+        TYPE_SINT64 = 18,
+      }
+
+      /// <summary>
+      ///  Whether a field is optional, required, or repeated.
+      /// </summary>
+      public enum Cardinality {
+        /// <summary>
+        ///  For fields with unknown cardinality.
+        /// </summary>
+        CARDINALITY_UNKNOWN = 0,
+        /// <summary>
+        ///  For optional fields.
+        /// </summary>
+        CARDINALITY_OPTIONAL = 1,
+        /// <summary>
+        ///  For required fields. Proto2 syntax only.
+        /// </summary>
+        CARDINALITY_REQUIRED = 2,
+        /// <summary>
+        ///  For repeated fields.
+        /// </summary>
+        CARDINALITY_REPEATED = 3,
+      }
+
+    }
+    #endregion
+
+  }
+
+  /// <summary>
+  ///  Enum type definition.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Enum : pb::IMessage<Enum> {
+    private static readonly pb::MessageParser<Enum> _parser = new pb::MessageParser<Enum>(() => new Enum());
+    public static pb::MessageParser<Enum> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Enum() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Enum(Enum other) : this() {
+      name_ = other.name_;
+      enumvalue_ = other.enumvalue_.Clone();
+      options_ = other.options_.Clone();
+      SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      syntax_ = other.syntax_;
+    }
+
+    public Enum Clone() {
+      return new Enum(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  Enum type name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "enumvalue" field.</summary>
+    public const int EnumvalueFieldNumber = 2;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.EnumValue> _repeated_enumvalue_codec
+        = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.EnumValue.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue> enumvalue_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue>();
+    /// <summary>
+    ///  Enum value definitions.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue> Enumvalue {
+      get { return enumvalue_; }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    /// <summary>Field number for the "source_context" field.</summary>
+    public const int SourceContextFieldNumber = 4;
+    private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  The source context.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
+      get { return sourceContext_; }
+      set {
+        sourceContext_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Enum);
+    }
+
+    public bool Equals(Enum other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if(!enumvalue_.Equals(other.enumvalue_)) return false;
+      if(!options_.Equals(other.options_)) return false;
+      if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if (Syntax != other.Syntax) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      hash ^= enumvalue_.GetHashCode();
+      hash ^= options_.GetHashCode();
+      if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      enumvalue_.WriteTo(output, _repeated_enumvalue_codec);
+      options_.WriteTo(output, _repeated_options_codec);
+      if (sourceContext_ != null) {
+        output.WriteRawTag(34);
+        output.WriteMessage(SourceContext);
+      }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(40);
+        output.WriteEnum((int) Syntax);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += enumvalue_.CalculateSize(_repeated_enumvalue_codec);
+      size += options_.CalculateSize(_repeated_options_codec);
+      if (sourceContext_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
+      }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Enum other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      enumvalue_.Add(other.enumvalue_);
+      options_.Add(other.options_);
+      if (other.sourceContext_ != null) {
+        if (sourceContext_ == null) {
+          sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+        }
+        SourceContext.MergeFrom(other.SourceContext);
+      }
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            enumvalue_.AddEntriesFrom(input, _repeated_enumvalue_codec);
+            break;
+          }
+          case 26: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+          case 34: {
+            if (sourceContext_ == null) {
+              sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
+            }
+            input.ReadMessage(sourceContext_);
+            break;
+          }
+          case 40: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Enum value definition.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class EnumValue : pb::IMessage<EnumValue> {
+    private static readonly pb::MessageParser<EnumValue> _parser = new pb::MessageParser<EnumValue>(() => new EnumValue());
+    public static pb::MessageParser<EnumValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public EnumValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public EnumValue(EnumValue other) : this() {
+      name_ = other.name_;
+      number_ = other.number_;
+      options_ = other.options_.Clone();
+    }
+
+    public EnumValue Clone() {
+      return new EnumValue(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  Enum value name.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "number" field.</summary>
+    public const int NumberFieldNumber = 2;
+    private int number_;
+    /// <summary>
+    ///  Enum value number.
+    /// </summary>
+    public int Number {
+      get { return number_; }
+      set {
+        number_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
+    public const int OptionsFieldNumber = 3;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
+        = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Protocol buffer options.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
+      get { return options_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as EnumValue);
+    }
+
+    public bool Equals(EnumValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Number != other.Number) return false;
+      if(!options_.Equals(other.options_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Number != 0) hash ^= Number.GetHashCode();
+      hash ^= options_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Number != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Number);
+      }
+      options_.WriteTo(output, _repeated_options_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Number != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number);
+      }
+      size += options_.CalculateSize(_repeated_options_codec);
+      return size;
+    }
+
+    public void MergeFrom(EnumValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Number != 0) {
+        Number = other.Number;
+      }
+      options_.Add(other.options_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 16: {
+            Number = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            options_.AddEntriesFrom(input, _repeated_options_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  A protocol buffer option, which can be attached to a message, field,
+  ///  enumeration, etc.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Option : pb::IMessage<Option> {
+    private static readonly pb::MessageParser<Option> _parser = new pb::MessageParser<Option>(() => new Option());
+    public static pb::MessageParser<Option> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Option() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Option(Option other) : this() {
+      name_ = other.name_;
+      Value = other.value_ != null ? other.Value.Clone() : null;
+    }
+
+    public Option Clone() {
+      return new Option(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The option's name. For example, `"java_package"`.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 2;
+    private global::Google.Protobuf.WellKnownTypes.Any value_;
+    /// <summary>
+    ///  The option's value. For example, `"com.google.protobuf"`.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Any Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Option);
+    }
+
+    public bool Equals(Option other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (!object.Equals(Value, other.Value)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (value_ != null) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (value_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (value_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Option other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.value_ != null) {
+        if (value_ == null) {
+          value_ = new global::Google.Protobuf.WellKnownTypes.Any();
+        }
+        Value.MergeFrom(other.Value);
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            if (value_ == null) {
+              value_ = new global::Google.Protobuf.WellKnownTypes.Any();
+            }
+            input.ReadMessage(value_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs
new file mode 100644
index 0000000..d34b560
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs
@@ -0,0 +1,99 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public partial class Value
+    {
+        /// <summary>
+        /// Convenience method to create a Value message with a string value.
+        /// </summary>
+        /// <param name="value">Value to set for the StringValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForString(string value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            return new Value { StringValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a number value.
+        /// </summary>
+        /// <param name="value">Value to set for the NumberValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForNumber(double value)
+        {
+            return new Value { NumberValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a Boolean value.
+        /// </summary>
+        /// <param name="value">Value to set for the BoolValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForBool(bool value)
+        {
+            return new Value { BoolValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a null initial value.
+        /// </summary>
+        /// <returns>A newly-created Value message a null initial value.</returns>
+        public static Value ForNull()
+        {
+            return new Value { NullValue = 0 };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with an initial list of values.
+        /// </summary>
+        /// <remarks>The values provided are not cloned; the references are copied directly.</remarks>
+        /// <returns>A newly-created Value message an initial list value.</returns>
+        public static Value ForList(params Value[] values)
+        {
+            ProtoPreconditions.CheckNotNull(values, "values");
+            return new Value { ListValue = new ListValue { Values = { values } } };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with an initial struct value
+        /// </summary>
+        /// <remarks>The value provided is not cloned; the reference is copied directly.</remarks>
+        /// <returns>A newly-created Value message an initial struct value.</returns>
+        public static Value ForStruct(Struct value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            return new Value { StructValue = value };
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
new file mode 100644
index 0000000..d6796d1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
@@ -0,0 +1,1057 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Google.Protobuf.WellKnownTypes {
+
+  /// <summary>Holder for reflection information generated from google/protobuf/wrappers.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class WrappersReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/wrappers.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static WrappersReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch5nb29nbGUvcHJvdG9idWYvd3JhcHBlcnMucHJvdG8SD2dvb2dsZS5wcm90",
+            "b2J1ZiIcCgtEb3VibGVWYWx1ZRINCgV2YWx1ZRgBIAEoASIbCgpGbG9hdFZh",
+            "bHVlEg0KBXZhbHVlGAEgASgCIhsKCkludDY0VmFsdWUSDQoFdmFsdWUYASAB",
+            "KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1",
+            "ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo",
+            "DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS",
+            "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJT",
+            "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQH4AQGi",
+            "AgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3Rv",
+            "Mw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.DoubleValue), global::Google.Protobuf.WellKnownTypes.DoubleValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FloatValue), global::Google.Protobuf.WellKnownTypes.FloatValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int64Value), global::Google.Protobuf.WellKnownTypes.Int64Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt64Value), global::Google.Protobuf.WellKnownTypes.UInt64Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int32Value), global::Google.Protobuf.WellKnownTypes.Int32Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt32Value), global::Google.Protobuf.WellKnownTypes.UInt32Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BoolValue), global::Google.Protobuf.WellKnownTypes.BoolValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.StringValue), global::Google.Protobuf.WellKnownTypes.StringValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BytesValue), global::Google.Protobuf.WellKnownTypes.BytesValue.Parser, new[]{ "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  Wrapper message for `double`.
+  ///
+  ///  The JSON representation for `DoubleValue` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class DoubleValue : pb::IMessage<DoubleValue> {
+    private static readonly pb::MessageParser<DoubleValue> _parser = new pb::MessageParser<DoubleValue>(() => new DoubleValue());
+    public static pb::MessageParser<DoubleValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public DoubleValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public DoubleValue(DoubleValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public DoubleValue Clone() {
+      return new DoubleValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private double value_;
+    /// <summary>
+    ///  The double value.
+    /// </summary>
+    public double Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as DoubleValue);
+    }
+
+    public bool Equals(DoubleValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0D) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0D) {
+        output.WriteRawTag(9);
+        output.WriteDouble(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(DoubleValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0D) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 9: {
+            Value = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `float`.
+  ///
+  ///  The JSON representation for `FloatValue` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class FloatValue : pb::IMessage<FloatValue> {
+    private static readonly pb::MessageParser<FloatValue> _parser = new pb::MessageParser<FloatValue>(() => new FloatValue());
+    public static pb::MessageParser<FloatValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public FloatValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public FloatValue(FloatValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public FloatValue Clone() {
+      return new FloatValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private float value_;
+    /// <summary>
+    ///  The float value.
+    /// </summary>
+    public float Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as FloatValue);
+    }
+
+    public bool Equals(FloatValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0F) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0F) {
+        output.WriteRawTag(13);
+        output.WriteFloat(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0F) {
+        size += 1 + 4;
+      }
+      return size;
+    }
+
+    public void MergeFrom(FloatValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0F) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 13: {
+            Value = input.ReadFloat();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `int64`.
+  ///
+  ///  The JSON representation for `Int64Value` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Int64Value : pb::IMessage<Int64Value> {
+    private static readonly pb::MessageParser<Int64Value> _parser = new pb::MessageParser<Int64Value>(() => new Int64Value());
+    public static pb::MessageParser<Int64Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Int64Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Int64Value(Int64Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public Int64Value Clone() {
+      return new Int64Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private long value_;
+    /// <summary>
+    ///  The int64 value.
+    /// </summary>
+    public long Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Int64Value);
+    }
+
+    public bool Equals(Int64Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0L) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0L) {
+        output.WriteRawTag(8);
+        output.WriteInt64(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0L) {
+        size += 1 + pb::CodedOutputStream.ComputeInt64Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Int64Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0L) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `uint64`.
+  ///
+  ///  The JSON representation for `UInt64Value` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class UInt64Value : pb::IMessage<UInt64Value> {
+    private static readonly pb::MessageParser<UInt64Value> _parser = new pb::MessageParser<UInt64Value>(() => new UInt64Value());
+    public static pb::MessageParser<UInt64Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public UInt64Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public UInt64Value(UInt64Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public UInt64Value Clone() {
+      return new UInt64Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private ulong value_;
+    /// <summary>
+    ///  The uint64 value.
+    /// </summary>
+    public ulong Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as UInt64Value);
+    }
+
+    public bool Equals(UInt64Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0UL) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0UL) {
+        output.WriteRawTag(8);
+        output.WriteUInt64(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0UL) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(UInt64Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0UL) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadUInt64();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `int32`.
+  ///
+  ///  The JSON representation for `Int32Value` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Int32Value : pb::IMessage<Int32Value> {
+    private static readonly pb::MessageParser<Int32Value> _parser = new pb::MessageParser<Int32Value>(() => new Int32Value());
+    public static pb::MessageParser<Int32Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[4]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Int32Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Int32Value(Int32Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public Int32Value Clone() {
+      return new Int32Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private int value_;
+    /// <summary>
+    ///  The int32 value.
+    /// </summary>
+    public int Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Int32Value);
+    }
+
+    public bool Equals(Int32Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Int32Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `uint32`.
+  ///
+  ///  The JSON representation for `UInt32Value` is JSON number.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class UInt32Value : pb::IMessage<UInt32Value> {
+    private static readonly pb::MessageParser<UInt32Value> _parser = new pb::MessageParser<UInt32Value>(() => new UInt32Value());
+    public static pb::MessageParser<UInt32Value> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[5]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public UInt32Value() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public UInt32Value(UInt32Value other) : this() {
+      value_ = other.value_;
+    }
+
+    public UInt32Value Clone() {
+      return new UInt32Value(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private uint value_;
+    /// <summary>
+    ///  The uint32 value.
+    /// </summary>
+    public uint Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as UInt32Value);
+    }
+
+    public bool Equals(UInt32Value other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != 0) {
+        output.WriteRawTag(8);
+        output.WriteUInt32(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(UInt32Value other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadUInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `bool`.
+  ///
+  ///  The JSON representation for `BoolValue` is JSON `true` and `false`.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BoolValue : pb::IMessage<BoolValue> {
+    private static readonly pb::MessageParser<BoolValue> _parser = new pb::MessageParser<BoolValue>(() => new BoolValue());
+    public static pb::MessageParser<BoolValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[6]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BoolValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BoolValue(BoolValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public BoolValue Clone() {
+      return new BoolValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private bool value_;
+    /// <summary>
+    ///  The bool value.
+    /// </summary>
+    public bool Value {
+      get { return value_; }
+      set {
+        value_ = value;
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BoolValue);
+    }
+
+    public bool Equals(BoolValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value != false) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value != false) {
+        size += 1 + 1;
+      }
+      return size;
+    }
+
+    public void MergeFrom(BoolValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value != false) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            Value = input.ReadBool();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `string`.
+  ///
+  ///  The JSON representation for `StringValue` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class StringValue : pb::IMessage<StringValue> {
+    private static readonly pb::MessageParser<StringValue> _parser = new pb::MessageParser<StringValue>(() => new StringValue());
+    public static pb::MessageParser<StringValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[7]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public StringValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public StringValue(StringValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public StringValue Clone() {
+      return new StringValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private string value_ = "";
+    /// <summary>
+    ///  The string value.
+    /// </summary>
+    public string Value {
+      get { return value_; }
+      set {
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as StringValue);
+    }
+
+    public bool Equals(StringValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value.Length != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(StringValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value.Length != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Value = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  Wrapper message for `bytes`.
+  ///
+  ///  The JSON representation for `BytesValue` is JSON string.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class BytesValue : pb::IMessage<BytesValue> {
+    private static readonly pb::MessageParser<BytesValue> _parser = new pb::MessageParser<BytesValue>(() => new BytesValue());
+    public static pb::MessageParser<BytesValue> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[8]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public BytesValue() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public BytesValue(BytesValue other) : this() {
+      value_ = other.value_;
+    }
+
+    public BytesValue Clone() {
+      return new BytesValue(this);
+    }
+
+    /// <summary>Field number for the "value" field.</summary>
+    public const int ValueFieldNumber = 1;
+    private pb::ByteString value_ = pb::ByteString.Empty;
+    /// <summary>
+    ///  The bytes value.
+    /// </summary>
+    public pb::ByteString Value {
+      get { return value_; }
+      set {
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as BytesValue);
+    }
+
+    public bool Equals(BytesValue other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Value != other.Value) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Value.Length != 0) hash ^= Value.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Value.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteBytes(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Value.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(BytesValue other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Value.Length != 0) {
+        Value = other.Value;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Value = input.ReadBytes();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs
new file mode 100644
index 0000000..9f620eb
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs
@@ -0,0 +1,42 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public static partial class WrappersReflection
+    {
+        /// <summary>
+        /// Field number for the single "value" field in all wrapper types.
+        /// </summary>
+        internal const int WrapperValueFieldNumber = Int32Value.ValueFieldNumber;
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WireFormat.cs b/csharp/src/Google.Protobuf/WireFormat.cs
new file mode 100644
index 0000000..faf1e71
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WireFormat.cs
@@ -0,0 +1,104 @@
+#region Copyright notice and license

+// Protocol Buffers - Google's data interchange format

+// Copyright 2008 Google Inc.  All rights reserved.

+// https://developers.google.com/protocol-buffers/

+//

+// Redistribution and use in source and binary forms, with or without

+// modification, are permitted provided that the following conditions are

+// met:

+//

+//     * Redistributions of source code must retain the above copyright

+// notice, this list of conditions and the following disclaimer.

+//     * Redistributions in binary form must reproduce the above

+// copyright notice, this list of conditions and the following disclaimer

+// in the documentation and/or other materials provided with the

+// distribution.

+//     * Neither the name of Google Inc. nor the names of its

+// contributors may be used to endorse or promote products derived from

+// this software without specific prior written permission.

+//

+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#endregion

+

+namespace Google.Protobuf

+{

+    /// <summary>

+    /// This class is used internally by the Protocol Buffer Library and generated

+    /// message implementations. It is public only for the sake of those generated

+    /// messages. Others should not use this class directly.

+    /// <para>

+    /// This class contains constants and helper functions useful for dealing with

+    /// the Protocol Buffer wire format.

+    /// </para>

+    /// </summary>

+    public static class WireFormat

+    {

+        /// <summary>

+        /// Wire types within protobuf encoding.

+        /// </summary>

+        public enum WireType : uint

+        {

+            /// <summary>

+            /// Variable-length integer.

+            /// </summary>

+            Varint = 0,

+            /// <summary>

+            /// A fixed-length 64-bit value.

+            /// </summary>

+            Fixed64 = 1,

+            /// <summary>

+            /// A length-delimited value, i.e. a length followed by that many bytes of data.

+            /// </summary>

+            LengthDelimited = 2,

+            /// <summary>

+            /// A "start group" value - not supported by this implementation.

+            /// </summary>

+            StartGroup = 3,

+            /// <summary>

+            /// An "end group" value - not supported by this implementation.

+            /// </summary>

+            EndGroup = 4,

+            /// <summary>

+            /// A fixed-length 32-bit value.

+            /// </summary>

+            Fixed32 = 5

+        }

+        

+        private const int TagTypeBits = 3;

+        private const uint TagTypeMask = (1 << TagTypeBits) - 1;

+

+        /// <summary>

+        /// Given a tag value, determines the wire type (lower 3 bits).

+        /// </summary>

+        public static WireType GetTagWireType(uint tag)

+        {

+            return (WireType) (tag & TagTypeMask);

+        }

+

+        /// <summary>

+        /// Given a tag value, determines the field number (the upper 29 bits).

+        /// </summary>

+        public static int GetTagFieldNumber(uint tag)

+        {

+            return (int) tag >> TagTypeBits;

+        }

+

+        /// <summary>

+        /// Makes a tag value given a field number and wire type.

+        /// </summary>

+        public static uint MakeTag(int fieldNumber, WireType wireType)

+        {

+            return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;

+        }        

+    }

+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/packages.config b/csharp/src/Google.Protobuf/packages.config
new file mode 100644
index 0000000..40b8fd9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="NuSpec.ReferenceGenerator" version="1.4.1" targetFramework="portable45-net45+win8+wp8+wpa81" developmentDependency="true" />
+</packages>
\ No newline at end of file