Browse Source

First pass at implementation and testing of reusable builders.

csharptest 14 years ago
parent
commit
1a0764ab27
36 changed files with 4303 additions and 997 deletions
  1. 141 35
      src/AddressBook/AddressBookProtos.cs
  2. 2 0
      src/ProtoGen/EnumFieldGenerator.cs
  3. 4 0
      src/ProtoGen/MessageFieldGenerator.cs
  4. 43 12
      src/ProtoGen/MessageGenerator.cs
  5. 2 0
      src/ProtoGen/PrimitiveFieldGenerator.cs
  6. 5 1
      src/ProtoGen/RepeatedEnumFieldGenerator.cs
  7. 7 1
      src/ProtoGen/RepeatedMessageFieldGenerator.cs
  8. 5 1
      src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
  9. 0 16
      src/ProtocolBuffers.Test/GeneratedMessageTest.cs
  10. 1 0
      src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
  11. 117 0
      src/ProtocolBuffers.Test/ReusableBuilderTest.cs
  12. 45 11
      src/ProtocolBuffers.Test/TestProtos/UnitTestCSharpOptionsProtoFile.cs
  13. 425 116
      src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs
  14. 50 12
      src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs
  15. 164 44
      src/ProtocolBuffers.Test/TestProtos/UnitTestExtrasIssuesProtoFile.cs
  16. 195 23
      src/ProtocolBuffers.Test/TestProtos/UnitTestGoogleSizeProtoFile.cs
  17. 195 23
      src/ProtocolBuffers.Test/TestProtos/UnitTestGoogleSpeedProtoFile.cs
  18. 41 11
      src/ProtocolBuffers.Test/TestProtos/UnitTestImportLiteProtoFile.cs
  19. 41 11
      src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs
  20. 253 67
      src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs
  21. 41 11
      src/ProtocolBuffers.Test/TestProtos/UnitTestNoGenericServicesProtoFile.cs
  22. 123 33
      src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs
  23. 249 51
      src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs
  24. 181 47
      src/ProtocolBuffers.Test/TestProtos/UnitTestRpcInterop.cs
  25. 281 71
      src/ProtocolBuffers.Test/TestProtos/UnitTestXmlSerializerTestProtoFile.cs
  26. 188 44
      src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs
  27. 282 61
      src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs
  28. 3 8
      src/ProtocolBuffers/GeneratedBuilder.cs
  29. 1 6
      src/ProtocolBuffers/GeneratedBuilderLite.cs
  30. 355 88
      src/ProtocolBuffersLite.Test/TestProtos/UnitTestExtrasFullProtoFile.cs
  31. 240 58
      src/ProtocolBuffersLite.Test/TestProtos/UnitTestExtrasLiteProtoFile.cs
  32. 41 11
      src/ProtocolBuffersLite.Test/TestProtos/UnitTestImportLiteProtoFile.cs
  33. 41 11
      src/ProtocolBuffersLite.Test/TestProtos/UnitTestImportProtoFile.cs
  34. 43 11
      src/ProtocolBuffersLite.Test/TestProtos/UnitTestLiteImportNonLiteProtoFile.cs
  35. 249 51
      src/ProtocolBuffersLite.Test/TestProtos/UnitTestLiteProtoFile.cs
  36. 249 51
      src/ProtocolBuffersLite.Test/TestProtos/UnitTestProtoFile.cs

+ 141 - 35
src/AddressBook/AddressBookProtos.cs

@@ -223,7 +223,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
         public override Builder ToBuilder() { return CreateBuilder(this); }
         public override Builder CreateBuilderForType() { return new Builder(); }
         public static Builder CreateBuilder(PhoneNumber prototype) {
-          return (Builder) new Builder().MergeFrom(prototype);
+          return new Builder(prototype);
         }
         
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -233,21 +233,48 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
           protected override Builder ThisBuilder {
             get { return this; }
           }
-          public Builder() {}
+          public Builder() {
+            result = DefaultInstance ?? new PhoneNumber();
+            builderIsReadOnly = result == DefaultInstance;
+          }
+          internal Builder(PhoneNumber cloneFrom) {
+            result = cloneFrom;
+            builderIsReadOnly = true;
+          }
           
-          PhoneNumber result = new PhoneNumber();
+          bool builderIsReadOnly;
+          PhoneNumber result;
+          
+          private PhoneNumber PrepareBuilder() {
+            if (builderIsReadOnly) {
+              PhoneNumber original = result;
+              result = new PhoneNumber();
+              builderIsReadOnly = false;
+              MergeFrom(original);
+            }
+            return result;
+          }
+          
+          public override bool IsInitialized {
+            get { return result.IsInitialized; }
+          }
           
           protected override PhoneNumber MessageBeingBuilt {
-            get { return result; }
+            get { return PrepareBuilder(); }
           }
           
           public override Builder Clear() {
-            result = new PhoneNumber();
+            result = DefaultInstance ?? new PhoneNumber();
+            builderIsReadOnly = true;
             return this;
           }
           
           public override Builder Clone() {
-            return new Builder().MergeFrom(result);
+            if (builderIsReadOnly) {
+              return new Builder(result);
+            } else {
+              return new Builder().MergeFrom(result);
+            }
           }
           
           public override pbd::MessageDescriptor DescriptorForType {
@@ -259,12 +286,11 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
           }
           
           public override PhoneNumber BuildPartial() {
-            if (result == null) {
-              throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+            if (builderIsReadOnly) {
+              return result;
             }
-            PhoneNumber returnMe = result;
-            result = null;
-            return returnMe;
+            builderIsReadOnly = true;
+            return result;
           }
           
           public override Builder MergeFrom(pb::IMessage other) {
@@ -278,6 +304,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
           
           public override Builder MergeFrom(PhoneNumber other) {
             if (other == global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.DefaultInstance) return this;
+            PrepareBuilder();
             if (other.HasNumber) {
               Number = other.Number;
             }
@@ -293,6 +320,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
           }
           
           public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+            PrepareBuilder();
             pb::UnknownFieldSet.Builder unknownFields = null;
             uint tag;
             string field_name;
@@ -361,11 +389,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
           }
           public Builder SetNumber(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasNumber = true;
             result.number_ = value;
             return this;
           }
           public Builder ClearNumber() {
+            PrepareBuilder();
             result.hasNumber = false;
             result.number_ = "";
             return this;
@@ -379,11 +409,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
             set { SetType(value); }
           }
           public Builder SetType(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneType value) {
+            PrepareBuilder();
             result.hasType = true;
             result.type_ = value;
             return this;
           }
           public Builder ClearType() {
+            PrepareBuilder();
             result.hasType = false;
             result.type_ = global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneType.HOME;
             return this;
@@ -527,7 +559,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(Person prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -537,21 +569,48 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new Person();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(Person cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      Person result = new Person();
+      bool builderIsReadOnly;
+      Person result;
+      
+      private Person PrepareBuilder() {
+        if (builderIsReadOnly) {
+          Person original = result;
+          result = new Person();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override Person MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new Person();
+        result = DefaultInstance ?? new Person();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -563,13 +622,12 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       
       public override Person BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.phone_.MakeReadOnly();
-        Person returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -583,6 +641,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       
       public override Builder MergeFrom(Person other) {
         if (other == global::Google.ProtocolBuffers.Examples.AddressBook.Person.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasName) {
           Name = other.Name;
         }
@@ -604,6 +663,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -672,11 +732,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       public Builder SetName(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasName = true;
         result.name_ = value;
         return this;
       }
       public Builder ClearName() {
+        PrepareBuilder();
         result.hasName = false;
         result.name_ = "";
         return this;
@@ -690,11 +752,13 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
         set { SetId(value); }
       }
       public Builder SetId(int value) {
+        PrepareBuilder();
         result.hasId = true;
         result.id_ = value;
         return this;
       }
       public Builder ClearId() {
+        PrepareBuilder();
         result.hasId = false;
         result.id_ = 0;
         return this;
@@ -709,18 +773,20 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       public Builder SetEmail(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasEmail = true;
         result.email_ = value;
         return this;
       }
       public Builder ClearEmail() {
+        PrepareBuilder();
         result.hasEmail = false;
         result.email_ = "";
         return this;
       }
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber> PhoneList {
-        get { return result.phone_; }
+        get { return PrepareBuilder().phone_; }
       }
       public int PhoneCount {
         get { return result.PhoneCount; }
@@ -730,29 +796,35 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       public Builder SetPhone(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.phone_[index] = value;
         return this;
       }
       public Builder SetPhone(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.phone_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddPhone(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.phone_.Add(value);
         return this;
       }
       public Builder AddPhone(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.phone_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangePhone(scg::IEnumerable<global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneNumber> values) {
+        PrepareBuilder();
         base.AddRange(values, result.phone_);
         return this;
       }
       public Builder ClearPhone() {
+        PrepareBuilder();
         result.phone_.Clear();
         return this;
       }
@@ -869,7 +941,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(AddressBook prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -879,21 +951,48 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new AddressBook();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(AddressBook cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      AddressBook result = new AddressBook();
+      bool builderIsReadOnly;
+      AddressBook result;
+      
+      private AddressBook PrepareBuilder() {
+        if (builderIsReadOnly) {
+          AddressBook original = result;
+          result = new AddressBook();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override AddressBook MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new AddressBook();
+        result = DefaultInstance ?? new AddressBook();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -905,13 +1004,12 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       
       public override AddressBook BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.person_.MakeReadOnly();
-        AddressBook returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -925,6 +1023,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       
       public override Builder MergeFrom(AddressBook other) {
         if (other == global::Google.ProtocolBuffers.Examples.AddressBook.AddressBook.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.person_.Count != 0) {
           base.AddRange(other.person_, result.person_);
         }
@@ -937,6 +1036,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -985,7 +1085,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.Examples.AddressBook.Person> PersonList {
-        get { return result.person_; }
+        get { return PrepareBuilder().person_; }
       }
       public int PersonCount {
         get { return result.PersonCount; }
@@ -995,29 +1095,35 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
       }
       public Builder SetPerson(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.person_[index] = value;
         return this;
       }
       public Builder SetPerson(int index, global::Google.ProtocolBuffers.Examples.AddressBook.Person.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.person_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddPerson(global::Google.ProtocolBuffers.Examples.AddressBook.Person value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.person_.Add(value);
         return this;
       }
       public Builder AddPerson(global::Google.ProtocolBuffers.Examples.AddressBook.Person.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.person_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangePerson(scg::IEnumerable<global::Google.ProtocolBuffers.Examples.AddressBook.Person> values) {
+        PrepareBuilder();
         base.AddRange(values, result.person_);
         return this;
       }
       public Builder ClearPerson() {
+        PrepareBuilder();
         result.person_.Clear();
         return this;
       }

+ 2 - 0
src/ProtoGen/EnumFieldGenerator.cs

@@ -70,11 +70,13 @@ namespace Google.ProtocolBuffers.ProtoGen
             writer.WriteLine("}");
             AddClsComplianceCheck(writer);
             writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.has{0} = true;", PropertyName);
             writer.WriteLine("  result.{0}_ = value;", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.has{0} = false;", PropertyName);
             writer.WriteLine("  result.{0}_ = {1};", Name, DefaultValue);
             writer.WriteLine("  return this;");

+ 4 - 0
src/ProtoGen/MessageFieldGenerator.cs

@@ -68,18 +68,21 @@ namespace Google.ProtocolBuffers.ProtoGen
             writer.WriteLine("}");
             writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
             AddNullCheck(writer);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.has{0} = true;", PropertyName);
             writer.WriteLine("  result.{0}_ = value;", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Set{0}({1}.Builder builderForValue) {{", PropertyName, TypeName);
             AddNullCheck(writer, "builderForValue");
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.has{0} = true;", PropertyName);
             writer.WriteLine("  result.{0}_ = builderForValue.Build();", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Merge{0}({1} value) {{", PropertyName, TypeName);
             AddNullCheck(writer);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  if (result.has{0} &&", PropertyName);
             writer.WriteLine("      result.{0}_ != {1}) {{", Name, DefaultValue);
             writer.WriteLine("      result.{0}_ = {1}.CreateBuilder(result.{0}_).MergeFrom(value).BuildPartial();", Name,
@@ -91,6 +94,7 @@ namespace Google.ProtocolBuffers.ProtoGen
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.has{0} = false;", PropertyName);
             writer.WriteLine("  result.{0}_ = {1};", Name, DefaultValue);
             writer.WriteLine("  return this;");

+ 43 - 12
src/ProtoGen/MessageGenerator.cs

@@ -551,7 +551,7 @@ namespace Google.ProtocolBuffers.ProtoGen
             writer.WriteLine("public override Builder ToBuilder() { return CreateBuilder(this); }");
             writer.WriteLine("public override Builder CreateBuilderForType() { return new Builder(); }");
             writer.WriteLine("public static Builder CreateBuilder({0} prototype) {{", ClassName);
-            writer.WriteLine("  return (Builder) new Builder().MergeFrom(prototype);");
+            writer.WriteLine("  return new Builder(prototype);");
             writer.WriteLine("}");
             writer.WriteLine();
             writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
@@ -582,21 +582,52 @@ namespace Google.ProtocolBuffers.ProtoGen
 
         private void GenerateCommonBuilderMethods(TextGenerator writer)
         {
-            writer.WriteLine("public Builder() {{}}", ClassAccessLevel);
+            //default constructor
+            writer.WriteLine("public Builder() {");
+            //Durring static initialization of message, DefaultInstance is expected to return null.
+            writer.WriteLine("  result = DefaultInstance ?? new {0}();", ClassName);
+            writer.WriteLine("  builderIsReadOnly = result == DefaultInstance;");
+            writer.WriteLine("}");
+            //clone constructor
+            writer.WriteLine("internal Builder({0} cloneFrom) {{", ClassName);
+            writer.WriteLine("  result = cloneFrom;");
+            writer.WriteLine("  builderIsReadOnly = true;");
+            writer.WriteLine("}");
+            writer.WriteLine();
+            writer.WriteLine("bool builderIsReadOnly;");
+            writer.WriteLine("{0} result;", ClassName);
+            writer.WriteLine();
+            writer.WriteLine("private {0} PrepareBuilder() {{", ClassName);
+            writer.WriteLine("  if (builderIsReadOnly) {");
+            writer.WriteLine("    {0} original = result;", ClassName);
+            writer.WriteLine("    result = new {0}();", ClassName);
+            writer.WriteLine("    builderIsReadOnly = false;");
+            writer.WriteLine("    MergeFrom(original);");
+            writer.WriteLine("  }");
+            writer.WriteLine("  return result;");
+            writer.WriteLine("}");
             writer.WriteLine();
-            writer.WriteLine("{0} result = new {0}();", ClassName);
+            writer.WriteLine("public override bool IsInitialized {");
+            writer.WriteLine("  get { return result.IsInitialized; }");
+            writer.WriteLine("}");
             writer.WriteLine();
             writer.WriteLine("protected override {0} MessageBeingBuilt {{", ClassName);
-            writer.WriteLine("  get { return result; }");
+            writer.WriteLine("  get { return PrepareBuilder(); }");
             writer.WriteLine("}");
             writer.WriteLine();
+            //Not actually expecting that DefaultInstance would ever be null here; however, we will ensure it does not break
             writer.WriteLine("public override Builder Clear() {");
-            writer.WriteLine("  result = new {0}();", ClassName);
+            writer.WriteLine("  result = DefaultInstance ?? new {0}();", ClassName);
+            writer.WriteLine("  builderIsReadOnly = true;");
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine();
             writer.WriteLine("public override Builder Clone() {");
-            writer.WriteLine("  return new Builder().MergeFrom(result);");
+            writer.WriteLine("  if (builderIsReadOnly) {");
+            writer.WriteLine("    return new Builder(result);");
+            writer.WriteLine("  } else {");
+            writer.WriteLine("    return new Builder().MergeFrom(result);");
+            writer.WriteLine("  }");
             writer.WriteLine("}");
             writer.WriteLine();
             if (!UseLiteRuntime)
@@ -613,17 +644,15 @@ namespace Google.ProtocolBuffers.ProtoGen
 
             writer.WriteLine("public override {0} BuildPartial() {{", ClassName);
             writer.Indent();
-            writer.WriteLine("if (result == null) {");
-            writer.WriteLine(
-                "  throw new global::System.InvalidOperationException(\"build() has already been called on this Builder\");");
+            writer.WriteLine("if (builderIsReadOnly) {");
+            writer.WriteLine("  return result;");
             writer.WriteLine("}");
             foreach (FieldDescriptor field in Descriptor.Fields)
             {
                 CreateFieldGenerator(field).GenerateBuildingCode(writer);
             }
-            writer.WriteLine("{0} returnMe = result;", ClassName);
-            writer.WriteLine("result = null;");
-            writer.WriteLine("return returnMe;");
+            writer.WriteLine("builderIsReadOnly = true;");
+            writer.WriteLine("return result;");
             writer.Outdent();
             writer.WriteLine("}");
             writer.WriteLine();
@@ -644,6 +673,7 @@ namespace Google.ProtocolBuffers.ProtoGen
                 // fields are set so we can skip the merge.
                 writer.Indent();
                 writer.WriteLine("if (other == {0}.DefaultInstance) return this;", FullClassName);
+                writer.WriteLine("PrepareBuilder();");
                 foreach (FieldDescriptor field in Descriptor.Fields)
                 {
                     CreateFieldGenerator(field).GenerateMergingCode(writer);
@@ -676,6 +706,7 @@ namespace Google.ProtocolBuffers.ProtoGen
             writer.WriteLine(
                 "public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {");
             writer.Indent();
+            writer.WriteLine("PrepareBuilder();");
             if (!UseLiteRuntime)
             {
                 writer.WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;");

+ 2 - 0
src/ProtoGen/PrimitiveFieldGenerator.cs

@@ -72,11 +72,13 @@ namespace Google.ProtocolBuffers.ProtoGen
             AddClsComplianceCheck(writer);
             writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
             AddNullCheck(writer);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.has{0} = true;", PropertyName);
             writer.WriteLine("  result.{0}_ = value;", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.has{0} = false;", PropertyName);
             writer.WriteLine("  result.{0}_ = {1};", Name, DefaultValue);
             writer.WriteLine("  return this;");

+ 5 - 1
src/ProtoGen/RepeatedEnumFieldGenerator.cs

@@ -71,7 +71,7 @@ namespace Google.ProtocolBuffers.ProtoGen
             // Note:  We can return the original list here, because we make it unmodifiable when we build
             // We return it via IPopsicleList so that collection initializers work more pleasantly.
             writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
-            writer.WriteLine("  get {{ return result.{0}_; }}", Name);
+            writer.WriteLine("  get {{ return PrepareBuilder().{0}_; }}", Name);
             writer.WriteLine("}");
             writer.WriteLine("public int {0}Count {{", PropertyName);
             writer.WriteLine("  get {{ return result.{0}Count; }}", PropertyName);
@@ -80,18 +80,22 @@ namespace Google.ProtocolBuffers.ProtoGen
             writer.WriteLine("  return result.Get{0}(index);", PropertyName);
             writer.WriteLine("}");
             writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_[index] = value;", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_.Add(value);", Name, TypeName);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  base.AddRange(values, result.{0}_);", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_.Clear();", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");

+ 7 - 1
src/ProtoGen/RepeatedMessageFieldGenerator.cs

@@ -67,7 +67,7 @@ namespace Google.ProtocolBuffers.ProtoGen
             // Note:  We can return the original list here, because we make it unmodifiable when we build
             // We return it via IPopsicleList so that collection initializers work more pleasantly.
             writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
-            writer.WriteLine("  get {{ return result.{0}_; }}", Name);
+            writer.WriteLine("  get {{ return PrepareBuilder().{0}_; }}", Name);
             writer.WriteLine("}");
             writer.WriteLine("public int {0}Count {{", PropertyName);
             writer.WriteLine("  get {{ return result.{0}Count; }}", PropertyName);
@@ -77,31 +77,37 @@ namespace Google.ProtocolBuffers.ProtoGen
             writer.WriteLine("}");
             writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
             AddNullCheck(writer);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_[index] = value;", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             // Extra overload for builder (just on messages)
             writer.WriteLine("public Builder Set{0}(int index, {1}.Builder builderForValue) {{", PropertyName, TypeName);
             AddNullCheck(writer, "builderForValue");
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_[index] = builderForValue.Build();", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
             AddNullCheck(writer);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_.Add(value);", Name, TypeName);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             // Extra overload for builder (just on messages)
             writer.WriteLine("public Builder Add{0}({1}.Builder builderForValue) {{", PropertyName, TypeName);
             AddNullCheck(writer, "builderForValue");
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_.Add(builderForValue.Build());", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  base.AddRange(values, result.{0}_);", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_.Clear();", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");

+ 5 - 1
src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs

@@ -74,7 +74,7 @@ namespace Google.ProtocolBuffers.ProtoGen
             // We return it via IPopsicleList so that collection initializers work more pleasantly.
             AddClsComplianceCheck(writer);
             writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
-            writer.WriteLine("  get {{ return result.{0}_; }}", Name);
+            writer.WriteLine("  get {{ return PrepareBuilder().{0}_; }}", Name);
             writer.WriteLine("}");
             writer.WriteLine("public int {0}Count {{", PropertyName);
             writer.WriteLine("  get {{ return result.{0}Count; }}", PropertyName);
@@ -86,21 +86,25 @@ namespace Google.ProtocolBuffers.ProtoGen
             AddClsComplianceCheck(writer);
             writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
             AddNullCheck(writer);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_[index] = value;", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             AddClsComplianceCheck(writer);
             writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
             AddNullCheck(writer);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_.Add(value);", Name, TypeName);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             AddClsComplianceCheck(writer);
             writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  base.AddRange(values, result.{0}_);", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");
             writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+            writer.WriteLine("  PrepareBuilder();");
             writer.WriteLine("  result.{0}_.Clear();", Name);
             writer.WriteLine("  return this;");
             writer.WriteLine("}");

+ 0 - 16
src/ProtocolBuffers.Test/GeneratedMessageTest.cs

@@ -111,22 +111,6 @@ namespace Google.ProtocolBuffers
             }
         }
 
-        [Test]
-        public void DoubleBuildError()
-        {
-            TestAllTypes.Builder builder = new TestAllTypes.Builder();
-            builder.Build();
-            try
-            {
-                builder.Build();
-                Assert.Fail("Should have thrown exception.");
-            }
-            catch (InvalidOperationException)
-            {
-                // Success.
-            }
-        }
-
         [Test]
         public void DefaultInstance()
         {

+ 1 - 0
src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj

@@ -105,6 +105,7 @@
     <Compile Include="NameHelpersTest.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ReflectionTester.cs" />
+    <Compile Include="ReusableBuilderTest.cs" />
     <Compile Include="ServiceTest.cs" />
     <Compile Include="TestProtos\UnitTestCSharpOptionsProtoFile.cs" />
     <Compile Include="TestProtos\UnitTestCustomOptionsProtoFile.cs" />

+ 117 - 0
src/ProtocolBuffers.Test/ReusableBuilderTest.cs

@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NUnit.Framework;
+using Google.ProtocolBuffers.TestProtos;
+
+namespace Google.ProtocolBuffers
+{
+    [TestFixture]
+    public class ReusableBuilderTest
+    {
+        [Test]
+        public void TestUnmodifiedDefaultInstance()
+        {
+            //Simply calling ToBuilder().Build() no longer creates a copy of the message
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void BuildMultipleWithoutChange()
+        {
+            //Calling Build() or BuildPartial() does not require a copy of the message
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            builder.SetDefaultBool(true);
+
+            TestAllTypes first = builder.BuildPartial();
+            //Still the same instance?
+            Assert.IsTrue(ReferenceEquals(first, builder.Build()));
+            //Still the same instance?
+            Assert.IsTrue(ReferenceEquals(first, builder.BuildPartial().ToBuilder().Build()));
+        }
+
+        [Test]
+        public void MergeFromDefaultInstance()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.MergeFrom(TestAllTypes.DefaultInstance);
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void BuildNewBuilderIsDefaultInstance()
+        {
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, new TestAllTypes.Builder().Build()));
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, TestAllTypes.CreateBuilder().Build()));
+            //last test, if you clear a builder it reverts to default instance
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance,
+                TestAllTypes.CreateBuilder().SetOptionalBool(true).Build().ToBuilder().Clear().Build()));
+        }
+
+        [Test]
+        public void CloneOnChangePrimitive()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.SetDefaultBool(true);
+            Assert.IsFalse(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void CloneOnAddRepeatedBool()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.AddRepeatedBool(true);
+            Assert.IsFalse(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void CloneOnChangeMessage()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.SetOptionalForeignMessage(new ForeignMessage.Builder());
+            Assert.IsFalse(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void CloneOnClearMessage()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.ClearOptionalForeignMessage();
+            Assert.IsFalse(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void CloneOnAddRepeatedForeignMessage()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.AddRepeatedForeignMessage(ForeignMessage.DefaultInstance);
+            Assert.IsFalse(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void CloneOnChangeEnumValue()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.SetOptionalForeignEnum(ForeignEnum.FOREIGN_BAR);
+            Assert.IsFalse(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+        [Test]
+        public void CloneOnAddRepeatedForeignEnum()
+        {
+            TestAllTypes.Builder builder = TestAllTypes.DefaultInstance.ToBuilder();
+            Assert.IsTrue(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+            builder.AddRepeatedForeignEnum(ForeignEnum.FOREIGN_BAR);
+            Assert.IsFalse(ReferenceEquals(TestAllTypes.DefaultInstance, builder.Build()));
+        }
+
+    }
+}

+ 45 - 11
src/ProtocolBuffers.Test/TestProtos/UnitTestCSharpOptionsProtoFile.cs

@@ -190,7 +190,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(OptionsMessage prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -200,21 +200,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new OptionsMessage();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(OptionsMessage cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      OptionsMessage result;
       
-      OptionsMessage result = new OptionsMessage();
+      private OptionsMessage PrepareBuilder() {
+        if (builderIsReadOnly) {
+          OptionsMessage original = result;
+          result = new OptionsMessage();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override OptionsMessage MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new OptionsMessage();
+        result = DefaultInstance ?? new OptionsMessage();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -226,12 +253,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override OptionsMessage BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        OptionsMessage returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -245,6 +271,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(OptionsMessage other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.OptionsMessage.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasNormal) {
           Normal = other.Normal;
         }
@@ -263,6 +290,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -327,11 +355,13 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetNormal(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasNormal = true;
         result.normal_ = value;
         return this;
       }
       public Builder ClearNormal() {
+        PrepareBuilder();
         result.hasNormal = false;
         result.normal_ = "";
         return this;
@@ -346,11 +376,13 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetOptionsMessage_(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasOptionsMessage_ = true;
         result.optionsMessage_ = value;
         return this;
       }
       public Builder ClearOptionsMessage_() {
+        PrepareBuilder();
         result.hasOptionsMessage_ = false;
         result.optionsMessage_ = "";
         return this;
@@ -365,11 +397,13 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetCustomName(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasCustomName = true;
         result.customized_ = value;
         return this;
       }
       public Builder ClearCustomName() {
+        PrepareBuilder();
         result.hasCustomName = false;
         result.customized_ = "";
         return this;

File diff suppressed because it is too large
+ 425 - 116
src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs


+ 50 - 12
src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs

@@ -186,7 +186,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestEmbedOptimizedForSize prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -196,21 +196,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestEmbedOptimizedForSize();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestEmbedOptimizedForSize cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      TestEmbedOptimizedForSize result;
       
-      TestEmbedOptimizedForSize result = new TestEmbedOptimizedForSize();
+      private TestEmbedOptimizedForSize PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestEmbedOptimizedForSize original = result;
+          result = new TestEmbedOptimizedForSize();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestEmbedOptimizedForSize MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestEmbedOptimizedForSize();
+        result = DefaultInstance ?? new TestEmbedOptimizedForSize();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -222,13 +249,12 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestEmbedOptimizedForSize BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.repeatedMessage_.MakeReadOnly();
-        TestEmbedOptimizedForSize returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -242,6 +268,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestEmbedOptimizedForSize other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestEmbedOptimizedForSize.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasOptionalMessage) {
           MergeOptionalMessage(other.OptionalMessage);
         }
@@ -257,6 +284,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -322,18 +350,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetOptionalMessage(global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasOptionalMessage = true;
         result.optionalMessage_ = value;
         return this;
       }
       public Builder SetOptionalMessage(global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasOptionalMessage = true;
         result.optionalMessage_ = builderForValue.Build();
         return this;
       }
       public Builder MergeOptionalMessage(global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasOptionalMessage &&
             result.optionalMessage_ != global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.DefaultInstance) {
             result.optionalMessage_ = global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.CreateBuilder(result.optionalMessage_).MergeFrom(value).BuildPartial();
@@ -344,13 +375,14 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearOptionalMessage() {
+        PrepareBuilder();
         result.hasOptionalMessage = false;
         result.optionalMessage_ = global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.DefaultInstance;
         return this;
       }
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize> RepeatedMessageList {
-        get { return result.repeatedMessage_; }
+        get { return PrepareBuilder().repeatedMessage_; }
       }
       public int RepeatedMessageCount {
         get { return result.RepeatedMessageCount; }
@@ -360,29 +392,35 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetRepeatedMessage(int index, global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.repeatedMessage_[index] = value;
         return this;
       }
       public Builder SetRepeatedMessage(int index, global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.repeatedMessage_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddRepeatedMessage(global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.repeatedMessage_.Add(value);
         return this;
       }
       public Builder AddRepeatedMessage(global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.repeatedMessage_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangeRepeatedMessage(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize> values) {
+        PrepareBuilder();
         base.AddRange(values, result.repeatedMessage_);
         return this;
       }
       public Builder ClearRepeatedMessage() {
+        PrepareBuilder();
         result.repeatedMessage_.Clear();
         return this;
       }

+ 164 - 44
src/ProtocolBuffers.Test/TestProtos/UnitTestExtrasIssuesProtoFile.cs

@@ -175,7 +175,7 @@ namespace UnitTest.Issues.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(A prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -185,21 +185,48 @@ namespace UnitTest.Issues.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new A();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(A cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      A result;
       
-      A result = new A();
+      private A PrepareBuilder() {
+        if (builderIsReadOnly) {
+          A original = result;
+          result = new A();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override A MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new A();
+        result = DefaultInstance ?? new A();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -211,12 +238,11 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override A BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        A returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -230,6 +256,7 @@ namespace UnitTest.Issues.TestProtos {
       
       public override Builder MergeFrom(A other) {
         if (other == global::UnitTest.Issues.TestProtos.A.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasA_) {
           A_ = other.A_;
         }
@@ -242,6 +269,7 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -297,11 +325,13 @@ namespace UnitTest.Issues.TestProtos {
         set { SetA_(value); }
       }
       public Builder SetA_(int value) {
+        PrepareBuilder();
         result.hasA_ = true;
         result.a_ = value;
         return this;
       }
       public Builder ClearA_() {
+        PrepareBuilder();
         result.hasA_ = false;
         result.a_ = 0;
         return this;
@@ -414,7 +444,7 @@ namespace UnitTest.Issues.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(B prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -424,21 +454,48 @@ namespace UnitTest.Issues.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new B();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(B cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      B result;
       
-      B result = new B();
+      private B PrepareBuilder() {
+        if (builderIsReadOnly) {
+          B original = result;
+          result = new B();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override B MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new B();
+        result = DefaultInstance ?? new B();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -450,12 +507,11 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override B BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        B returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -469,6 +525,7 @@ namespace UnitTest.Issues.TestProtos {
       
       public override Builder MergeFrom(B other) {
         if (other == global::UnitTest.Issues.TestProtos.B.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasB_) {
           B_ = other.B_;
         }
@@ -481,6 +538,7 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -536,11 +594,13 @@ namespace UnitTest.Issues.TestProtos {
         set { SetB_(value); }
       }
       public Builder SetB_(int value) {
+        PrepareBuilder();
         result.hasB_ = true;
         result.b_ = value;
         return this;
       }
       public Builder ClearB_() {
+        PrepareBuilder();
         result.hasB_ = false;
         result.b_ = 0;
         return this;
@@ -653,7 +713,7 @@ namespace UnitTest.Issues.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(AB prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -663,21 +723,48 @@ namespace UnitTest.Issues.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new AB();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(AB cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      AB result;
       
-      AB result = new AB();
+      private AB PrepareBuilder() {
+        if (builderIsReadOnly) {
+          AB original = result;
+          result = new AB();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override AB MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new AB();
+        result = DefaultInstance ?? new AB();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -689,12 +776,11 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override AB BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        AB returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -708,6 +794,7 @@ namespace UnitTest.Issues.TestProtos {
       
       public override Builder MergeFrom(AB other) {
         if (other == global::UnitTest.Issues.TestProtos.AB.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasAB_) {
           AB_ = other.AB_;
         }
@@ -720,6 +807,7 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -775,11 +863,13 @@ namespace UnitTest.Issues.TestProtos {
         set { SetAB_(value); }
       }
       public Builder SetAB_(int value) {
+        PrepareBuilder();
         result.hasAB_ = true;
         result.aB_ = value;
         return this;
       }
       public Builder ClearAB_() {
+        PrepareBuilder();
         result.hasAB_ = false;
         result.aB_ = 0;
         return this;
@@ -894,7 +984,7 @@ namespace UnitTest.Issues.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(NumberField prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -904,21 +994,48 @@ namespace UnitTest.Issues.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new NumberField();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(NumberField cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      NumberField result;
       
-      NumberField result = new NumberField();
+      private NumberField PrepareBuilder() {
+        if (builderIsReadOnly) {
+          NumberField original = result;
+          result = new NumberField();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override NumberField MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new NumberField();
+        result = DefaultInstance ?? new NumberField();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -930,12 +1047,11 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override NumberField BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        NumberField returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -949,6 +1065,7 @@ namespace UnitTest.Issues.TestProtos {
       
       public override Builder MergeFrom(NumberField other) {
         if (other == global::UnitTest.Issues.TestProtos.NumberField.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.Has_01) {
           _01 = other._01;
         }
@@ -961,6 +1078,7 @@ namespace UnitTest.Issues.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1018,11 +1136,13 @@ namespace UnitTest.Issues.TestProtos {
       }
       [global::System.CLSCompliant(false)]
       public Builder Set_01(int value) {
+        PrepareBuilder();
         result.has_01 = true;
         result._01_ = value;
         return this;
       }
       public Builder Clear_01() {
+        PrepareBuilder();
         result.has_01 = false;
         result._01_ = 0;
         return this;

File diff suppressed because it is too large
+ 195 - 23
src/ProtocolBuffers.Test/TestProtos/UnitTestGoogleSizeProtoFile.cs


File diff suppressed because it is too large
+ 195 - 23
src/ProtocolBuffers.Test/TestProtos/UnitTestGoogleSpeedProtoFile.cs


+ 41 - 11
src/ProtocolBuffers.Test/TestProtos/UnitTestImportLiteProtoFile.cs

@@ -150,7 +150,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(ImportMessageLite prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -160,21 +160,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new ImportMessageLite();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(ImportMessageLite cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      ImportMessageLite result;
       
-      ImportMessageLite result = new ImportMessageLite();
+      private ImportMessageLite PrepareBuilder() {
+        if (builderIsReadOnly) {
+          ImportMessageLite original = result;
+          result = new ImportMessageLite();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override ImportMessageLite MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new ImportMessageLite();
+        result = DefaultInstance ?? new ImportMessageLite();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override ImportMessageLite DefaultInstanceForType {
@@ -182,12 +209,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override ImportMessageLite BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        ImportMessageLite returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessageLite other) {
@@ -201,6 +227,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(ImportMessageLite other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.ImportMessageLite.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasD) {
           D = other.D;
         }
@@ -212,6 +239,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         uint tag;
         string field_name;
         while (input.ReadTag(out tag, out field_name)) {
@@ -254,11 +282,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetD(value); }
       }
       public Builder SetD(int value) {
+        PrepareBuilder();
         result.hasD = true;
         result.d_ = value;
         return this;
       }
       public Builder ClearD() {
+        PrepareBuilder();
         result.hasD = false;
         result.d_ = 0;
         return this;

+ 41 - 11
src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs

@@ -169,7 +169,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(ImportMessage prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -179,21 +179,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new ImportMessage();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(ImportMessage cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      ImportMessage result;
       
-      ImportMessage result = new ImportMessage();
+      private ImportMessage PrepareBuilder() {
+        if (builderIsReadOnly) {
+          ImportMessage original = result;
+          result = new ImportMessage();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override ImportMessage MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new ImportMessage();
+        result = DefaultInstance ?? new ImportMessage();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -205,12 +232,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override ImportMessage BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        ImportMessage returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -224,6 +250,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(ImportMessage other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.ImportMessage.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasD) {
           D = other.D;
         }
@@ -236,6 +263,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -291,11 +319,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetD(value); }
       }
       public Builder SetD(int value) {
+        PrepareBuilder();
         result.hasD = true;
         result.d_ = value;
         return this;
       }
       public Builder ClearD() {
+        PrepareBuilder();
         result.hasD = false;
         result.d_ = 0;
         return this;

+ 253 - 67
src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs

@@ -189,7 +189,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestMessageSet prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -199,21 +199,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestMessageSet();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestMessageSet cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestMessageSet result = new TestMessageSet();
+      bool builderIsReadOnly;
+      TestMessageSet result;
+      
+      private TestMessageSet PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestMessageSet original = result;
+          result = new TestMessageSet();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestMessageSet MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestMessageSet();
+        result = DefaultInstance ?? new TestMessageSet();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -225,12 +252,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestMessageSet BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestMessageSet returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -244,6 +270,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestMessageSet other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestMessageSet.DefaultInstance) return this;
+        PrepareBuilder();
           this.MergeExtensionFields(other);
         this.MergeUnknownFields(other.UnknownFields);
         return this;
@@ -254,6 +281,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -404,7 +432,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestMessageSetContainer prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -414,21 +442,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestMessageSetContainer();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestMessageSetContainer cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestMessageSetContainer result = new TestMessageSetContainer();
+      bool builderIsReadOnly;
+      TestMessageSetContainer result;
+      
+      private TestMessageSetContainer PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestMessageSetContainer original = result;
+          result = new TestMessageSetContainer();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestMessageSetContainer MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestMessageSetContainer();
+        result = DefaultInstance ?? new TestMessageSetContainer();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -440,12 +495,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestMessageSetContainer BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestMessageSetContainer returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -459,6 +513,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestMessageSetContainer other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestMessageSetContainer.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasMessageSet) {
           MergeMessageSet(other.MessageSet);
         }
@@ -471,6 +526,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -532,18 +588,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetMessageSet(global::Google.ProtocolBuffers.TestProtos.TestMessageSet value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasMessageSet = true;
         result.messageSet_ = value;
         return this;
       }
       public Builder SetMessageSet(global::Google.ProtocolBuffers.TestProtos.TestMessageSet.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasMessageSet = true;
         result.messageSet_ = builderForValue.Build();
         return this;
       }
       public Builder MergeMessageSet(global::Google.ProtocolBuffers.TestProtos.TestMessageSet value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasMessageSet &&
             result.messageSet_ != global::Google.ProtocolBuffers.TestProtos.TestMessageSet.DefaultInstance) {
             result.messageSet_ = global::Google.ProtocolBuffers.TestProtos.TestMessageSet.CreateBuilder(result.messageSet_).MergeFrom(value).BuildPartial();
@@ -554,6 +613,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearMessageSet() {
+        PrepareBuilder();
         result.hasMessageSet = false;
         result.messageSet_ = global::Google.ProtocolBuffers.TestProtos.TestMessageSet.DefaultInstance;
         return this;
@@ -668,7 +728,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestMessageSetExtension1 prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -678,21 +738,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestMessageSetExtension1();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestMessageSetExtension1 cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestMessageSetExtension1 result = new TestMessageSetExtension1();
+      bool builderIsReadOnly;
+      TestMessageSetExtension1 result;
+      
+      private TestMessageSetExtension1 PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestMessageSetExtension1 original = result;
+          result = new TestMessageSetExtension1();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestMessageSetExtension1 MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestMessageSetExtension1();
+        result = DefaultInstance ?? new TestMessageSetExtension1();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -704,12 +791,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestMessageSetExtension1 BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestMessageSetExtension1 returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -723,6 +809,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestMessageSetExtension1 other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestMessageSetExtension1.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasI) {
           I = other.I;
         }
@@ -735,6 +822,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -790,11 +878,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetI(value); }
       }
       public Builder SetI(int value) {
+        PrepareBuilder();
         result.hasI = true;
         result.i_ = value;
         return this;
       }
       public Builder ClearI() {
+        PrepareBuilder();
         result.hasI = false;
         result.i_ = 0;
         return this;
@@ -909,7 +999,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestMessageSetExtension2 prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -919,21 +1009,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestMessageSetExtension2();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestMessageSetExtension2 cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestMessageSetExtension2 result = new TestMessageSetExtension2();
+      bool builderIsReadOnly;
+      TestMessageSetExtension2 result;
+      
+      private TestMessageSetExtension2 PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestMessageSetExtension2 original = result;
+          result = new TestMessageSetExtension2();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestMessageSetExtension2 MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestMessageSetExtension2();
+        result = DefaultInstance ?? new TestMessageSetExtension2();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -945,12 +1062,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestMessageSetExtension2 BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestMessageSetExtension2 returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -964,6 +1080,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestMessageSetExtension2 other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestMessageSetExtension2.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasStr) {
           Str = other.Str;
         }
@@ -976,6 +1093,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1032,11 +1150,13 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetStr(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasStr = true;
         result.str_ = value;
         return this;
       }
       public Builder ClearStr() {
+        PrepareBuilder();
         result.hasStr = false;
         result.str_ = "";
         return this;
@@ -1199,7 +1319,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         public override Builder ToBuilder() { return CreateBuilder(this); }
         public override Builder CreateBuilderForType() { return new Builder(); }
         public static Builder CreateBuilder(Item prototype) {
-          return (Builder) new Builder().MergeFrom(prototype);
+          return new Builder(prototype);
         }
         
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1209,21 +1329,48 @@ namespace Google.ProtocolBuffers.TestProtos {
           protected override Builder ThisBuilder {
             get { return this; }
           }
-          public Builder() {}
+          public Builder() {
+            result = DefaultInstance ?? new Item();
+            builderIsReadOnly = result == DefaultInstance;
+          }
+          internal Builder(Item cloneFrom) {
+            result = cloneFrom;
+            builderIsReadOnly = true;
+          }
           
-          Item result = new Item();
+          bool builderIsReadOnly;
+          Item result;
+          
+          private Item PrepareBuilder() {
+            if (builderIsReadOnly) {
+              Item original = result;
+              result = new Item();
+              builderIsReadOnly = false;
+              MergeFrom(original);
+            }
+            return result;
+          }
+          
+          public override bool IsInitialized {
+            get { return result.IsInitialized; }
+          }
           
           protected override Item MessageBeingBuilt {
-            get { return result; }
+            get { return PrepareBuilder(); }
           }
           
           public override Builder Clear() {
-            result = new Item();
+            result = DefaultInstance ?? new Item();
+            builderIsReadOnly = true;
             return this;
           }
           
           public override Builder Clone() {
-            return new Builder().MergeFrom(result);
+            if (builderIsReadOnly) {
+              return new Builder(result);
+            } else {
+              return new Builder().MergeFrom(result);
+            }
           }
           
           public override pbd::MessageDescriptor DescriptorForType {
@@ -1235,12 +1382,11 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Item BuildPartial() {
-            if (result == null) {
-              throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+            if (builderIsReadOnly) {
+              return result;
             }
-            Item returnMe = result;
-            result = null;
-            return returnMe;
+            builderIsReadOnly = true;
+            return result;
           }
           
           public override Builder MergeFrom(pb::IMessage other) {
@@ -1254,6 +1400,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           
           public override Builder MergeFrom(Item other) {
             if (other == global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item.DefaultInstance) return this;
+            PrepareBuilder();
             if (other.HasTypeId) {
               TypeId = other.TypeId;
             }
@@ -1269,6 +1416,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+            PrepareBuilder();
             pb::UnknownFieldSet.Builder unknownFields = null;
             uint tag;
             string field_name;
@@ -1328,11 +1476,13 @@ namespace Google.ProtocolBuffers.TestProtos {
             set { SetTypeId(value); }
           }
           public Builder SetTypeId(int value) {
+            PrepareBuilder();
             result.hasTypeId = true;
             result.typeId_ = value;
             return this;
           }
           public Builder ClearTypeId() {
+            PrepareBuilder();
             result.hasTypeId = false;
             result.typeId_ = 0;
             return this;
@@ -1347,11 +1497,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetMessage(pb::ByteString value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasMessage = true;
             result.message_ = value;
             return this;
           }
           public Builder ClearMessage() {
+            PrepareBuilder();
             result.hasMessage = false;
             result.message_ = pb::ByteString.Empty;
             return this;
@@ -1442,7 +1594,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(RawMessageSet prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1452,21 +1604,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new RawMessageSet();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(RawMessageSet cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      RawMessageSet result = new RawMessageSet();
+      bool builderIsReadOnly;
+      RawMessageSet result;
+      
+      private RawMessageSet PrepareBuilder() {
+        if (builderIsReadOnly) {
+          RawMessageSet original = result;
+          result = new RawMessageSet();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override RawMessageSet MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new RawMessageSet();
+        result = DefaultInstance ?? new RawMessageSet();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -1478,13 +1657,12 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override RawMessageSet BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.item_.MakeReadOnly();
-        RawMessageSet returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -1498,6 +1676,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(RawMessageSet other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.RawMessageSet.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.item_.Count != 0) {
           base.AddRange(other.item_, result.item_);
         }
@@ -1510,6 +1689,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1558,7 +1738,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item> ItemList {
-        get { return result.item_; }
+        get { return PrepareBuilder().item_; }
       }
       public int ItemCount {
         get { return result.ItemCount; }
@@ -1568,29 +1748,35 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetItem(int index, global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.item_[index] = value;
         return this;
       }
       public Builder SetItem(int index, global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.item_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddItem(global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.item_.Add(value);
         return this;
       }
       public Builder AddItem(global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.item_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangeItem(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.RawMessageSet.Types.Item> values) {
+        PrepareBuilder();
         base.AddRange(values, result.item_);
         return this;
       }
       public Builder ClearItem() {
+        PrepareBuilder();
         result.item_.Clear();
         return this;
       }

+ 41 - 11
src/ProtocolBuffers.Test/TestProtos/UnitTestNoGenericServicesProtoFile.cs

@@ -183,7 +183,7 @@ namespace Google.ProtocolBuffers.TestProtos.NoGenericService {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestMessage prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -193,21 +193,48 @@ namespace Google.ProtocolBuffers.TestProtos.NoGenericService {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestMessage();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestMessage cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      TestMessage result;
       
-      TestMessage result = new TestMessage();
+      private TestMessage PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestMessage original = result;
+          result = new TestMessage();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestMessage MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestMessage();
+        result = DefaultInstance ?? new TestMessage();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -219,12 +246,11 @@ namespace Google.ProtocolBuffers.TestProtos.NoGenericService {
       }
       
       public override TestMessage BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestMessage returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -238,6 +264,7 @@ namespace Google.ProtocolBuffers.TestProtos.NoGenericService {
       
       public override Builder MergeFrom(TestMessage other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.NoGenericService.TestMessage.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasA) {
           A = other.A;
         }
@@ -251,6 +278,7 @@ namespace Google.ProtocolBuffers.TestProtos.NoGenericService {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -306,11 +334,13 @@ namespace Google.ProtocolBuffers.TestProtos.NoGenericService {
         set { SetA(value); }
       }
       public Builder SetA(int value) {
+        PrepareBuilder();
         result.hasA = true;
         result.a_ = value;
         return this;
       }
       public Builder ClearA() {
+        PrepareBuilder();
         result.hasA = false;
         result.a_ = 0;
         return this;

+ 123 - 33
src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs

@@ -164,7 +164,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestOptimizedForSize prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -174,21 +174,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestOptimizedForSize();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestOptimizedForSize cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestOptimizedForSize result = new TestOptimizedForSize();
+      bool builderIsReadOnly;
+      TestOptimizedForSize result;
+      
+      private TestOptimizedForSize PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestOptimizedForSize original = result;
+          result = new TestOptimizedForSize();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestOptimizedForSize MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestOptimizedForSize();
+        result = DefaultInstance ?? new TestOptimizedForSize();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -200,12 +227,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestOptimizedForSize BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestOptimizedForSize returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       
@@ -217,11 +243,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetI(value); }
       }
       public Builder SetI(int value) {
+        PrepareBuilder();
         result.hasI = true;
         result.i_ = value;
         return this;
       }
       public Builder ClearI() {
+        PrepareBuilder();
         result.hasI = false;
         result.i_ = 0;
         return this;
@@ -236,18 +264,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetMsg(global::Google.ProtocolBuffers.TestProtos.ForeignMessage value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasMsg = true;
         result.msg_ = value;
         return this;
       }
       public Builder SetMsg(global::Google.ProtocolBuffers.TestProtos.ForeignMessage.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasMsg = true;
         result.msg_ = builderForValue.Build();
         return this;
       }
       public Builder MergeMsg(global::Google.ProtocolBuffers.TestProtos.ForeignMessage value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasMsg &&
             result.msg_ != global::Google.ProtocolBuffers.TestProtos.ForeignMessage.DefaultInstance) {
             result.msg_ = global::Google.ProtocolBuffers.TestProtos.ForeignMessage.CreateBuilder(result.msg_).MergeFrom(value).BuildPartial();
@@ -258,6 +289,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearMsg() {
+        PrepareBuilder();
         result.hasMsg = false;
         result.msg_ = global::Google.ProtocolBuffers.TestProtos.ForeignMessage.DefaultInstance;
         return this;
@@ -337,7 +369,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestRequiredOptimizedForSize prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -347,21 +379,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestRequiredOptimizedForSize();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestRequiredOptimizedForSize cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestRequiredOptimizedForSize result = new TestRequiredOptimizedForSize();
+      bool builderIsReadOnly;
+      TestRequiredOptimizedForSize result;
+      
+      private TestRequiredOptimizedForSize PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestRequiredOptimizedForSize original = result;
+          result = new TestRequiredOptimizedForSize();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestRequiredOptimizedForSize MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestRequiredOptimizedForSize();
+        result = DefaultInstance ?? new TestRequiredOptimizedForSize();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -373,12 +432,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestRequiredOptimizedForSize BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestRequiredOptimizedForSize returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       
@@ -390,11 +448,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetX(value); }
       }
       public Builder SetX(int value) {
+        PrepareBuilder();
         result.hasX = true;
         result.x_ = value;
         return this;
       }
       public Builder ClearX() {
+        PrepareBuilder();
         result.hasX = false;
         result.x_ = 0;
         return this;
@@ -474,7 +534,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestOptionalOptimizedForSize prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -484,21 +544,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestOptionalOptimizedForSize();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestOptionalOptimizedForSize cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestOptionalOptimizedForSize result = new TestOptionalOptimizedForSize();
+      bool builderIsReadOnly;
+      TestOptionalOptimizedForSize result;
+      
+      private TestOptionalOptimizedForSize PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestOptionalOptimizedForSize original = result;
+          result = new TestOptionalOptimizedForSize();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestOptionalOptimizedForSize MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestOptionalOptimizedForSize();
+        result = DefaultInstance ?? new TestOptionalOptimizedForSize();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -510,12 +597,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestOptionalOptimizedForSize BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestOptionalOptimizedForSize returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       
@@ -528,18 +614,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetO(global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasO = true;
         result.o_ = value;
         return this;
       }
       public Builder SetO(global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasO = true;
         result.o_ = builderForValue.Build();
         return this;
       }
       public Builder MergeO(global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasO &&
             result.o_ != global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.DefaultInstance) {
             result.o_ = global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.CreateBuilder(result.o_).MergeFrom(value).BuildPartial();
@@ -550,6 +639,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearO() {
+        PrepareBuilder();
         result.hasO = false;
         result.o_ = global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.DefaultInstance;
         return this;

File diff suppressed because it is too large
+ 249 - 51
src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs


+ 181 - 47
src/ProtocolBuffers.Test/TestProtos/UnitTestRpcInterop.cs

@@ -188,7 +188,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(SearchRequest prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -198,21 +198,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new SearchRequest();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(SearchRequest cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      SearchRequest result;
       
-      SearchRequest result = new SearchRequest();
+      private SearchRequest PrepareBuilder() {
+        if (builderIsReadOnly) {
+          SearchRequest original = result;
+          result = new SearchRequest();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override SearchRequest MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new SearchRequest();
+        result = DefaultInstance ?? new SearchRequest();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -224,13 +251,12 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override SearchRequest BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.criteria_.MakeReadOnly();
-        SearchRequest returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -244,6 +270,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(SearchRequest other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.SearchRequest.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.criteria_.Count != 0) {
           base.AddRange(other.criteria_, result.criteria_);
         }
@@ -256,6 +283,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -304,7 +332,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       
       public pbc::IPopsicleList<string> CriteriaList {
-        get { return result.criteria_; }
+        get { return PrepareBuilder().criteria_; }
       }
       public int CriteriaCount {
         get { return result.CriteriaCount; }
@@ -314,19 +342,23 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetCriteria(int index, string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.criteria_[index] = value;
         return this;
       }
       public Builder AddCriteria(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.criteria_.Add(value);
         return this;
       }
       public Builder AddRangeCriteria(scg::IEnumerable<string> values) {
+        PrepareBuilder();
         base.AddRange(values, result.criteria_);
         return this;
       }
       public Builder ClearCriteria() {
+        PrepareBuilder();
         result.criteria_.Clear();
         return this;
       }
@@ -487,7 +519,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         public override Builder ToBuilder() { return CreateBuilder(this); }
         public override Builder CreateBuilderForType() { return new Builder(); }
         public static Builder CreateBuilder(ResultItem prototype) {
-          return (Builder) new Builder().MergeFrom(prototype);
+          return new Builder(prototype);
         }
         
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -497,21 +529,48 @@ namespace Google.ProtocolBuffers.TestProtos {
           protected override Builder ThisBuilder {
             get { return this; }
           }
-          public Builder() {}
+          public Builder() {
+            result = DefaultInstance ?? new ResultItem();
+            builderIsReadOnly = result == DefaultInstance;
+          }
+          internal Builder(ResultItem cloneFrom) {
+            result = cloneFrom;
+            builderIsReadOnly = true;
+          }
+          
+          bool builderIsReadOnly;
+          ResultItem result;
           
-          ResultItem result = new ResultItem();
+          private ResultItem PrepareBuilder() {
+            if (builderIsReadOnly) {
+              ResultItem original = result;
+              result = new ResultItem();
+              builderIsReadOnly = false;
+              MergeFrom(original);
+            }
+            return result;
+          }
+          
+          public override bool IsInitialized {
+            get { return result.IsInitialized; }
+          }
           
           protected override ResultItem MessageBeingBuilt {
-            get { return result; }
+            get { return PrepareBuilder(); }
           }
           
           public override Builder Clear() {
-            result = new ResultItem();
+            result = DefaultInstance ?? new ResultItem();
+            builderIsReadOnly = true;
             return this;
           }
           
           public override Builder Clone() {
-            return new Builder().MergeFrom(result);
+            if (builderIsReadOnly) {
+              return new Builder(result);
+            } else {
+              return new Builder().MergeFrom(result);
+            }
           }
           
           public override pbd::MessageDescriptor DescriptorForType {
@@ -523,12 +582,11 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override ResultItem BuildPartial() {
-            if (result == null) {
-              throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+            if (builderIsReadOnly) {
+              return result;
             }
-            ResultItem returnMe = result;
-            result = null;
-            return returnMe;
+            builderIsReadOnly = true;
+            return result;
           }
           
           public override Builder MergeFrom(pb::IMessage other) {
@@ -542,6 +600,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           
           public override Builder MergeFrom(ResultItem other) {
             if (other == global::Google.ProtocolBuffers.TestProtos.SearchResponse.Types.ResultItem.DefaultInstance) return this;
+            PrepareBuilder();
             if (other.HasUrl) {
               Url = other.Url;
             }
@@ -557,6 +616,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+            PrepareBuilder();
             pb::UnknownFieldSet.Builder unknownFields = null;
             uint tag;
             string field_name;
@@ -617,11 +677,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetUrl(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasUrl = true;
             result.url_ = value;
             return this;
           }
           public Builder ClearUrl() {
+            PrepareBuilder();
             result.hasUrl = false;
             result.url_ = "";
             return this;
@@ -636,11 +698,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetName(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasName = true;
             result.name_ = value;
             return this;
           }
           public Builder ClearName() {
+            PrepareBuilder();
             result.hasName = false;
             result.name_ = "";
             return this;
@@ -734,7 +798,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(SearchResponse prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -744,21 +808,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new SearchResponse();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(SearchResponse cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      SearchResponse result;
       
-      SearchResponse result = new SearchResponse();
+      private SearchResponse PrepareBuilder() {
+        if (builderIsReadOnly) {
+          SearchResponse original = result;
+          result = new SearchResponse();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override SearchResponse MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new SearchResponse();
+        result = DefaultInstance ?? new SearchResponse();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -770,13 +861,12 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override SearchResponse BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.results_.MakeReadOnly();
-        SearchResponse returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -790,6 +880,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(SearchResponse other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.SearchResponse.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.results_.Count != 0) {
           base.AddRange(other.results_, result.results_);
         }
@@ -802,6 +893,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -850,7 +942,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.SearchResponse.Types.ResultItem> ResultsList {
-        get { return result.results_; }
+        get { return PrepareBuilder().results_; }
       }
       public int ResultsCount {
         get { return result.ResultsCount; }
@@ -860,29 +952,35 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetResults(int index, global::Google.ProtocolBuffers.TestProtos.SearchResponse.Types.ResultItem value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.results_[index] = value;
         return this;
       }
       public Builder SetResults(int index, global::Google.ProtocolBuffers.TestProtos.SearchResponse.Types.ResultItem.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.results_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddResults(global::Google.ProtocolBuffers.TestProtos.SearchResponse.Types.ResultItem value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.results_.Add(value);
         return this;
       }
       public Builder AddResults(global::Google.ProtocolBuffers.TestProtos.SearchResponse.Types.ResultItem.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.results_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangeResults(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.SearchResponse.Types.ResultItem> values) {
+        PrepareBuilder();
         base.AddRange(values, result.results_);
         return this;
       }
       public Builder ClearResults() {
+        PrepareBuilder();
         result.results_.Clear();
         return this;
       }
@@ -1019,7 +1117,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(RefineSearchRequest prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1029,21 +1127,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new RefineSearchRequest();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(RefineSearchRequest cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      RefineSearchRequest result;
       
-      RefineSearchRequest result = new RefineSearchRequest();
+      private RefineSearchRequest PrepareBuilder() {
+        if (builderIsReadOnly) {
+          RefineSearchRequest original = result;
+          result = new RefineSearchRequest();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override RefineSearchRequest MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new RefineSearchRequest();
+        result = DefaultInstance ?? new RefineSearchRequest();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -1055,13 +1180,12 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override RefineSearchRequest BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.criteria_.MakeReadOnly();
-        RefineSearchRequest returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -1075,6 +1199,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(RefineSearchRequest other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.RefineSearchRequest.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.criteria_.Count != 0) {
           base.AddRange(other.criteria_, result.criteria_);
         }
@@ -1090,6 +1215,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1147,7 +1273,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       
       public pbc::IPopsicleList<string> CriteriaList {
-        get { return result.criteria_; }
+        get { return PrepareBuilder().criteria_; }
       }
       public int CriteriaCount {
         get { return result.CriteriaCount; }
@@ -1157,19 +1283,23 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetCriteria(int index, string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.criteria_[index] = value;
         return this;
       }
       public Builder AddCriteria(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.criteria_.Add(value);
         return this;
       }
       public Builder AddRangeCriteria(scg::IEnumerable<string> values) {
+        PrepareBuilder();
         base.AddRange(values, result.criteria_);
         return this;
       }
       public Builder ClearCriteria() {
+        PrepareBuilder();
         result.criteria_.Clear();
         return this;
       }
@@ -1183,18 +1313,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetPreviousResults(global::Google.ProtocolBuffers.TestProtos.SearchResponse value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasPreviousResults = true;
         result.previousResults_ = value;
         return this;
       }
       public Builder SetPreviousResults(global::Google.ProtocolBuffers.TestProtos.SearchResponse.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasPreviousResults = true;
         result.previousResults_ = builderForValue.Build();
         return this;
       }
       public Builder MergePreviousResults(global::Google.ProtocolBuffers.TestProtos.SearchResponse value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasPreviousResults &&
             result.previousResults_ != global::Google.ProtocolBuffers.TestProtos.SearchResponse.DefaultInstance) {
             result.previousResults_ = global::Google.ProtocolBuffers.TestProtos.SearchResponse.CreateBuilder(result.previousResults_).MergeFrom(value).BuildPartial();
@@ -1205,6 +1338,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearPreviousResults() {
+        PrepareBuilder();
         result.hasPreviousResults = false;
         result.previousResults_ = global::Google.ProtocolBuffers.TestProtos.SearchResponse.DefaultInstance;
         return this;

+ 281 - 71
src/ProtocolBuffers.Test/TestProtos/UnitTestXmlSerializerTestProtoFile.cs

@@ -261,7 +261,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestXmlChild prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -271,21 +271,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestXmlChild();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestXmlChild cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestXmlChild result = new TestXmlChild();
+      bool builderIsReadOnly;
+      TestXmlChild result;
+      
+      private TestXmlChild PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestXmlChild original = result;
+          result = new TestXmlChild();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestXmlChild MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestXmlChild();
+        result = DefaultInstance ?? new TestXmlChild();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -297,13 +324,12 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestXmlChild BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.options_.MakeReadOnly();
-        TestXmlChild returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -317,6 +343,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestXmlChild other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestXmlChild.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.options_.Count != 0) {
           base.AddRange(other.options_, result.options_);
         }
@@ -332,6 +359,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -394,7 +422,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.EnumOptions> OptionsList {
-        get { return result.options_; }
+        get { return PrepareBuilder().options_; }
       }
       public int OptionsCount {
         get { return result.OptionsCount; }
@@ -403,18 +431,22 @@ namespace Google.ProtocolBuffers.TestProtos {
         return result.GetOptions(index);
       }
       public Builder SetOptions(int index, global::Google.ProtocolBuffers.TestProtos.EnumOptions value) {
+        PrepareBuilder();
         result.options_[index] = value;
         return this;
       }
       public Builder AddOptions(global::Google.ProtocolBuffers.TestProtos.EnumOptions value) {
+        PrepareBuilder();
         result.options_.Add(value);
         return this;
       }
       public Builder AddRangeOptions(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.EnumOptions> values) {
+        PrepareBuilder();
         base.AddRange(values, result.options_);
         return this;
       }
       public Builder ClearOptions() {
+        PrepareBuilder();
         result.options_.Clear();
         return this;
       }
@@ -428,11 +460,13 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetBinary(pb::ByteString value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasBinary = true;
         result.binary_ = value;
         return this;
       }
       public Builder ClearBinary() {
+        PrepareBuilder();
         result.hasBinary = false;
         result.binary_ = pb::ByteString.Empty;
         return this;
@@ -529,7 +563,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestXmlNoFields prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -539,21 +573,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestXmlNoFields();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestXmlNoFields cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestXmlNoFields result = new TestXmlNoFields();
+      bool builderIsReadOnly;
+      TestXmlNoFields result;
+      
+      private TestXmlNoFields PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestXmlNoFields original = result;
+          result = new TestXmlNoFields();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestXmlNoFields MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestXmlNoFields();
+        result = DefaultInstance ?? new TestXmlNoFields();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -565,12 +626,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestXmlNoFields BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestXmlNoFields returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -584,6 +644,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestXmlNoFields other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestXmlNoFields.DefaultInstance) return this;
+        PrepareBuilder();
         this.MergeUnknownFields(other.UnknownFields);
         return this;
       }
@@ -593,6 +654,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -743,7 +805,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestXmlRescursive prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -753,21 +815,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestXmlRescursive();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestXmlRescursive cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestXmlRescursive result = new TestXmlRescursive();
+      bool builderIsReadOnly;
+      TestXmlRescursive result;
+      
+      private TestXmlRescursive PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestXmlRescursive original = result;
+          result = new TestXmlRescursive();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestXmlRescursive MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestXmlRescursive();
+        result = DefaultInstance ?? new TestXmlRescursive();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -779,12 +868,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestXmlRescursive BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestXmlRescursive returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -798,6 +886,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestXmlRescursive other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestXmlRescursive.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasChild) {
           MergeChild(other.Child);
         }
@@ -810,6 +899,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -871,18 +961,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetChild(global::Google.ProtocolBuffers.TestProtos.TestXmlRescursive value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasChild = true;
         result.child_ = value;
         return this;
       }
       public Builder SetChild(global::Google.ProtocolBuffers.TestProtos.TestXmlRescursive.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasChild = true;
         result.child_ = builderForValue.Build();
         return this;
       }
       public Builder MergeChild(global::Google.ProtocolBuffers.TestProtos.TestXmlRescursive value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasChild &&
             result.child_ != global::Google.ProtocolBuffers.TestProtos.TestXmlRescursive.DefaultInstance) {
             result.child_ = global::Google.ProtocolBuffers.TestProtos.TestXmlRescursive.CreateBuilder(result.child_).MergeFrom(value).BuildPartial();
@@ -893,6 +986,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearChild() {
+        PrepareBuilder();
         result.hasChild = false;
         result.child_ = global::Google.ProtocolBuffers.TestProtos.TestXmlRescursive.DefaultInstance;
         return this;
@@ -1062,7 +1156,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         public override Builder ToBuilder() { return CreateBuilder(this); }
         public override Builder CreateBuilderForType() { return new Builder(); }
         public static Builder CreateBuilder(Children prototype) {
-          return (Builder) new Builder().MergeFrom(prototype);
+          return new Builder(prototype);
         }
         
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1072,21 +1166,48 @@ namespace Google.ProtocolBuffers.TestProtos {
           protected override Builder ThisBuilder {
             get { return this; }
           }
-          public Builder() {}
+          public Builder() {
+            result = DefaultInstance ?? new Children();
+            builderIsReadOnly = result == DefaultInstance;
+          }
+          internal Builder(Children cloneFrom) {
+            result = cloneFrom;
+            builderIsReadOnly = true;
+          }
           
-          Children result = new Children();
+          bool builderIsReadOnly;
+          Children result;
+          
+          private Children PrepareBuilder() {
+            if (builderIsReadOnly) {
+              Children original = result;
+              result = new Children();
+              builderIsReadOnly = false;
+              MergeFrom(original);
+            }
+            return result;
+          }
+          
+          public override bool IsInitialized {
+            get { return result.IsInitialized; }
+          }
           
           protected override Children MessageBeingBuilt {
-            get { return result; }
+            get { return PrepareBuilder(); }
           }
           
           public override Builder Clear() {
-            result = new Children();
+            result = DefaultInstance ?? new Children();
+            builderIsReadOnly = true;
             return this;
           }
           
           public override Builder Clone() {
-            return new Builder().MergeFrom(result);
+            if (builderIsReadOnly) {
+              return new Builder(result);
+            } else {
+              return new Builder().MergeFrom(result);
+            }
           }
           
           public override pbd::MessageDescriptor DescriptorForType {
@@ -1098,13 +1219,12 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Children BuildPartial() {
-            if (result == null) {
-              throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+            if (builderIsReadOnly) {
+              return result;
             }
             result.options_.MakeReadOnly();
-            Children returnMe = result;
-            result = null;
-            return returnMe;
+            builderIsReadOnly = true;
+            return result;
           }
           
           public override Builder MergeFrom(pb::IMessage other) {
@@ -1118,6 +1238,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           
           public override Builder MergeFrom(Children other) {
             if (other == global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.Types.Children.DefaultInstance) return this;
+            PrepareBuilder();
             if (other.options_.Count != 0) {
               base.AddRange(other.options_, result.options_);
             }
@@ -1133,6 +1254,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+            PrepareBuilder();
             pb::UnknownFieldSet.Builder unknownFields = null;
             uint tag;
             string field_name;
@@ -1195,7 +1317,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           
           
           public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.EnumOptions> OptionsList {
-            get { return result.options_; }
+            get { return PrepareBuilder().options_; }
           }
           public int OptionsCount {
             get { return result.OptionsCount; }
@@ -1204,18 +1326,22 @@ namespace Google.ProtocolBuffers.TestProtos {
             return result.GetOptions(index);
           }
           public Builder SetOptions(int index, global::Google.ProtocolBuffers.TestProtos.EnumOptions value) {
+            PrepareBuilder();
             result.options_[index] = value;
             return this;
           }
           public Builder AddOptions(global::Google.ProtocolBuffers.TestProtos.EnumOptions value) {
+            PrepareBuilder();
             result.options_.Add(value);
             return this;
           }
           public Builder AddRangeOptions(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.EnumOptions> values) {
+            PrepareBuilder();
             base.AddRange(values, result.options_);
             return this;
           }
           public Builder ClearOptions() {
+            PrepareBuilder();
             result.options_.Clear();
             return this;
           }
@@ -1229,11 +1355,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetBinary(pb::ByteString value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasBinary = true;
             result.binary_ = value;
             return this;
           }
           public Builder ClearBinary() {
+            PrepareBuilder();
             result.hasBinary = false;
             result.binary_ = pb::ByteString.Empty;
             return this;
@@ -1438,7 +1566,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestXmlMessage prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1448,21 +1576,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestXmlMessage();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestXmlMessage cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestXmlMessage result = new TestXmlMessage();
+      bool builderIsReadOnly;
+      TestXmlMessage result;
+      
+      private TestXmlMessage PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestXmlMessage original = result;
+          result = new TestXmlMessage();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestXmlMessage MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestXmlMessage();
+        result = DefaultInstance ?? new TestXmlMessage();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -1474,15 +1629,14 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestXmlMessage BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.numbers_.MakeReadOnly();
         result.textlines_.MakeReadOnly();
         result.children_.MakeReadOnly();
-        TestXmlMessage returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -1496,6 +1650,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestXmlMessage other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasNumber) {
           Number = other.Number;
         }
@@ -1527,6 +1682,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1612,18 +1768,20 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetNumber(value); }
       }
       public Builder SetNumber(long value) {
+        PrepareBuilder();
         result.hasNumber = true;
         result.number_ = value;
         return this;
       }
       public Builder ClearNumber() {
+        PrepareBuilder();
         result.hasNumber = false;
         result.number_ = 0L;
         return this;
       }
       
       public pbc::IPopsicleList<int> NumbersList {
-        get { return result.numbers_; }
+        get { return PrepareBuilder().numbers_; }
       }
       public int NumbersCount {
         get { return result.NumbersCount; }
@@ -1632,18 +1790,22 @@ namespace Google.ProtocolBuffers.TestProtos {
         return result.GetNumbers(index);
       }
       public Builder SetNumbers(int index, int value) {
+        PrepareBuilder();
         result.numbers_[index] = value;
         return this;
       }
       public Builder AddNumbers(int value) {
+        PrepareBuilder();
         result.numbers_.Add(value);
         return this;
       }
       public Builder AddRangeNumbers(scg::IEnumerable<int> values) {
+        PrepareBuilder();
         base.AddRange(values, result.numbers_);
         return this;
       }
       public Builder ClearNumbers() {
+        PrepareBuilder();
         result.numbers_.Clear();
         return this;
       }
@@ -1657,18 +1819,20 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetText(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasText = true;
         result.text_ = value;
         return this;
       }
       public Builder ClearText() {
+        PrepareBuilder();
         result.hasText = false;
         result.text_ = "";
         return this;
       }
       
       public pbc::IPopsicleList<string> TextlinesList {
-        get { return result.textlines_; }
+        get { return PrepareBuilder().textlines_; }
       }
       public int TextlinesCount {
         get { return result.TextlinesCount; }
@@ -1678,19 +1842,23 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetTextlines(int index, string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.textlines_[index] = value;
         return this;
       }
       public Builder AddTextlines(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.textlines_.Add(value);
         return this;
       }
       public Builder AddRangeTextlines(scg::IEnumerable<string> values) {
+        PrepareBuilder();
         base.AddRange(values, result.textlines_);
         return this;
       }
       public Builder ClearTextlines() {
+        PrepareBuilder();
         result.textlines_.Clear();
         return this;
       }
@@ -1703,11 +1871,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetValid(value); }
       }
       public Builder SetValid(bool value) {
+        PrepareBuilder();
         result.hasValid = true;
         result.valid_ = value;
         return this;
       }
       public Builder ClearValid() {
+        PrepareBuilder();
         result.hasValid = false;
         result.valid_ = false;
         return this;
@@ -1722,18 +1892,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetChild(global::Google.ProtocolBuffers.TestProtos.TestXmlChild value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasChild = true;
         result.child_ = value;
         return this;
       }
       public Builder SetChild(global::Google.ProtocolBuffers.TestProtos.TestXmlChild.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasChild = true;
         result.child_ = builderForValue.Build();
         return this;
       }
       public Builder MergeChild(global::Google.ProtocolBuffers.TestProtos.TestXmlChild value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasChild &&
             result.child_ != global::Google.ProtocolBuffers.TestProtos.TestXmlChild.DefaultInstance) {
             result.child_ = global::Google.ProtocolBuffers.TestProtos.TestXmlChild.CreateBuilder(result.child_).MergeFrom(value).BuildPartial();
@@ -1744,13 +1917,14 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearChild() {
+        PrepareBuilder();
         result.hasChild = false;
         result.child_ = global::Google.ProtocolBuffers.TestProtos.TestXmlChild.DefaultInstance;
         return this;
       }
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.Types.Children> ChildrenList {
-        get { return result.children_; }
+        get { return PrepareBuilder().children_; }
       }
       public int ChildrenCount {
         get { return result.ChildrenCount; }
@@ -1760,29 +1934,35 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetChildren(int index, global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.Types.Children value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.children_[index] = value;
         return this;
       }
       public Builder SetChildren(int index, global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.Types.Children.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.children_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddChildren(global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.Types.Children value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.children_.Add(value);
         return this;
       }
       public Builder AddChildren(global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.Types.Children.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.children_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangeChildren(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.TestXmlMessage.Types.Children> values) {
+        PrepareBuilder();
         base.AddRange(values, result.children_);
         return this;
       }
       public Builder ClearChildren() {
+        PrepareBuilder();
         result.children_.Clear();
         return this;
       }
@@ -1895,7 +2075,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestXmlExtension prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1905,21 +2085,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestXmlExtension();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestXmlExtension cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestXmlExtension result = new TestXmlExtension();
+      bool builderIsReadOnly;
+      TestXmlExtension result;
+      
+      private TestXmlExtension PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestXmlExtension original = result;
+          result = new TestXmlExtension();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestXmlExtension MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestXmlExtension();
+        result = DefaultInstance ?? new TestXmlExtension();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -1931,12 +2138,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestXmlExtension BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestXmlExtension returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -1950,6 +2156,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestXmlExtension other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestXmlExtension.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasNumber) {
           Number = other.Number;
         }
@@ -1962,6 +2169,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -2017,11 +2225,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetNumber(value); }
       }
       public Builder SetNumber(int value) {
+        PrepareBuilder();
         result.hasNumber = true;
         result.number_ = value;
         return this;
       }
       public Builder ClearNumber() {
+        PrepareBuilder();
         result.hasNumber = false;
         result.number_ = 0;
         return this;

+ 188 - 44
src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs

@@ -415,7 +415,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(CSharpFileOptions prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -425,21 +425,48 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new CSharpFileOptions();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(CSharpFileOptions cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      CSharpFileOptions result;
       
-      CSharpFileOptions result = new CSharpFileOptions();
+      private CSharpFileOptions PrepareBuilder() {
+        if (builderIsReadOnly) {
+          CSharpFileOptions original = result;
+          result = new CSharpFileOptions();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override CSharpFileOptions MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new CSharpFileOptions();
+        result = DefaultInstance ?? new CSharpFileOptions();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -451,12 +478,11 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override CSharpFileOptions BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        CSharpFileOptions returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -470,6 +496,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       
       public override Builder MergeFrom(CSharpFileOptions other) {
         if (other == global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasNamespace) {
           Namespace = other.Namespace;
         }
@@ -518,6 +545,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -630,11 +658,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       public Builder SetNamespace(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasNamespace = true;
         result.namespace_ = value;
         return this;
       }
       public Builder ClearNamespace() {
+        PrepareBuilder();
         result.hasNamespace = false;
         result.namespace_ = "";
         return this;
@@ -649,11 +679,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       public Builder SetUmbrellaClassname(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasUmbrellaClassname = true;
         result.umbrellaClassname_ = value;
         return this;
       }
       public Builder ClearUmbrellaClassname() {
+        PrepareBuilder();
         result.hasUmbrellaClassname = false;
         result.umbrellaClassname_ = "";
         return this;
@@ -667,11 +699,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetPublicClasses(value); }
       }
       public Builder SetPublicClasses(bool value) {
+        PrepareBuilder();
         result.hasPublicClasses = true;
         result.publicClasses_ = value;
         return this;
       }
       public Builder ClearPublicClasses() {
+        PrepareBuilder();
         result.hasPublicClasses = false;
         result.publicClasses_ = true;
         return this;
@@ -685,11 +719,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetMultipleFiles(value); }
       }
       public Builder SetMultipleFiles(bool value) {
+        PrepareBuilder();
         result.hasMultipleFiles = true;
         result.multipleFiles_ = value;
         return this;
       }
       public Builder ClearMultipleFiles() {
+        PrepareBuilder();
         result.hasMultipleFiles = false;
         result.multipleFiles_ = false;
         return this;
@@ -703,11 +739,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetNestClasses(value); }
       }
       public Builder SetNestClasses(bool value) {
+        PrepareBuilder();
         result.hasNestClasses = true;
         result.nestClasses_ = value;
         return this;
       }
       public Builder ClearNestClasses() {
+        PrepareBuilder();
         result.hasNestClasses = false;
         result.nestClasses_ = false;
         return this;
@@ -721,11 +759,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetCodeContracts(value); }
       }
       public Builder SetCodeContracts(bool value) {
+        PrepareBuilder();
         result.hasCodeContracts = true;
         result.codeContracts_ = value;
         return this;
       }
       public Builder ClearCodeContracts() {
+        PrepareBuilder();
         result.hasCodeContracts = false;
         result.codeContracts_ = false;
         return this;
@@ -739,11 +779,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetExpandNamespaceDirectories(value); }
       }
       public Builder SetExpandNamespaceDirectories(bool value) {
+        PrepareBuilder();
         result.hasExpandNamespaceDirectories = true;
         result.expandNamespaceDirectories_ = value;
         return this;
       }
       public Builder ClearExpandNamespaceDirectories() {
+        PrepareBuilder();
         result.hasExpandNamespaceDirectories = false;
         result.expandNamespaceDirectories_ = false;
         return this;
@@ -757,11 +799,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetClsCompliance(value); }
       }
       public Builder SetClsCompliance(bool value) {
+        PrepareBuilder();
         result.hasClsCompliance = true;
         result.clsCompliance_ = value;
         return this;
       }
       public Builder ClearClsCompliance() {
+        PrepareBuilder();
         result.hasClsCompliance = false;
         result.clsCompliance_ = true;
         return this;
@@ -776,11 +820,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       public Builder SetFileExtension(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasFileExtension = true;
         result.fileExtension_ = value;
         return this;
       }
       public Builder ClearFileExtension() {
+        PrepareBuilder();
         result.hasFileExtension = false;
         result.fileExtension_ = ".cs";
         return this;
@@ -795,11 +841,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       public Builder SetUmbrellaNamespace(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasUmbrellaNamespace = true;
         result.umbrellaNamespace_ = value;
         return this;
       }
       public Builder ClearUmbrellaNamespace() {
+        PrepareBuilder();
         result.hasUmbrellaNamespace = false;
         result.umbrellaNamespace_ = "";
         return this;
@@ -814,11 +862,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       public Builder SetOutputDirectory(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasOutputDirectory = true;
         result.outputDirectory_ = value;
         return this;
       }
       public Builder ClearOutputDirectory() {
+        PrepareBuilder();
         result.hasOutputDirectory = false;
         result.outputDirectory_ = ".";
         return this;
@@ -832,11 +882,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetIgnoreGoogleProtobuf(value); }
       }
       public Builder SetIgnoreGoogleProtobuf(bool value) {
+        PrepareBuilder();
         result.hasIgnoreGoogleProtobuf = true;
         result.ignoreGoogleProtobuf_ = value;
         return this;
       }
       public Builder ClearIgnoreGoogleProtobuf() {
+        PrepareBuilder();
         result.hasIgnoreGoogleProtobuf = false;
         result.ignoreGoogleProtobuf_ = false;
         return this;
@@ -850,11 +902,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetServiceGeneratorType(value); }
       }
       public Builder SetServiceGeneratorType(global::Google.ProtocolBuffers.DescriptorProtos.CSharpServiceType value) {
+        PrepareBuilder();
         result.hasServiceGeneratorType = true;
         result.serviceGeneratorType_ = value;
         return this;
       }
       public Builder ClearServiceGeneratorType() {
+        PrepareBuilder();
         result.hasServiceGeneratorType = false;
         result.serviceGeneratorType_ = global::Google.ProtocolBuffers.DescriptorProtos.CSharpServiceType.NONE;
         return this;
@@ -967,7 +1021,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(CSharpFieldOptions prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -977,21 +1031,48 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new CSharpFieldOptions();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(CSharpFieldOptions cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      CSharpFieldOptions result;
       
-      CSharpFieldOptions result = new CSharpFieldOptions();
+      private CSharpFieldOptions PrepareBuilder() {
+        if (builderIsReadOnly) {
+          CSharpFieldOptions original = result;
+          result = new CSharpFieldOptions();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override CSharpFieldOptions MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new CSharpFieldOptions();
+        result = DefaultInstance ?? new CSharpFieldOptions();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -1003,12 +1084,11 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override CSharpFieldOptions BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        CSharpFieldOptions returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -1022,6 +1102,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       
       public override Builder MergeFrom(CSharpFieldOptions other) {
         if (other == global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasPropertyName) {
           PropertyName = other.PropertyName;
         }
@@ -1034,6 +1115,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1090,11 +1172,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       public Builder SetPropertyName(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasPropertyName = true;
         result.propertyName_ = value;
         return this;
       }
       public Builder ClearPropertyName() {
+        PrepareBuilder();
         result.hasPropertyName = false;
         result.propertyName_ = "";
         return this;
@@ -1207,7 +1291,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(CSharpServiceOptions prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1217,21 +1301,48 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new CSharpServiceOptions();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(CSharpServiceOptions cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      CSharpServiceOptions result;
       
-      CSharpServiceOptions result = new CSharpServiceOptions();
+      private CSharpServiceOptions PrepareBuilder() {
+        if (builderIsReadOnly) {
+          CSharpServiceOptions original = result;
+          result = new CSharpServiceOptions();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override CSharpServiceOptions MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new CSharpServiceOptions();
+        result = DefaultInstance ?? new CSharpServiceOptions();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -1243,12 +1354,11 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override CSharpServiceOptions BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        CSharpServiceOptions returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -1262,6 +1372,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       
       public override Builder MergeFrom(CSharpServiceOptions other) {
         if (other == global::Google.ProtocolBuffers.DescriptorProtos.CSharpServiceOptions.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasInterfaceId) {
           InterfaceId = other.InterfaceId;
         }
@@ -1274,6 +1385,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1330,11 +1442,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       public Builder SetInterfaceId(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasInterfaceId = true;
         result.interfaceId_ = value;
         return this;
       }
       public Builder ClearInterfaceId() {
+        PrepareBuilder();
         result.hasInterfaceId = false;
         result.interfaceId_ = "";
         return this;
@@ -1447,7 +1561,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(CSharpMethodOptions prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1457,21 +1571,48 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new CSharpMethodOptions();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(CSharpMethodOptions cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      CSharpMethodOptions result;
       
-      CSharpMethodOptions result = new CSharpMethodOptions();
+      private CSharpMethodOptions PrepareBuilder() {
+        if (builderIsReadOnly) {
+          CSharpMethodOptions original = result;
+          result = new CSharpMethodOptions();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override CSharpMethodOptions MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new CSharpMethodOptions();
+        result = DefaultInstance ?? new CSharpMethodOptions();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -1483,12 +1624,11 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override CSharpMethodOptions BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        CSharpMethodOptions returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -1502,6 +1642,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       
       public override Builder MergeFrom(CSharpMethodOptions other) {
         if (other == global::Google.ProtocolBuffers.DescriptorProtos.CSharpMethodOptions.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasDispatchId) {
           DispatchId = other.DispatchId;
         }
@@ -1514,6 +1655,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -1569,11 +1711,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
         set { SetDispatchId(value); }
       }
       public Builder SetDispatchId(int value) {
+        PrepareBuilder();
         result.hasDispatchId = true;
         result.dispatchId_ = value;
         return this;
       }
       public Builder ClearDispatchId() {
+        PrepareBuilder();
         result.hasDispatchId = false;
         result.dispatchId_ = 0;
         return this;

File diff suppressed because it is too large
+ 282 - 61
src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs


+ 3 - 8
src/ProtocolBuffers/GeneratedBuilder.cs

@@ -58,12 +58,7 @@ namespace Google.ProtocolBuffers
 
         protected internal FieldAccessorTable<TMessage, TBuilder> InternalFieldAccessors
         {
-            get { return MessageBeingBuilt.FieldAccessorsFromBuilder; }
-        }
-
-        public override bool IsInitialized
-        {
-            get { return MessageBeingBuilt.IsInitialized; }
+            get { return DefaultInstanceForType.FieldAccessorsFromBuilder; }
         }
 
         public override IDictionary<FieldDescriptor, object> AllFields
@@ -123,7 +118,7 @@ namespace Google.ProtocolBuffers
 
         public override MessageDescriptor DescriptorForType
         {
-            get { return MessageBeingBuilt.DescriptorForType; }
+            get { return DefaultInstanceForType.DescriptorForType; }
         }
 
         public override int GetRepeatedFieldCount(FieldDescriptor field)
@@ -230,7 +225,7 @@ namespace Google.ProtocolBuffers
         public override TMessage Build()
         {
             // If the message is null, we'll throw a more appropriate exception in BuildPartial.
-            if (MessageBeingBuilt != null && !IsInitialized)
+            if (!IsInitialized)
             {
                 throw new UninitializedMessageException(MessageBeingBuilt);
             }

+ 1 - 6
src/ProtocolBuffers/GeneratedBuilderLite.cs

@@ -61,11 +61,6 @@ namespace Google.ProtocolBuffers
 
         public abstract TBuilder MergeFrom(TMessage other);
 
-        public override bool IsInitialized
-        {
-            get { return MessageBeingBuilt.IsInitialized; }
-        }
-
         /// <summary>
         /// Adds all of the specified values to the given collection.
         /// </summary>
@@ -122,7 +117,7 @@ namespace Google.ProtocolBuffers
         public override TMessage Build()
         {
             // If the message is null, we'll throw a more appropriate exception in BuildPartial.
-            if (MessageBeingBuilt != null && !IsInitialized)
+            if (!IsInitialized)
             {
                 throw new UninitializedMessageException(MessageBeingBuilt);
             }

File diff suppressed because it is too large
+ 355 - 88
src/ProtocolBuffersLite.Test/TestProtos/UnitTestExtrasFullProtoFile.cs


+ 240 - 58
src/ProtocolBuffersLite.Test/TestProtos/UnitTestExtrasLiteProtoFile.cs

@@ -187,7 +187,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestRequiredLite prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -197,21 +197,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestRequiredLite();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestRequiredLite cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      TestRequiredLite result;
+      
+      private TestRequiredLite PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestRequiredLite original = result;
+          result = new TestRequiredLite();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
       
-      TestRequiredLite result = new TestRequiredLite();
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestRequiredLite MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestRequiredLite();
+        result = DefaultInstance ?? new TestRequiredLite();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override TestRequiredLite DefaultInstanceForType {
@@ -219,12 +246,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestRequiredLite BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestRequiredLite returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessageLite other) {
@@ -238,6 +264,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestRequiredLite other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestRequiredLite.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasD) {
           D = other.D;
         }
@@ -252,6 +279,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         uint tag;
         string field_name;
         while (input.ReadTag(out tag, out field_name)) {
@@ -302,11 +330,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetD(value); }
       }
       public Builder SetD(int value) {
+        PrepareBuilder();
         result.hasD = true;
         result.d_ = value;
         return this;
       }
       public Builder ClearD() {
+        PrepareBuilder();
         result.hasD = false;
         result.d_ = 0;
         return this;
@@ -320,11 +350,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetEn(value); }
       }
       public Builder SetEn(global::Google.ProtocolBuffers.TestProtos.ExtraEnum value) {
+        PrepareBuilder();
         result.hasEn = true;
         result.en_ = value;
         return this;
       }
       public Builder ClearEn() {
+        PrepareBuilder();
         result.hasEn = false;
         result.en_ = global::Google.ProtocolBuffers.TestProtos.ExtraEnum.DEFAULT;
         return this;
@@ -498,7 +530,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         public override Builder ToBuilder() { return CreateBuilder(this); }
         public override Builder CreateBuilderForType() { return new Builder(); }
         public static Builder CreateBuilder(PhoneNumber prototype) {
-          return (Builder) new Builder().MergeFrom(prototype);
+          return new Builder(prototype);
         }
         
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -508,21 +540,48 @@ namespace Google.ProtocolBuffers.TestProtos {
           protected override Builder ThisBuilder {
             get { return this; }
           }
-          public Builder() {}
+          public Builder() {
+            result = DefaultInstance ?? new PhoneNumber();
+            builderIsReadOnly = result == DefaultInstance;
+          }
+          internal Builder(PhoneNumber cloneFrom) {
+            result = cloneFrom;
+            builderIsReadOnly = true;
+          }
           
-          PhoneNumber result = new PhoneNumber();
+          bool builderIsReadOnly;
+          PhoneNumber result;
+          
+          private PhoneNumber PrepareBuilder() {
+            if (builderIsReadOnly) {
+              PhoneNumber original = result;
+              result = new PhoneNumber();
+              builderIsReadOnly = false;
+              MergeFrom(original);
+            }
+            return result;
+          }
+          
+          public override bool IsInitialized {
+            get { return result.IsInitialized; }
+          }
           
           protected override PhoneNumber MessageBeingBuilt {
-            get { return result; }
+            get { return PrepareBuilder(); }
           }
           
           public override Builder Clear() {
-            result = new PhoneNumber();
+            result = DefaultInstance ?? new PhoneNumber();
+            builderIsReadOnly = true;
             return this;
           }
           
           public override Builder Clone() {
-            return new Builder().MergeFrom(result);
+            if (builderIsReadOnly) {
+              return new Builder(result);
+            } else {
+              return new Builder().MergeFrom(result);
+            }
           }
           
           public override PhoneNumber DefaultInstanceForType {
@@ -530,12 +589,11 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override PhoneNumber BuildPartial() {
-            if (result == null) {
-              throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+            if (builderIsReadOnly) {
+              return result;
             }
-            PhoneNumber returnMe = result;
-            result = null;
-            return returnMe;
+            builderIsReadOnly = true;
+            return result;
           }
           
           public override Builder MergeFrom(pb::IMessageLite other) {
@@ -549,6 +607,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           
           public override Builder MergeFrom(PhoneNumber other) {
             if (other == global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneNumber.DefaultInstance) return this;
+            PrepareBuilder();
             if (other.HasNumber) {
               Number = other.Number;
             }
@@ -563,6 +622,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+            PrepareBuilder();
             uint tag;
             string field_name;
             while (input.ReadTag(out tag, out field_name)) {
@@ -614,11 +674,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetNumber(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasNumber = true;
             result.number_ = value;
             return this;
           }
           public Builder ClearNumber() {
+            PrepareBuilder();
             result.hasNumber = false;
             result.number_ = "";
             return this;
@@ -632,11 +694,13 @@ namespace Google.ProtocolBuffers.TestProtos {
             set { SetType(value); }
           }
           public Builder SetType(global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneType value) {
+            PrepareBuilder();
             result.hasType = true;
             result.type_ = value;
             return this;
           }
           public Builder ClearType() {
+            PrepareBuilder();
             result.hasType = false;
             result.type_ = global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneType.HOME;
             return this;
@@ -839,7 +903,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         public override Builder ToBuilder() { return CreateBuilder(this); }
         public override Builder CreateBuilderForType() { return new Builder(); }
         public static Builder CreateBuilder(Addresses prototype) {
-          return (Builder) new Builder().MergeFrom(prototype);
+          return new Builder(prototype);
         }
         
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -849,21 +913,48 @@ namespace Google.ProtocolBuffers.TestProtos {
           protected override Builder ThisBuilder {
             get { return this; }
           }
-          public Builder() {}
+          public Builder() {
+            result = DefaultInstance ?? new Addresses();
+            builderIsReadOnly = result == DefaultInstance;
+          }
+          internal Builder(Addresses cloneFrom) {
+            result = cloneFrom;
+            builderIsReadOnly = true;
+          }
+          
+          bool builderIsReadOnly;
+          Addresses result;
           
-          Addresses result = new Addresses();
+          private Addresses PrepareBuilder() {
+            if (builderIsReadOnly) {
+              Addresses original = result;
+              result = new Addresses();
+              builderIsReadOnly = false;
+              MergeFrom(original);
+            }
+            return result;
+          }
+          
+          public override bool IsInitialized {
+            get { return result.IsInitialized; }
+          }
           
           protected override Addresses MessageBeingBuilt {
-            get { return result; }
+            get { return PrepareBuilder(); }
           }
           
           public override Builder Clear() {
-            result = new Addresses();
+            result = DefaultInstance ?? new Addresses();
+            builderIsReadOnly = true;
             return this;
           }
           
           public override Builder Clone() {
-            return new Builder().MergeFrom(result);
+            if (builderIsReadOnly) {
+              return new Builder(result);
+            } else {
+              return new Builder().MergeFrom(result);
+            }
           }
           
           public override Addresses DefaultInstanceForType {
@@ -871,12 +962,11 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Addresses BuildPartial() {
-            if (result == null) {
-              throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+            if (builderIsReadOnly) {
+              return result;
             }
-            Addresses returnMe = result;
-            result = null;
-            return returnMe;
+            builderIsReadOnly = true;
+            return result;
           }
           
           public override Builder MergeFrom(pb::IMessageLite other) {
@@ -890,6 +980,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           
           public override Builder MergeFrom(Addresses other) {
             if (other == global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.Addresses.DefaultInstance) return this;
+            PrepareBuilder();
             if (other.HasAddress) {
               Address = other.Address;
             }
@@ -913,6 +1004,7 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           
           public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+            PrepareBuilder();
             uint tag;
             string field_name;
             while (input.ReadTag(out tag, out field_name)) {
@@ -972,11 +1064,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetAddress(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasAddress = true;
             result.address_ = value;
             return this;
           }
           public Builder ClearAddress() {
+            PrepareBuilder();
             result.hasAddress = false;
             result.address_ = "";
             return this;
@@ -991,11 +1085,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetAddress2(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasAddress2 = true;
             result.address2_ = value;
             return this;
           }
           public Builder ClearAddress2() {
+            PrepareBuilder();
             result.hasAddress2 = false;
             result.address2_ = "";
             return this;
@@ -1010,11 +1106,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetCity(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasCity = true;
             result.city_ = value;
             return this;
           }
           public Builder ClearCity() {
+            PrepareBuilder();
             result.hasCity = false;
             result.city_ = "";
             return this;
@@ -1029,11 +1127,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           public Builder SetState(string value) {
             pb::ThrowHelper.ThrowIfNull(value, "value");
+            PrepareBuilder();
             result.hasState = true;
             result.state_ = value;
             return this;
           }
           public Builder ClearState() {
+            PrepareBuilder();
             result.hasState = false;
             result.state_ = "";
             return this;
@@ -1049,11 +1149,13 @@ namespace Google.ProtocolBuffers.TestProtos {
           }
           [global::System.CLSCompliant(false)]
           public Builder SetZip(uint value) {
+            PrepareBuilder();
             result.hasZip = true;
             result.zip_ = value;
             return this;
           }
           public Builder ClearZip() {
+            PrepareBuilder();
             result.hasZip = false;
             result.zip_ = 0;
             return this;
@@ -1290,7 +1392,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestInteropPersonLite prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1300,21 +1402,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestInteropPersonLite();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestInteropPersonLite cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestInteropPersonLite result = new TestInteropPersonLite();
+      bool builderIsReadOnly;
+      TestInteropPersonLite result;
+      
+      private TestInteropPersonLite PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestInteropPersonLite original = result;
+          result = new TestInteropPersonLite();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestInteropPersonLite MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestInteropPersonLite();
+        result = DefaultInstance ?? new TestInteropPersonLite();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override TestInteropPersonLite DefaultInstanceForType {
@@ -1322,15 +1451,14 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestInteropPersonLite BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
         result.codes_.MakeReadOnly();
         result.phone_.MakeReadOnly();
         result.addresses_.MakeReadOnly();
-        TestInteropPersonLite returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessageLite other) {
@@ -1344,6 +1472,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestInteropPersonLite other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasName) {
           Name = other.Name;
         }
@@ -1371,6 +1500,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         uint tag;
         string field_name;
         while (input.ReadTag(out tag, out field_name)) {
@@ -1435,11 +1565,13 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetName(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasName = true;
         result.name_ = value;
         return this;
       }
       public Builder ClearName() {
+        PrepareBuilder();
         result.hasName = false;
         result.name_ = "";
         return this;
@@ -1453,11 +1585,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetId(value); }
       }
       public Builder SetId(int value) {
+        PrepareBuilder();
         result.hasId = true;
         result.id_ = value;
         return this;
       }
       public Builder ClearId() {
+        PrepareBuilder();
         result.hasId = false;
         result.id_ = 0;
         return this;
@@ -1472,18 +1606,20 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetEmail(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasEmail = true;
         result.email_ = value;
         return this;
       }
       public Builder ClearEmail() {
+        PrepareBuilder();
         result.hasEmail = false;
         result.email_ = "";
         return this;
       }
       
       public pbc::IPopsicleList<int> CodesList {
-        get { return result.codes_; }
+        get { return PrepareBuilder().codes_; }
       }
       public int CodesCount {
         get { return result.CodesCount; }
@@ -1492,24 +1628,28 @@ namespace Google.ProtocolBuffers.TestProtos {
         return result.GetCodes(index);
       }
       public Builder SetCodes(int index, int value) {
+        PrepareBuilder();
         result.codes_[index] = value;
         return this;
       }
       public Builder AddCodes(int value) {
+        PrepareBuilder();
         result.codes_.Add(value);
         return this;
       }
       public Builder AddRangeCodes(scg::IEnumerable<int> values) {
+        PrepareBuilder();
         base.AddRange(values, result.codes_);
         return this;
       }
       public Builder ClearCodes() {
+        PrepareBuilder();
         result.codes_.Clear();
         return this;
       }
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneNumber> PhoneList {
-        get { return result.phone_; }
+        get { return PrepareBuilder().phone_; }
       }
       public int PhoneCount {
         get { return result.PhoneCount; }
@@ -1519,35 +1659,41 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetPhone(int index, global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneNumber value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.phone_[index] = value;
         return this;
       }
       public Builder SetPhone(int index, global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneNumber.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.phone_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddPhone(global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneNumber value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.phone_.Add(value);
         return this;
       }
       public Builder AddPhone(global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneNumber.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.phone_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangePhone(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.PhoneNumber> values) {
+        PrepareBuilder();
         base.AddRange(values, result.phone_);
         return this;
       }
       public Builder ClearPhone() {
+        PrepareBuilder();
         result.phone_.Clear();
         return this;
       }
       
       public pbc::IPopsicleList<global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.Addresses> AddressesList {
-        get { return result.addresses_; }
+        get { return PrepareBuilder().addresses_; }
       }
       public int AddressesCount {
         get { return result.AddressesCount; }
@@ -1557,29 +1703,35 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetAddresses(int index, global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.Addresses value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.addresses_[index] = value;
         return this;
       }
       public Builder SetAddresses(int index, global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.Addresses.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.addresses_[index] = builderForValue.Build();
         return this;
       }
       public Builder AddAddresses(global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.Addresses value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.addresses_.Add(value);
         return this;
       }
       public Builder AddAddresses(global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.Addresses.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.addresses_.Add(builderForValue.Build());
         return this;
       }
       public Builder AddRangeAddresses(scg::IEnumerable<global::Google.ProtocolBuffers.TestProtos.TestInteropPersonLite.Types.Addresses> values) {
+        PrepareBuilder();
         base.AddRange(values, result.addresses_);
         return this;
       }
       public Builder ClearAddresses() {
+        PrepareBuilder();
         result.addresses_.Clear();
         return this;
       }
@@ -1701,7 +1853,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestInteropEmployeeIdLite prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -1711,21 +1863,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestInteropEmployeeIdLite();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestInteropEmployeeIdLite cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
       
-      TestInteropEmployeeIdLite result = new TestInteropEmployeeIdLite();
+      bool builderIsReadOnly;
+      TestInteropEmployeeIdLite result;
+      
+      private TestInteropEmployeeIdLite PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestInteropEmployeeIdLite original = result;
+          result = new TestInteropEmployeeIdLite();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestInteropEmployeeIdLite MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestInteropEmployeeIdLite();
+        result = DefaultInstance ?? new TestInteropEmployeeIdLite();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override TestInteropEmployeeIdLite DefaultInstanceForType {
@@ -1733,12 +1912,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestInteropEmployeeIdLite BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestInteropEmployeeIdLite returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessageLite other) {
@@ -1752,6 +1930,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestInteropEmployeeIdLite other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestInteropEmployeeIdLite.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasNumber) {
           Number = other.Number;
         }
@@ -1763,6 +1942,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         uint tag;
         string field_name;
         while (input.ReadTag(out tag, out field_name)) {
@@ -1806,11 +1986,13 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetNumber(string value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasNumber = true;
         result.number_ = value;
         return this;
       }
       public Builder ClearNumber() {
+        PrepareBuilder();
         result.hasNumber = false;
         result.number_ = "";
         return this;

+ 41 - 11
src/ProtocolBuffersLite.Test/TestProtos/UnitTestImportLiteProtoFile.cs

@@ -150,7 +150,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(ImportMessageLite prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -160,21 +160,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new ImportMessageLite();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(ImportMessageLite cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      ImportMessageLite result;
       
-      ImportMessageLite result = new ImportMessageLite();
+      private ImportMessageLite PrepareBuilder() {
+        if (builderIsReadOnly) {
+          ImportMessageLite original = result;
+          result = new ImportMessageLite();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override ImportMessageLite MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new ImportMessageLite();
+        result = DefaultInstance ?? new ImportMessageLite();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override ImportMessageLite DefaultInstanceForType {
@@ -182,12 +209,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override ImportMessageLite BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        ImportMessageLite returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessageLite other) {
@@ -201,6 +227,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(ImportMessageLite other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.ImportMessageLite.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasD) {
           D = other.D;
         }
@@ -212,6 +239,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         uint tag;
         string field_name;
         while (input.ReadTag(out tag, out field_name)) {
@@ -254,11 +282,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetD(value); }
       }
       public Builder SetD(int value) {
+        PrepareBuilder();
         result.hasD = true;
         result.d_ = value;
         return this;
       }
       public Builder ClearD() {
+        PrepareBuilder();
         result.hasD = false;
         result.d_ = 0;
         return this;

+ 41 - 11
src/ProtocolBuffersLite.Test/TestProtos/UnitTestImportProtoFile.cs

@@ -169,7 +169,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(ImportMessage prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -179,21 +179,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new ImportMessage();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(ImportMessage cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      ImportMessage result;
       
-      ImportMessage result = new ImportMessage();
+      private ImportMessage PrepareBuilder() {
+        if (builderIsReadOnly) {
+          ImportMessage original = result;
+          result = new ImportMessage();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override ImportMessage MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new ImportMessage();
+        result = DefaultInstance ?? new ImportMessage();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override pbd::MessageDescriptor DescriptorForType {
@@ -205,12 +232,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override ImportMessage BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        ImportMessage returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessage other) {
@@ -224,6 +250,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(ImportMessage other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.ImportMessage.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasD) {
           D = other.D;
         }
@@ -236,6 +263,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         pb::UnknownFieldSet.Builder unknownFields = null;
         uint tag;
         string field_name;
@@ -291,11 +319,13 @@ namespace Google.ProtocolBuffers.TestProtos {
         set { SetD(value); }
       }
       public Builder SetD(int value) {
+        PrepareBuilder();
         result.hasD = true;
         result.d_ = value;
         return this;
       }
       public Builder ClearD() {
+        PrepareBuilder();
         result.hasD = false;
         result.d_ = 0;
         return this;

+ 43 - 11
src/ProtocolBuffersLite.Test/TestProtos/UnitTestLiteImportNonLiteProtoFile.cs

@@ -139,7 +139,7 @@ namespace Google.ProtocolBuffers.TestProtos {
     public override Builder ToBuilder() { return CreateBuilder(this); }
     public override Builder CreateBuilderForType() { return new Builder(); }
     public static Builder CreateBuilder(TestLiteImportsNonlite prototype) {
-      return (Builder) new Builder().MergeFrom(prototype);
+      return new Builder(prototype);
     }
     
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -149,21 +149,48 @@ namespace Google.ProtocolBuffers.TestProtos {
       protected override Builder ThisBuilder {
         get { return this; }
       }
-      public Builder() {}
+      public Builder() {
+        result = DefaultInstance ?? new TestLiteImportsNonlite();
+        builderIsReadOnly = result == DefaultInstance;
+      }
+      internal Builder(TestLiteImportsNonlite cloneFrom) {
+        result = cloneFrom;
+        builderIsReadOnly = true;
+      }
+      
+      bool builderIsReadOnly;
+      TestLiteImportsNonlite result;
       
-      TestLiteImportsNonlite result = new TestLiteImportsNonlite();
+      private TestLiteImportsNonlite PrepareBuilder() {
+        if (builderIsReadOnly) {
+          TestLiteImportsNonlite original = result;
+          result = new TestLiteImportsNonlite();
+          builderIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+      
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
       
       protected override TestLiteImportsNonlite MessageBeingBuilt {
-        get { return result; }
+        get { return PrepareBuilder(); }
       }
       
       public override Builder Clear() {
-        result = new TestLiteImportsNonlite();
+        result = DefaultInstance ?? new TestLiteImportsNonlite();
+        builderIsReadOnly = true;
         return this;
       }
       
       public override Builder Clone() {
-        return new Builder().MergeFrom(result);
+        if (builderIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
       }
       
       public override TestLiteImportsNonlite DefaultInstanceForType {
@@ -171,12 +198,11 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override TestLiteImportsNonlite BuildPartial() {
-        if (result == null) {
-          throw new global::System.InvalidOperationException("build() has already been called on this Builder");
+        if (builderIsReadOnly) {
+          return result;
         }
-        TestLiteImportsNonlite returnMe = result;
-        result = null;
-        return returnMe;
+        builderIsReadOnly = true;
+        return result;
       }
       
       public override Builder MergeFrom(pb::IMessageLite other) {
@@ -190,6 +216,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       
       public override Builder MergeFrom(TestLiteImportsNonlite other) {
         if (other == global::Google.ProtocolBuffers.TestProtos.TestLiteImportsNonlite.DefaultInstance) return this;
+        PrepareBuilder();
         if (other.HasMessage) {
           MergeMessage(other.Message);
         }
@@ -201,6 +228,7 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       
       public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
         uint tag;
         string field_name;
         while (input.ReadTag(out tag, out field_name)) {
@@ -249,18 +277,21 @@ namespace Google.ProtocolBuffers.TestProtos {
       }
       public Builder SetMessage(global::Google.ProtocolBuffers.TestProtos.TestAllTypes value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         result.hasMessage = true;
         result.message_ = value;
         return this;
       }
       public Builder SetMessage(global::Google.ProtocolBuffers.TestProtos.TestAllTypes.Builder builderForValue) {
         pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+        PrepareBuilder();
         result.hasMessage = true;
         result.message_ = builderForValue.Build();
         return this;
       }
       public Builder MergeMessage(global::Google.ProtocolBuffers.TestProtos.TestAllTypes value) {
         pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
         if (result.hasMessage &&
             result.message_ != global::Google.ProtocolBuffers.TestProtos.TestAllTypes.DefaultInstance) {
             result.message_ = global::Google.ProtocolBuffers.TestProtos.TestAllTypes.CreateBuilder(result.message_).MergeFrom(value).BuildPartial();
@@ -271,6 +302,7 @@ namespace Google.ProtocolBuffers.TestProtos {
         return this;
       }
       public Builder ClearMessage() {
+        PrepareBuilder();
         result.hasMessage = false;
         result.message_ = global::Google.ProtocolBuffers.TestProtos.TestAllTypes.DefaultInstance;
         return this;

File diff suppressed because it is too large
+ 249 - 51
src/ProtocolBuffersLite.Test/TestProtos/UnitTestLiteProtoFile.cs


File diff suppressed because it is too large
+ 249 - 51
src/ProtocolBuffersLite.Test/TestProtos/UnitTestProtoFile.cs


Some files were not shown because too many files changed in this diff