Browse Source

Merge pull request #321 from anandolee/csharp

Field Presence for Protocol Buffer C# Proto3
Jie Luo 10 years ago
parent
commit
447de3ad6e

+ 21 - 0
csharp/protos/google/protobuf/field_presence_test.proto

@@ -0,0 +1,21 @@
+syntax = "proto3";
+
+package Google.ProtocolBuffers.TestProtos.FieldPresence;
+
+// TODO(jieluo): Add repeated fields, oneof, maps to TestAllTypes 
+message TestAllTypes {
+  enum NestedEnum {
+    FOO = 0;
+    BAR = 1;
+    BAZ = 2;
+  }
+  message NestedMessage {
+    optional int32 value = 1;
+  }
+
+  optional int32 optional_int32 = 1;
+  optional string optional_string = 2;
+  optional bytes optional_bytes = 3;
+  optional NestedEnum optional_nested_enum = 4;
+  optional NestedMessage optional_nested_message = 5;
+}

+ 183 - 0
csharp/src/ProtocolBuffers.Test/FieldPresenceTest.cs

@@ -0,0 +1,183 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// Author: jieluo@google.com (Jie Luo)
+//
+// 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
+// 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.ProtocolBuffers.Descriptors;
+using Google.ProtocolBuffers.TestProtos.FieldPresence;
+using Xunit;
+
+namespace Google.ProtocolBuffers
+{
+    public class FieldPresenceTest
+    {
+        private void CheckHasMethodRemoved(Type proto2Type, Type proto3Type, string name)
+        {
+            Assert.NotNull(proto2Type.GetProperty(name));
+            Assert.NotNull(proto2Type.GetProperty("Has" + name));
+            Assert.NotNull(proto3Type.GetProperty(name));
+            Assert.Null(proto3Type.GetProperty("Has" + name));
+        }
+
+        [Fact]
+        public void TestHasMethod()
+        {
+            // Optional non-message fields don't have HasFoo method generated
+            Type proto2Type = typeof(Google.ProtocolBuffers.TestProtos.TestAllTypes);
+            Type proto3Type = typeof(TestAllTypes);
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalInt32");
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalString");
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalBytes");
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalNestedEnum");
+            
+            proto2Type = typeof(Google.ProtocolBuffers.TestProtos.TestAllTypes.Builder);
+            proto3Type = typeof(TestAllTypes.Builder);
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalInt32");
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalString");
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalBytes");
+            CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalNestedEnum");
+
+            // message fields still have the HasFoo method generated
+            Assert.False(TestAllTypes.CreateBuilder().Build().HasOptionalNestedMessage);
+            Assert.False(TestAllTypes.CreateBuilder().HasOptionalNestedMessage);
+        }
+
+        [Fact]
+        public void TestFieldPresence()
+        {
+            // Optional non-message fields set to their default value are treated the same
+            // way as not set.
+
+            // Serialization will ignore such fields.
+            TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
+            builder.SetOptionalInt32(0);
+            builder.SetOptionalString("");
+            builder.SetOptionalBytes(ByteString.Empty);
+            builder.SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.FOO);
+            TestAllTypes message = builder.Build();
+            Assert.Equal(0, message.SerializedSize);
+
+            // Test merge
+            TestAllTypes.Builder a = TestAllTypes.CreateBuilder();
+            a.SetOptionalInt32(1);
+            a.SetOptionalString("x");
+            a.SetOptionalBytes(ByteString.CopyFromUtf8("y"));
+            a.SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.BAR);
+            a.MergeFrom(message);
+            TestAllTypes messageA = a.Build();
+            Assert.Equal(1, messageA.OptionalInt32);
+            Assert.Equal("x", messageA.OptionalString);
+            Assert.Equal(ByteString.CopyFromUtf8("y"), messageA.OptionalBytes);
+            Assert.Equal(TestAllTypes.Types.NestedEnum.BAR, messageA.OptionalNestedEnum);
+
+            // equals/hashCode should produce the same results
+            TestAllTypes empty = TestAllTypes.CreateBuilder().Build();
+            Assert.True(empty.Equals(message));
+            Assert.True(message.Equals(empty));
+            Assert.Equal(empty.GetHashCode(), message.GetHashCode());
+        }
+
+        [Fact]
+        public void TestFieldPresenceReflection()
+        {
+            MessageDescriptor descriptor = TestAllTypes.Descriptor;
+            FieldDescriptor optionalInt32Field = descriptor.FindFieldByName("optional_int32");
+            FieldDescriptor optionalStringField = descriptor.FindFieldByName("optional_string");
+            FieldDescriptor optionalBytesField = descriptor.FindFieldByName("optional_bytes");
+            FieldDescriptor optionalNestedEnumField = descriptor.FindFieldByName("optional_nested_enum");
+
+            TestAllTypes message = TestAllTypes.CreateBuilder().Build();
+            Assert.False(message.HasField(optionalInt32Field));
+            Assert.False(message.HasField(optionalStringField));
+            Assert.False(message.HasField(optionalBytesField));
+            Assert.False(message.HasField(optionalNestedEnumField));
+
+            // Set to default value is seen as not present
+            message = TestAllTypes.CreateBuilder()
+                .SetOptionalInt32(0)
+                .SetOptionalString("")
+                .SetOptionalBytes(ByteString.Empty)
+                .SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.FOO)
+                .Build();
+            Assert.False(message.HasField(optionalInt32Field));
+            Assert.False(message.HasField(optionalStringField));
+            Assert.False(message.HasField(optionalBytesField));
+            Assert.False(message.HasField(optionalNestedEnumField));
+            Assert.Equal(0, message.AllFields.Count);
+            
+            // Set t0 non-defalut value is seen as present
+            message = TestAllTypes.CreateBuilder()
+                .SetOptionalInt32(1)
+                .SetOptionalString("x")
+                .SetOptionalBytes(ByteString.CopyFromUtf8("y"))
+                .SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.BAR)
+                .Build();
+            Assert.True(message.HasField(optionalInt32Field));
+            Assert.True(message.HasField(optionalStringField));
+            Assert.True(message.HasField(optionalBytesField));
+            Assert.True(message.HasField(optionalNestedEnumField));
+            Assert.Equal(4, message.AllFields.Count);
+        }
+
+        [Fact]
+        public void TestMessageField()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
+            Assert.False(builder.HasOptionalNestedMessage);
+            Assert.False(builder.Build().HasOptionalNestedMessage);
+
+            // Unlike non-message fields, if we set default value to message field, the field
+            // shoule be seem as present.
+            builder.SetOptionalNestedMessage(TestAllTypes.Types.NestedMessage.DefaultInstance);
+            Assert.True(builder.HasOptionalNestedMessage);
+            Assert.True(builder.Build().HasOptionalNestedMessage);
+        }
+
+        [Fact]
+        public void TestSerializeAndParse()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
+            builder.SetOptionalInt32(1234);
+            builder.SetOptionalString("hello");
+            builder.SetOptionalNestedMessage(TestAllTypes.Types.NestedMessage.DefaultInstance);
+            ByteString data = builder.Build().ToByteString();
+
+            TestAllTypes message = TestAllTypes.ParseFrom(data);
+            Assert.Equal(1234, message.OptionalInt32);
+            Assert.Equal("hello", message.OptionalString);
+            Assert.Equal(ByteString.Empty, message.OptionalBytes);
+            Assert.Equal(TestAllTypes.Types.NestedEnum.FOO, message.OptionalNestedEnum);
+            Assert.True(message.HasOptionalNestedMessage);
+            Assert.Equal(0, message.OptionalNestedMessage.Value);
+        }
+    }
+}

+ 2 - 0
csharp/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj

@@ -65,6 +65,7 @@
   <ItemGroup>
   <ItemGroup>
     <Compile Include="AbstractMessageTest.cs" />
     <Compile Include="AbstractMessageTest.cs" />
     <Compile Include="ByteStringTest.cs" />
     <Compile Include="ByteStringTest.cs" />
+    <Compile Include="FieldPresenceTest.cs" />
     <Compile Include="CodedInputStreamTest.cs" />
     <Compile Include="CodedInputStreamTest.cs" />
     <Compile Include="CodedOutputStreamTest.cs" />
     <Compile Include="CodedOutputStreamTest.cs" />
     <Compile Include="Collections\PopsicleListTest.cs" />
     <Compile Include="Collections\PopsicleListTest.cs" />
@@ -75,6 +76,7 @@
     <Compile Include="Compatibility\TestResources.cs" />
     <Compile Include="Compatibility\TestResources.cs" />
     <Compile Include="Compatibility\TextCompatibilityTests.cs" />
     <Compile Include="Compatibility\TextCompatibilityTests.cs" />
     <Compile Include="Compatibility\XmlCompatibilityTests.cs" />
     <Compile Include="Compatibility\XmlCompatibilityTests.cs" />
+    <Compile Include="TestProtos\FieldPresence.cs" />
     <Compile Include="TestProtos\GoogleSize.cs" />
     <Compile Include="TestProtos\GoogleSize.cs" />
     <Compile Include="TestProtos\GoogleSpeed.cs" />
     <Compile Include="TestProtos\GoogleSpeed.cs" />
     <Compile Include="TestProtos\Unittest.cs" />
     <Compile Include="TestProtos\Unittest.cs" />

+ 782 - 0
csharp/src/ProtocolBuffers.Test/TestProtos/FieldPresence.cs

@@ -0,0 +1,782 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: protos/google/protobuf/field_presence_test.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.ProtocolBuffers;
+using pbc = global::Google.ProtocolBuffers.Collections;
+using pbd = global::Google.ProtocolBuffers.Descriptors;
+using scg = global::System.Collections.Generic;
+namespace Google.ProtocolBuffers.TestProtos.FieldPresence {
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class FieldPresenceTest {
+
+    #region Extension registration
+    public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
+    }
+    #endregion
+    #region Static variables
+    internal static pbd::MessageDescriptor internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__Descriptor;
+    internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes, global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Builder> internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__FieldAccessorTable;
+    internal static pbd::MessageDescriptor internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes_NestedMessage__Descriptor;
+    internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage, global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.Builder> internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes_NestedMessage__FieldAccessorTable;
+    #endregion
+    #region Descriptor
+    public static pbd::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbd::FileDescriptor descriptor;
+
+    static FieldPresenceTest() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CjBwcm90b3MvZ29vZ2xlL3Byb3RvYnVmL2ZpZWxkX3ByZXNlbmNlX3Rlc3Qu", 
+            "cHJvdG8SL0dvb2dsZS5Qcm90b2NvbEJ1ZmZlcnMuVGVzdFByb3Rvcy5GaWVs", 
+            "ZFByZXNlbmNlIvYCCgxUZXN0QWxsVHlwZXMSFgoOb3B0aW9uYWxfaW50MzIY", 
+            "ASABKAUSFwoPb3B0aW9uYWxfc3RyaW5nGAIgASgJEhYKDm9wdGlvbmFsX2J5", 
+            "dGVzGAMgASgMEmYKFG9wdGlvbmFsX25lc3RlZF9lbnVtGAQgASgOMkguR29v", 
+            "Z2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zLkZpZWxkUHJlc2VuY2Uu", 
+            "VGVzdEFsbFR5cGVzLk5lc3RlZEVudW0SbAoXb3B0aW9uYWxfbmVzdGVkX21l", 
+            "c3NhZ2UYBSABKAsySy5Hb29nbGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQcm90", 
+            "b3MuRmllbGRQcmVzZW5jZS5UZXN0QWxsVHlwZXMuTmVzdGVkTWVzc2FnZRoe", 
+            "Cg1OZXN0ZWRNZXNzYWdlEg0KBXZhbHVlGAEgASgFIicKCk5lc3RlZEVudW0S", 
+          "BwoDRk9PEAASBwoDQkFSEAESBwoDQkFaEAJiBnByb3RvMw=="));
+      pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
+        descriptor = root;
+        internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__Descriptor = Descriptor.MessageTypes[0];
+        internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__FieldAccessorTable = 
+            new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes, global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Builder>(internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__Descriptor,
+                new string[] { "OptionalInt32", "OptionalString", "OptionalBytes", "OptionalNestedEnum", "OptionalNestedMessage", });
+        internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes_NestedMessage__Descriptor = internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__Descriptor.NestedTypes[0];
+        internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes_NestedMessage__FieldAccessorTable = 
+            new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage, global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.Builder>(internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes_NestedMessage__Descriptor,
+                new string[] { "Value", });
+        pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();
+        RegisterAllExtensions(registry);
+        return registry;
+      };
+      pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+          new pbd::FileDescriptor[] {
+          }, assigner);
+    }
+    #endregion
+
+  }
+  #region Messages
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class TestAllTypes : pb::GeneratedMessage<TestAllTypes, TestAllTypes.Builder> {
+    private TestAllTypes() { }
+    private static readonly TestAllTypes defaultInstance = new TestAllTypes().MakeReadOnly();
+    private static readonly string[] _testAllTypesFieldNames = new string[] { "optional_bytes", "optional_int32", "optional_nested_enum", "optional_nested_message", "optional_string" };
+    private static readonly uint[] _testAllTypesFieldTags = new uint[] { 26, 8, 32, 42, 18 };
+    public static TestAllTypes DefaultInstance {
+      get { return defaultInstance; }
+    }
+
+    public override TestAllTypes DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+
+    protected override TestAllTypes ThisMessage {
+      get { return this; }
+    }
+
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.FieldPresenceTest.internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__Descriptor; }
+    }
+
+    protected override pb::FieldAccess.FieldAccessorTable<TestAllTypes, TestAllTypes.Builder> InternalFieldAccessors {
+      get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.FieldPresenceTest.internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes__FieldAccessorTable; }
+    }
+
+    #region Nested types
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum NestedEnum {
+        FOO = 0,
+        BAR = 1,
+        BAZ = 2,
+      }
+
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      public sealed partial class NestedMessage : pb::GeneratedMessage<NestedMessage, NestedMessage.Builder> {
+        private NestedMessage() { }
+        private static readonly NestedMessage defaultInstance = new NestedMessage().MakeReadOnly();
+        private static readonly string[] _nestedMessageFieldNames = new string[] { "value" };
+        private static readonly uint[] _nestedMessageFieldTags = new uint[] { 8 };
+        public static NestedMessage DefaultInstance {
+          get { return defaultInstance; }
+        }
+
+        public override NestedMessage DefaultInstanceForType {
+          get { return DefaultInstance; }
+        }
+
+        protected override NestedMessage ThisMessage {
+          get { return this; }
+        }
+
+        public static pbd::MessageDescriptor Descriptor {
+          get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.FieldPresenceTest.internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes_NestedMessage__Descriptor; }
+        }
+
+        protected override pb::FieldAccess.FieldAccessorTable<NestedMessage, NestedMessage.Builder> InternalFieldAccessors {
+          get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.FieldPresenceTest.internal__static_Google_ProtocolBuffers_TestProtos_FieldPresence_TestAllTypes_NestedMessage__FieldAccessorTable; }
+        }
+
+        public const int ValueFieldNumber = 1;
+        private int value_;
+        public int Value {
+          get { return value_; }
+        }
+
+        public override void WriteTo(pb::ICodedOutputStream output) {
+          CalcSerializedSize();
+          string[] field_names = _nestedMessageFieldNames;
+          if (Value != 0) {
+            output.WriteInt32(1, field_names[0], Value);
+          }
+          UnknownFields.WriteTo(output);
+        }
+
+        private int memoizedSerializedSize = -1;
+        public override int SerializedSize {
+          get {
+            int size = memoizedSerializedSize;
+            if (size != -1) return size;
+            return CalcSerializedSize();
+          }
+        }
+
+        private int CalcSerializedSize() {
+          int size = memoizedSerializedSize;
+          if (size != -1) return size;
+
+          size = 0;
+          if (Value != 0) {
+            size += pb::CodedOutputStream.ComputeInt32Size(1, Value);
+          }
+          size += UnknownFields.SerializedSize;
+          memoizedSerializedSize = size;
+          return size;
+        }
+        public static NestedMessage ParseFrom(pb::ByteString data) {
+          return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+        }
+        public static NestedMessage ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+          return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+        }
+        public static NestedMessage ParseFrom(byte[] data) {
+          return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+        }
+        public static NestedMessage ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+          return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+        }
+        public static NestedMessage ParseFrom(global::System.IO.Stream input) {
+          return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+        }
+        public static NestedMessage ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+          return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+        }
+        public static NestedMessage ParseDelimitedFrom(global::System.IO.Stream input) {
+          return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+        }
+        public static NestedMessage ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+          return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+        }
+        public static NestedMessage ParseFrom(pb::ICodedInputStream input) {
+          return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+        }
+        public static NestedMessage ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+          return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+        }
+        private NestedMessage MakeReadOnly() {
+          return this;
+        }
+
+        public static Builder CreateBuilder() { return new Builder(); }
+        public override Builder ToBuilder() { return CreateBuilder(this); }
+        public override Builder CreateBuilderForType() { return new Builder(); }
+        public static Builder CreateBuilder(NestedMessage prototype) {
+          return new Builder(prototype);
+        }
+
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        public sealed partial class Builder : pb::GeneratedBuilder<NestedMessage, Builder> {
+          protected override Builder ThisBuilder {
+            get { return this; }
+          }
+          public Builder() {
+            result = DefaultInstance;
+            resultIsReadOnly = true;
+          }
+          internal Builder(NestedMessage cloneFrom) {
+            result = cloneFrom;
+            resultIsReadOnly = true;
+          }
+
+          private bool resultIsReadOnly;
+          private NestedMessage result;
+
+          private NestedMessage PrepareBuilder() {
+            if (resultIsReadOnly) {
+              NestedMessage original = result;
+              result = new NestedMessage();
+              resultIsReadOnly = false;
+              MergeFrom(original);
+            }
+            return result;
+          }
+
+          public override bool IsInitialized {
+            get { return result.IsInitialized; }
+          }
+
+          protected override NestedMessage MessageBeingBuilt {
+            get { return PrepareBuilder(); }
+          }
+
+          public override Builder Clear() {
+            result = DefaultInstance;
+            resultIsReadOnly = true;
+            return this;
+          }
+
+          public override Builder Clone() {
+            if (resultIsReadOnly) {
+              return new Builder(result);
+            } else {
+              return new Builder().MergeFrom(result);
+            }
+          }
+
+          public override pbd::MessageDescriptor DescriptorForType {
+            get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.Descriptor; }
+          }
+
+          public override NestedMessage DefaultInstanceForType {
+            get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.DefaultInstance; }
+          }
+
+          public override NestedMessage BuildPartial() {
+            if (resultIsReadOnly) {
+              return result;
+            }
+            resultIsReadOnly = true;
+            return result.MakeReadOnly();
+          }
+
+          public override Builder MergeFrom(pb::IMessage other) {
+            if (other is NestedMessage) {
+              return MergeFrom((NestedMessage) other);
+            } else {
+              base.MergeFrom(other);
+              return this;
+            }
+          }
+
+          public override Builder MergeFrom(NestedMessage other) {
+            if (other == global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.DefaultInstance) return this;
+            PrepareBuilder();
+            if (other.Value != 0) {
+              Value = other.Value;
+            }
+            this.MergeUnknownFields(other.UnknownFields);
+            return this;
+          }
+
+          public override Builder MergeFrom(pb::ICodedInputStream input) {
+            return MergeFrom(input, pb::ExtensionRegistry.Empty);
+          }
+
+          public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+            PrepareBuilder();
+            pb::UnknownFieldSet.Builder unknownFields = null;
+            uint tag;
+            string field_name;
+            while (input.ReadTag(out tag, out field_name)) {
+              if(tag == 0 && field_name != null) {
+                int field_ordinal = global::System.Array.BinarySearch(_nestedMessageFieldNames, field_name, global::System.StringComparer.Ordinal);
+                if(field_ordinal >= 0)
+                  tag = _nestedMessageFieldTags[field_ordinal];
+                else {
+                  if (unknownFields == null) {
+                    unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+                  }
+                  ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+                  continue;
+                }
+              }
+              switch (tag) {
+                case 0: {
+                  throw pb::InvalidProtocolBufferException.InvalidTag();
+                }
+                default: {
+                  if (pb::WireFormat.IsEndGroupTag(tag)) {
+                    if (unknownFields != null) {
+                      this.UnknownFields = unknownFields.Build();
+                    }
+                    return this;
+                  }
+                  if (unknownFields == null) {
+                    unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+                  }
+                  ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+                  break;
+                }
+                case 8: {
+                  input.ReadInt32(ref result.value_);
+                  break;
+                }
+              }
+            }
+
+            if (unknownFields != null) {
+              this.UnknownFields = unknownFields.Build();
+            }
+            return this;
+          }
+
+
+          public int Value {
+            get { return result.Value; }
+            set { SetValue(value); }
+          }
+          public Builder SetValue(int value) {
+            PrepareBuilder();
+            result.value_ = value;
+            return this;
+          }
+          public Builder ClearValue() {
+            PrepareBuilder();
+            result.value_ = 0;
+            return this;
+          }
+        }
+        static NestedMessage() {
+          object.ReferenceEquals(global::Google.ProtocolBuffers.TestProtos.FieldPresence.FieldPresenceTest.Descriptor, null);
+        }
+      }
+
+    }
+    #endregion
+
+    public const int OptionalInt32FieldNumber = 1;
+    private int optionalInt32_;
+    public int OptionalInt32 {
+      get { return optionalInt32_; }
+    }
+
+    public const int OptionalStringFieldNumber = 2;
+    private string optionalString_ = "";
+    public string OptionalString {
+      get { return optionalString_; }
+    }
+
+    public const int OptionalBytesFieldNumber = 3;
+    private pb::ByteString optionalBytes_ = pb::ByteString.Empty;
+    public pb::ByteString OptionalBytes {
+      get { return optionalBytes_; }
+    }
+
+    public const int OptionalNestedEnumFieldNumber = 4;
+    private global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum optionalNestedEnum_ = global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum.FOO;
+    public global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum OptionalNestedEnum {
+      get { return optionalNestedEnum_; }
+    }
+
+    public const int OptionalNestedMessageFieldNumber = 5;
+    private bool hasOptionalNestedMessage;
+    private global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage optionalNestedMessage_;
+    public bool HasOptionalNestedMessage {
+      get { return hasOptionalNestedMessage; }
+    }
+    public global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage OptionalNestedMessage {
+      get { return optionalNestedMessage_ ?? global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.DefaultInstance; }
+    }
+
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      CalcSerializedSize();
+      string[] field_names = _testAllTypesFieldNames;
+      if (OptionalInt32 != 0) {
+        output.WriteInt32(1, field_names[1], OptionalInt32);
+      }
+      if (OptionalString != "") {
+        output.WriteString(2, field_names[4], OptionalString);
+      }
+      if (OptionalBytes != pb::ByteString.Empty) {
+        output.WriteBytes(3, field_names[0], OptionalBytes);
+      }
+      if (OptionalNestedEnum != global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum.FOO) {
+        output.WriteEnum(4, field_names[2], (int) OptionalNestedEnum, OptionalNestedEnum);
+      }
+      if (hasOptionalNestedMessage) {
+        output.WriteMessage(5, field_names[3], OptionalNestedMessage);
+      }
+      UnknownFields.WriteTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        return CalcSerializedSize();
+      }
+    }
+
+    private int CalcSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (OptionalInt32 != 0) {
+        size += pb::CodedOutputStream.ComputeInt32Size(1, OptionalInt32);
+      }
+      if (OptionalString != "") {
+        size += pb::CodedOutputStream.ComputeStringSize(2, OptionalString);
+      }
+      if (OptionalBytes != pb::ByteString.Empty) {
+        size += pb::CodedOutputStream.ComputeBytesSize(3, OptionalBytes);
+      }
+      if (OptionalNestedEnum != global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum.FOO) {
+        size += pb::CodedOutputStream.ComputeEnumSize(4, (int) OptionalNestedEnum);
+      }
+      if (hasOptionalNestedMessage) {
+        size += pb::CodedOutputStream.ComputeMessageSize(5, OptionalNestedMessage);
+      }
+      size += UnknownFields.SerializedSize;
+      memoizedSerializedSize = size;
+      return size;
+    }
+    public static TestAllTypes ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static TestAllTypes ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static TestAllTypes ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static TestAllTypes ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static TestAllTypes ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static TestAllTypes ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static TestAllTypes ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static TestAllTypes ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static TestAllTypes ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static TestAllTypes ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private TestAllTypes MakeReadOnly() {
+      return this;
+    }
+
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder ToBuilder() { return CreateBuilder(this); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(TestAllTypes prototype) {
+      return new Builder(prototype);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<TestAllTypes, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(TestAllTypes cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+
+      private bool resultIsReadOnly;
+      private TestAllTypes result;
+
+      private TestAllTypes PrepareBuilder() {
+        if (resultIsReadOnly) {
+          TestAllTypes original = result;
+          result = new TestAllTypes();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+
+      protected override TestAllTypes MessageBeingBuilt {
+        get { return PrepareBuilder(); }
+      }
+
+      public override Builder Clear() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+        return this;
+      }
+
+      public override Builder Clone() {
+        if (resultIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
+      }
+
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Descriptor; }
+      }
+
+      public override TestAllTypes DefaultInstanceForType {
+        get { return global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.DefaultInstance; }
+      }
+
+      public override TestAllTypes BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is TestAllTypes) {
+          return MergeFrom((TestAllTypes) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+
+      public override Builder MergeFrom(TestAllTypes other) {
+        if (other == global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.DefaultInstance) return this;
+        PrepareBuilder();
+        if (other.OptionalInt32 != 0) {
+          OptionalInt32 = other.OptionalInt32;
+        }
+        if (other.OptionalString != "") {
+          OptionalString = other.OptionalString;
+        }
+        if (other.OptionalBytes != pb::ByteString.Empty) {
+          OptionalBytes = other.OptionalBytes;
+        }
+        if (other.OptionalNestedEnum != global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum.FOO) {
+          OptionalNestedEnum = other.OptionalNestedEnum;
+        }
+        if (other.HasOptionalNestedMessage) {
+          MergeOptionalNestedMessage(other.OptionalNestedMessage);
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
+        pb::UnknownFieldSet.Builder unknownFields = null;
+        uint tag;
+        string field_name;
+        while (input.ReadTag(out tag, out field_name)) {
+          if(tag == 0 && field_name != null) {
+            int field_ordinal = global::System.Array.BinarySearch(_testAllTypesFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _testAllTypesFieldTags[field_ordinal];
+            else {
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              continue;
+            }
+          }
+          switch (tag) {
+            case 0: {
+              throw pb::InvalidProtocolBufferException.InvalidTag();
+            }
+            default: {
+              if (pb::WireFormat.IsEndGroupTag(tag)) {
+                if (unknownFields != null) {
+                  this.UnknownFields = unknownFields.Build();
+                }
+                return this;
+              }
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              break;
+            }
+            case 8: {
+              input.ReadInt32(ref result.optionalInt32_);
+              break;
+            }
+            case 18: {
+              input.ReadString(ref result.optionalString_);
+              break;
+            }
+            case 26: {
+              input.ReadBytes(ref result.optionalBytes_);
+              break;
+            }
+            case 32: {
+              object unknown;
+              if(input.ReadEnum(ref result.optionalNestedEnum_, out unknown)) {
+              } else if(unknown is int) {
+                if (unknownFields == null) {
+                  unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+                }
+                unknownFields.MergeVarintField(4, (ulong)(int)unknown);
+              }
+              break;
+            }
+            case 42: {
+              global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.Builder subBuilder = global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.CreateBuilder();
+              if (result.hasOptionalNestedMessage) {
+                subBuilder.MergeFrom(OptionalNestedMessage);
+              }
+              input.ReadMessage(subBuilder, extensionRegistry);
+              OptionalNestedMessage = subBuilder.BuildPartial();
+              break;
+            }
+          }
+        }
+
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+
+
+      public int OptionalInt32 {
+        get { return result.OptionalInt32; }
+        set { SetOptionalInt32(value); }
+      }
+      public Builder SetOptionalInt32(int value) {
+        PrepareBuilder();
+        result.optionalInt32_ = value;
+        return this;
+      }
+      public Builder ClearOptionalInt32() {
+        PrepareBuilder();
+        result.optionalInt32_ = 0;
+        return this;
+      }
+
+      public string OptionalString {
+        get { return result.OptionalString; }
+        set { SetOptionalString(value); }
+      }
+      public Builder SetOptionalString(string value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.optionalString_ = value;
+        return this;
+      }
+      public Builder ClearOptionalString() {
+        PrepareBuilder();
+        result.optionalString_ = "";
+        return this;
+      }
+
+      public pb::ByteString OptionalBytes {
+        get { return result.OptionalBytes; }
+        set { SetOptionalBytes(value); }
+      }
+      public Builder SetOptionalBytes(pb::ByteString value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.optionalBytes_ = value;
+        return this;
+      }
+      public Builder ClearOptionalBytes() {
+        PrepareBuilder();
+        result.optionalBytes_ = pb::ByteString.Empty;
+        return this;
+      }
+
+      public global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum OptionalNestedEnum {
+        get { return result.OptionalNestedEnum; }
+        set { SetOptionalNestedEnum(value); }
+      }
+      public Builder SetOptionalNestedEnum(global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum value) {
+        PrepareBuilder();
+        result.optionalNestedEnum_ = value;
+        return this;
+      }
+      public Builder ClearOptionalNestedEnum() {
+        PrepareBuilder();
+        result.optionalNestedEnum_ = global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedEnum.FOO;
+        return this;
+      }
+
+      public bool HasOptionalNestedMessage {
+       get { return result.hasOptionalNestedMessage; }
+      }
+      public global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage OptionalNestedMessage {
+        get { return result.OptionalNestedMessage; }
+        set { SetOptionalNestedMessage(value); }
+      }
+      public Builder SetOptionalNestedMessage(global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.hasOptionalNestedMessage = true;
+        result.optionalNestedMessage_ = value;
+        return this;
+      }
+      public Builder SetOptionalNestedMessage(global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.Builder builderForValue) {
+        pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
+        result.hasOptionalNestedMessage = true;
+        result.optionalNestedMessage_ = builderForValue.Build();
+        return this;
+      }
+      public Builder MergeOptionalNestedMessage(global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        if (result.hasOptionalNestedMessage &&
+            result.optionalNestedMessage_ != global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.DefaultInstance) {
+            result.optionalNestedMessage_ = global::Google.ProtocolBuffers.TestProtos.FieldPresence.TestAllTypes.Types.NestedMessage.CreateBuilder(result.optionalNestedMessage_).MergeFrom(value).BuildPartial();
+        } else {
+          result.optionalNestedMessage_ = value;
+        }
+        result.hasOptionalNestedMessage = true;
+        return this;
+      }
+      public Builder ClearOptionalNestedMessage() {
+        PrepareBuilder();
+        result.hasOptionalNestedMessage = false;
+        result.optionalNestedMessage_ = null;
+        return this;
+      }
+    }
+    static TestAllTypes() {
+      object.ReferenceEquals(global::Google.ProtocolBuffers.TestProtos.FieldPresence.FieldPresenceTest.Descriptor, null);
+    }
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 11 - 0
csharp/src/ProtocolBuffers/Descriptors/FileDescriptor.cs

@@ -54,6 +54,17 @@ namespace Google.ProtocolBuffers.Descriptors
         private readonly IList<FileDescriptor> publicDependencies;
         private readonly IList<FileDescriptor> publicDependencies;
         private readonly DescriptorPool pool;
         private readonly DescriptorPool pool;
 
 
+        public enum ProtoSyntax
+        {
+            Proto2,
+            Proto3
+        }
+
+        public ProtoSyntax Syntax
+        {
+            get { return proto.Syntax == "proto3" ? ProtoSyntax.Proto3 : ProtoSyntax.Proto2; }
+        }
+
         private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies)
         private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies)
         {
         {
             this.pool = pool;
             this.pool = pool;

+ 5 - 4
csharp/src/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs

@@ -68,16 +68,17 @@ namespace Google.ProtocolBuffers.FieldAccess
         {
         {
             this.descriptor = descriptor;
             this.descriptor = descriptor;
             accessors = new IFieldAccessor<TMessage, TBuilder>[descriptor.Fields.Count];
             accessors = new IFieldAccessor<TMessage, TBuilder>[descriptor.Fields.Count];
+            bool supportFieldPresence = descriptor.File.Syntax == FileDescriptor.ProtoSyntax.Proto2;
             for (int i = 0; i < accessors.Length; i++)
             for (int i = 0; i < accessors.Length; i++)
             {
             {
-                accessors[i] = CreateAccessor(descriptor.Fields[i], propertyNames[i]);
+                accessors[i] = CreateAccessor(descriptor.Fields[i], propertyNames[i], supportFieldPresence);
             }
             }
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Creates an accessor for a single field
         /// Creates an accessor for a single field
         /// </summary>   
         /// </summary>   
-        private static IFieldAccessor<TMessage, TBuilder> CreateAccessor(FieldDescriptor field, string name)
+        private static IFieldAccessor<TMessage, TBuilder> CreateAccessor(FieldDescriptor field, string name, bool supportFieldPresence)
         {
         {
             if (field.IsRepeated)
             if (field.IsRepeated)
             {
             {
@@ -98,9 +99,9 @@ namespace Google.ProtocolBuffers.FieldAccess
                     case MappedType.Message:
                     case MappedType.Message:
                         return new SingleMessageAccessor<TMessage, TBuilder>(name);
                         return new SingleMessageAccessor<TMessage, TBuilder>(name);
                     case MappedType.Enum:
                     case MappedType.Enum:
-                        return new SingleEnumAccessor<TMessage, TBuilder>(field, name);
+                        return new SingleEnumAccessor<TMessage, TBuilder>(field, name, supportFieldPresence);
                     default:
                     default:
-                        return new SinglePrimitiveAccessor<TMessage, TBuilder>(name);
+                        return new SinglePrimitiveAccessor<TMessage, TBuilder>(field, name, supportFieldPresence);
                 }
                 }
             }
             }
         }
         }

+ 1 - 1
csharp/src/ProtocolBuffers/FieldAccess/SingleEnumAccessor.cs

@@ -42,7 +42,7 @@ namespace Google.ProtocolBuffers.FieldAccess
     {
     {
         private readonly EnumDescriptor enumDescriptor;
         private readonly EnumDescriptor enumDescriptor;
 
 
-        internal SingleEnumAccessor(FieldDescriptor field, string name) : base(name)
+        internal SingleEnumAccessor(FieldDescriptor field, string name, bool supportFieldPresence) : base(field, name, supportFieldPresence)
         {
         {
             enumDescriptor = field.EnumType;
             enumDescriptor = field.EnumType;
         }
         }

+ 1 - 1
csharp/src/ProtocolBuffers/FieldAccess/SingleMessageAccessor.cs

@@ -48,7 +48,7 @@ namespace Google.ProtocolBuffers.FieldAccess
         /// </summary>
         /// </summary>
         private readonly Func<IBuilder> createBuilderDelegate;
         private readonly Func<IBuilder> createBuilderDelegate;
 
 
-        internal SingleMessageAccessor(string name) : base(name)
+        internal SingleMessageAccessor(string name) : base(null, name, true)
         {
         {
             MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", ReflectionUtil.EmptyTypes);
             MethodInfo createBuilderMethod = ClrType.GetMethod("CreateBuilder", ReflectionUtil.EmptyTypes);
             if (createBuilderMethod == null)
             if (createBuilderMethod == null)

+ 17 - 4
csharp/src/ProtocolBuffers/FieldAccess/SinglePrimitiveAccessor.cs

@@ -31,6 +31,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using System;
 using System;
 using System.Reflection;
 using System.Reflection;
+using Google.ProtocolBuffers.Descriptors;
 
 
 namespace Google.ProtocolBuffers.FieldAccess
 namespace Google.ProtocolBuffers.FieldAccess
 {
 {
@@ -56,18 +57,30 @@ namespace Google.ProtocolBuffers.FieldAccess
             get { return clrType; }
             get { return clrType; }
         }
         }
 
 
-        internal SinglePrimitiveAccessor(string name)
+        internal SinglePrimitiveAccessor(FieldDescriptor fieldDescriptor, string name, bool supportFieldPresence)
         {
         {
             PropertyInfo messageProperty = typeof(TMessage).GetProperty(name, null, ReflectionUtil.EmptyTypes);
             PropertyInfo messageProperty = typeof(TMessage).GetProperty(name, null, ReflectionUtil.EmptyTypes);
             PropertyInfo builderProperty = typeof(TBuilder).GetProperty(name, null, ReflectionUtil.EmptyTypes);
             PropertyInfo builderProperty = typeof(TBuilder).GetProperty(name, null, ReflectionUtil.EmptyTypes);
-            PropertyInfo hasProperty = typeof(TMessage).GetProperty("Has" + name);
             MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
             MethodInfo clearMethod = typeof(TBuilder).GetMethod("Clear" + name);
-            if (messageProperty == null || builderProperty == null || hasProperty == null || clearMethod == null)
+            if (messageProperty == null || builderProperty == null || clearMethod == null)
             {
             {
                 throw new ArgumentException("Not all required properties/methods available");
                 throw new ArgumentException("Not all required properties/methods available");
             }
             }
+
+            if (supportFieldPresence)
+            {
+                PropertyInfo hasProperty = typeof(TMessage).GetProperty("Has" + name);
+                if (hasProperty == null)
+                {
+                    throw new ArgumentException("Has properties not available");
+                }
+                hasDelegate = ReflectionUtil.CreateDelegateFunc<TMessage, bool>(hasProperty.GetGetMethod());
+            } else
+            {
+                hasDelegate = message => !GetValue(message).Equals(fieldDescriptor.DefaultValue);
+            }
+
             clrType = messageProperty.PropertyType;
             clrType = messageProperty.PropertyType;
-            hasDelegate = ReflectionUtil.CreateDelegateFunc<TMessage, bool>(hasProperty.GetGetMethod());
             clearDelegate = ReflectionUtil.CreateDelegateFunc<TBuilder, IBuilder>(clearMethod);
             clearDelegate = ReflectionUtil.CreateDelegateFunc<TBuilder, IBuilder>(clearMethod);
             getValueDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(messageProperty.GetGetMethod());
             getValueDelegate = ReflectionUtil.CreateUpcastDelegate<TMessage>(messageProperty.GetGetMethod());
             setValueDelegate = ReflectionUtil.CreateDowncastDelegate<TBuilder>(builderProperty.GetSetMethod());
             setValueDelegate = ReflectionUtil.CreateDowncastDelegate<TBuilder>(builderProperty.GetSetMethod());

+ 59 - 20
src/google/protobuf/compiler/csharp/csharp_enum_field.cc

@@ -56,13 +56,17 @@ EnumFieldGenerator::~EnumFieldGenerator() {
 }
 }
 
 
 void EnumFieldGenerator::GenerateMembers(Writer* writer) {
 void EnumFieldGenerator::GenerateMembers(Writer* writer) {
-  writer->WriteLine("private bool has$0$;", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("private bool has$0$;", property_name());
+  }
   writer->WriteLine("private $0$ $1$_ = $2$;", type_name(), name(),
   writer->WriteLine("private $0$ $1$_ = $2$;", type_name(), name(),
                     default_value());
                     default_value());
   AddDeprecatedFlag(writer);
   AddDeprecatedFlag(writer);
-  writer->WriteLine("public bool Has$0$ {", property_name());
-  writer->WriteLine("  get { return has$0$; }", property_name());
-  writer->WriteLine("}");
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("public bool Has$0$ {", property_name());
+    writer->WriteLine("  get { return has$0$; }", property_name());
+    writer->WriteLine("}");
+  }
   AddPublicMemberAttributes(writer);
   AddPublicMemberAttributes(writer);
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("  get { return $0$_; }", name());
   writer->WriteLine("  get { return $0$_; }", name());
@@ -71,9 +75,11 @@ void EnumFieldGenerator::GenerateMembers(Writer* writer) {
 
 
 void EnumFieldGenerator::GenerateBuilderMembers(Writer* writer) {
 void EnumFieldGenerator::GenerateBuilderMembers(Writer* writer) {
   AddDeprecatedFlag(writer);
   AddDeprecatedFlag(writer);
-  writer->WriteLine("public bool Has$0$ {", property_name());
-  writer->WriteLine(" get { return result.has$0$; }", property_name());
-  writer->WriteLine("}");
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("public bool Has$0$ {", property_name());
+    writer->WriteLine(" get { return result.has$0$; }", property_name());
+    writer->WriteLine("}");
+  }
   AddPublicMemberAttributes(writer);
   AddPublicMemberAttributes(writer);
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("  get { return result.$0$; }", property_name());
   writer->WriteLine("  get { return result.$0$; }", property_name());
@@ -83,21 +89,29 @@ void EnumFieldGenerator::GenerateBuilderMembers(Writer* writer) {
   writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(),
   writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(),
                     type_name());
                     type_name());
   writer->WriteLine("  PrepareBuilder();");
   writer->WriteLine("  PrepareBuilder();");
-  writer->WriteLine("  result.has$0$ = true;", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("  result.has$0$ = true;", property_name());
+  }
   writer->WriteLine("  result.$0$_ = value;", name());
   writer->WriteLine("  result.$0$_ = value;", name());
   writer->WriteLine("  return this;");
   writer->WriteLine("  return this;");
   writer->WriteLine("}");
   writer->WriteLine("}");
   AddDeprecatedFlag(writer);
   AddDeprecatedFlag(writer);
   writer->WriteLine("public Builder Clear$0$() {", property_name());
   writer->WriteLine("public Builder Clear$0$() {", property_name());
   writer->WriteLine("  PrepareBuilder();");
   writer->WriteLine("  PrepareBuilder();");
-  writer->WriteLine("  result.has$0$ = false;", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("  result.has$0$ = false;", property_name());
+  }
   writer->WriteLine("  result.$0$_ = $1$;", name(), default_value());
   writer->WriteLine("  result.$0$_ = $1$;", name(), default_value());
   writer->WriteLine("  return this;");
   writer->WriteLine("  return this;");
   writer->WriteLine("}");
   writer->WriteLine("}");
 }
 }
 
 
 void EnumFieldGenerator::GenerateMergingCode(Writer* writer) {
 void EnumFieldGenerator::GenerateMergingCode(Writer* writer) {
-  writer->WriteLine("if (other.Has$0$) {", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (other.Has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if (other.$0$ != $1$) {", property_name(), default_value());
+  }
   writer->WriteLine("  $0$ = other.$0$;", property_name());
   writer->WriteLine("  $0$ = other.$0$;", property_name());
   writer->WriteLine("}");
   writer->WriteLine("}");
 }
 }
@@ -110,7 +124,9 @@ void EnumFieldGenerator::GenerateParsingCode(Writer* writer) {
   writer->WriteLine("object unknown;");
   writer->WriteLine("object unknown;");
   writer->WriteLine("if(input.ReadEnum(ref result.$0$_, out unknown)) {",
   writer->WriteLine("if(input.ReadEnum(ref result.$0$_, out unknown)) {",
                     name());
                     name());
-  writer->WriteLine("  result.has$0$ = true;", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("  result.has$0$ = true;", property_name());
+  }
   writer->WriteLine("} else if(unknown is int) {");
   writer->WriteLine("} else if(unknown is int) {");
   if (!use_lite_runtime()) {
   if (!use_lite_runtime()) {
     writer->WriteLine("  if (unknownFields == null) {");  // First unknown field - create builder now
     writer->WriteLine("  if (unknownFields == null) {");  // First unknown field - create builder now
@@ -125,7 +141,11 @@ void EnumFieldGenerator::GenerateParsingCode(Writer* writer) {
 }
 }
 
 
 void EnumFieldGenerator::GenerateSerializationCode(Writer* writer) {
 void EnumFieldGenerator::GenerateSerializationCode(Writer* writer) {
-  writer->WriteLine("if (has$0$) {", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value());
+  }
   writer->WriteLine(
   writer->WriteLine(
       "  output.WriteEnum($0$, field_names[$2$], (int) $1$, $1$);", number(),
       "  output.WriteEnum($0$, field_names[$2$], (int) $1$, $1$);", number(),
       property_name(), field_ordinal());
       property_name(), field_ordinal());
@@ -133,7 +153,11 @@ void EnumFieldGenerator::GenerateSerializationCode(Writer* writer) {
 }
 }
 
 
 void EnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) {
 void EnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) {
-  writer->WriteLine("if (has$0$) {", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value());
+  }
   writer->WriteLine(
   writer->WriteLine(
       "  size += pb::CodedOutputStream.ComputeEnumSize($0$, (int) $1$);",
       "  size += pb::CodedOutputStream.ComputeEnumSize($0$, (int) $1$);",
       number(), property_name());
       number(), property_name());
@@ -141,17 +165,32 @@ void EnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) {
 }
 }
 
 
 void EnumFieldGenerator::WriteHash(Writer* writer) {
 void EnumFieldGenerator::WriteHash(Writer* writer) {
-  writer->WriteLine("if (has$0$) hash ^= $1$_.GetHashCode();", property_name(),
-                    name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value());
+  }
+  writer->WriteLine("  hash ^= $0$_.GetHashCode();", name());
+  writer->WriteLine("}");
 }
 }
 void EnumFieldGenerator::WriteEquals(Writer* writer) {
 void EnumFieldGenerator::WriteEquals(Writer* writer) {
-  writer->WriteLine(
-      "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;",
-      property_name(), name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine(
+        "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;",
+        property_name(), name());
+  } else {
+    writer->WriteLine(
+        "if (!$0$_.Equals(other.$0$_)) return false;", name());
+  }
 }
 }
 void EnumFieldGenerator::WriteToString(Writer* writer) {
 void EnumFieldGenerator::WriteToString(Writer* writer) {
-  writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);",
-                    descriptor_->name(), property_name(), name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);",
+                      descriptor_->name(), property_name(), name());
+  } else {
+    writer->WriteLine("PrintField(\"$0$\", $1$_, writer);",
+                      descriptor_->name(), name());
+  }
 }
 }
 
 
 }  // namespace csharp
 }  // namespace csharp

+ 4 - 0
src/google/protobuf/compiler/csharp/csharp_helpers.h

@@ -101,6 +101,10 @@ FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int
 
 
 bool HasRequiredFields(const Descriptor* descriptor);
 bool HasRequiredFields(const Descriptor* descriptor);
 
 
+inline bool SupportFieldPresence(const FileDescriptor* file) {
+  return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
 }  // namespace csharp
 }  // namespace csharp
 }  // namespace compiler
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace protobuf

+ 3 - 1
src/google/protobuf/compiler/csharp/csharp_message.cc

@@ -279,7 +279,9 @@ void MessageGenerator::Generate(Writer* writer) {
   }
   }
 
 
   if (optimize_speed()) {
   if (optimize_speed()) {
-    GenerateIsInitialized(writer);
+    if (SupportFieldPresence(descriptor_->file())) {
+      GenerateIsInitialized(writer);
+    }
     GenerateMessageSerializationMethods(writer);
     GenerateMessageSerializationMethods(writer);
   }
   }
   if (use_lite_runtime()) {
   if (use_lite_runtime()) {

+ 63 - 21
src/google/protobuf/compiler/csharp/csharp_primitive_field.cc

@@ -57,13 +57,17 @@ PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {
 }
 }
 
 
 void PrimitiveFieldGenerator::GenerateMembers(Writer* writer) {
 void PrimitiveFieldGenerator::GenerateMembers(Writer* writer) {
-  writer->WriteLine("private bool has$0$;", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("private bool has$0$;", property_name());
+  }
   writer->WriteLine("private $0$ $1$_$2$;", type_name(), name(),
   writer->WriteLine("private $0$ $1$_$2$;", type_name(), name(),
                     has_default_value() ? " = " + default_value() : "");
                     has_default_value() ? " = " + default_value() : "");
   AddDeprecatedFlag(writer);
   AddDeprecatedFlag(writer);
-  writer->WriteLine("public bool Has$0$ {", property_name());
-  writer->WriteLine("  get { return has$0$; }", property_name());
-  writer->WriteLine("}");
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("public bool Has$0$ {", property_name());
+    writer->WriteLine("  get { return has$0$; }", property_name());
+    writer->WriteLine("}");
+  }
   AddPublicMemberAttributes(writer);
   AddPublicMemberAttributes(writer);
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("  get { return $0$_; }", name());
   writer->WriteLine("  get { return $0$_; }", name());
@@ -72,9 +76,11 @@ void PrimitiveFieldGenerator::GenerateMembers(Writer* writer) {
 
 
 void PrimitiveFieldGenerator::GenerateBuilderMembers(Writer* writer) {
 void PrimitiveFieldGenerator::GenerateBuilderMembers(Writer* writer) {
   AddDeprecatedFlag(writer);
   AddDeprecatedFlag(writer);
-  writer->WriteLine("public bool Has$0$ {", property_name());
-  writer->WriteLine("  get { return result.has$0$; }", property_name());
-  writer->WriteLine("}");
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("public bool Has$0$ {", property_name());
+    writer->WriteLine("  get { return result.has$0$; }", property_name());
+    writer->WriteLine("}");
+  }
   AddPublicMemberAttributes(writer);
   AddPublicMemberAttributes(writer);
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("public $0$ $1$ {", type_name(), property_name());
   writer->WriteLine("  get { return result.$0$; }", property_name());
   writer->WriteLine("  get { return result.$0$; }", property_name());
@@ -85,21 +91,29 @@ void PrimitiveFieldGenerator::GenerateBuilderMembers(Writer* writer) {
                     type_name());
                     type_name());
   AddNullCheck(writer);
   AddNullCheck(writer);
   writer->WriteLine("  PrepareBuilder();");
   writer->WriteLine("  PrepareBuilder();");
-  writer->WriteLine("  result.has$0$ = true;", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("  result.has$0$ = true;", property_name());
+  }
   writer->WriteLine("  result.$0$_ = value;", name());
   writer->WriteLine("  result.$0$_ = value;", name());
   writer->WriteLine("  return this;");
   writer->WriteLine("  return this;");
   writer->WriteLine("}");
   writer->WriteLine("}");
   AddDeprecatedFlag(writer);
   AddDeprecatedFlag(writer);
   writer->WriteLine("public Builder Clear$0$() {", property_name());
   writer->WriteLine("public Builder Clear$0$() {", property_name());
   writer->WriteLine("  PrepareBuilder();");
   writer->WriteLine("  PrepareBuilder();");
-  writer->WriteLine("  result.has$0$ = false;", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("  result.has$0$ = false;", property_name());
+  }
   writer->WriteLine("  result.$0$_ = $1$;", name(), default_value());
   writer->WriteLine("  result.$0$_ = $1$;", name(), default_value());
   writer->WriteLine("  return this;");
   writer->WriteLine("  return this;");
   writer->WriteLine("}");
   writer->WriteLine("}");
 }
 }
 
 
 void PrimitiveFieldGenerator::GenerateMergingCode(Writer* writer) {
 void PrimitiveFieldGenerator::GenerateMergingCode(Writer* writer) {
-  writer->WriteLine("if (other.Has$0$) {", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (other.Has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if (other.$0$ != $1$) {", property_name(), default_value());
+  }
   writer->WriteLine("  $0$ = other.$0$;", property_name());
   writer->WriteLine("  $0$ = other.$0$;", property_name());
   writer->WriteLine("}");
   writer->WriteLine("}");
 }
 }
@@ -109,12 +123,21 @@ void PrimitiveFieldGenerator::GenerateBuildingCode(Writer* writer) {
 }
 }
 
 
 void PrimitiveFieldGenerator::GenerateParsingCode(Writer* writer) {
 void PrimitiveFieldGenerator::GenerateParsingCode(Writer* writer) {
-  writer->WriteLine("result.has$0$ = input.Read$1$(ref result.$2$_);",
-                    property_name(), capitalized_type_name(), name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("result.has$0$ = input.Read$1$(ref result.$2$_);",
+                      property_name(), capitalized_type_name(), name());
+  } else {
+    writer->WriteLine("input.Read$0$(ref result.$1$_);",
+                      capitalized_type_name(), name());
+  }
 }
 }
 
 
 void PrimitiveFieldGenerator::GenerateSerializationCode(Writer* writer) {
 void PrimitiveFieldGenerator::GenerateSerializationCode(Writer* writer) {
-  writer->WriteLine("if (has$0$) {", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value());
+  }
   writer->WriteLine("  output.Write$0$($1$, field_names[$3$], $2$);",
   writer->WriteLine("  output.Write$0$($1$, field_names[$3$], $2$);",
                     capitalized_type_name(), number(), property_name(),
                     capitalized_type_name(), number(), property_name(),
                     field_ordinal());
                     field_ordinal());
@@ -122,24 +145,43 @@ void PrimitiveFieldGenerator::GenerateSerializationCode(Writer* writer) {
 }
 }
 
 
 void PrimitiveFieldGenerator::GenerateSerializedSizeCode(Writer* writer) {
 void PrimitiveFieldGenerator::GenerateSerializedSizeCode(Writer* writer) {
-  writer->WriteLine("if (has$0$) {", property_name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value());
+  }
   writer->WriteLine("  size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);",
   writer->WriteLine("  size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);",
                     capitalized_type_name(), number(), property_name());
                     capitalized_type_name(), number(), property_name());
   writer->WriteLine("}");
   writer->WriteLine("}");
 }
 }
 
 
 void PrimitiveFieldGenerator::WriteHash(Writer* writer) {
 void PrimitiveFieldGenerator::WriteHash(Writer* writer) {
-  writer->WriteLine("if (has$0$) hash ^= $1$_.GetHashCode();", property_name(),
-                    name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("if (has$0$) {", property_name());
+  } else {
+    writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value());
+  }
+  writer->WriteLine("  hash ^= $0$_.GetHashCode();", name());
+  writer->WriteLine("}");
 }
 }
 void PrimitiveFieldGenerator::WriteEquals(Writer* writer) {
 void PrimitiveFieldGenerator::WriteEquals(Writer* writer) {
-  writer->WriteLine(
-      "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;",
-      property_name(), name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine(
+        "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;",
+        property_name(), name());
+  } else {
+    writer->WriteLine(
+        "if (!$0$_.Equals(other.$0$_)) return false;", name());
+  }
 }
 }
 void PrimitiveFieldGenerator::WriteToString(Writer* writer) {
 void PrimitiveFieldGenerator::WriteToString(Writer* writer) {
-  writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);",
-                    descriptor_->name(), property_name(), name());
+  if (SupportFieldPresence(descriptor_->file())) {
+    writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);",
+                      descriptor_->name(), property_name(), name());
+  } else {
+    writer->WriteLine("PrintField(\"$0$\", $1$_, writer);",
+                      descriptor_->name(), name());
+  }
 }
 }
 
 
 }  // namespace csharp
 }  // namespace csharp