First pass at implementation and testing of reusable builders.
diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestRpcInterop.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestRpcInterop.cs
index ae309fa..3c5e930 100644
--- a/src/ProtocolBuffers.Test/TestProtos/UnitTestRpcInterop.cs
+++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestRpcInterop.cs
@@ -188,7 +188,7 @@
     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 @@
       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;

+      }

       

-      SearchRequest result = new SearchRequest();

+      bool builderIsReadOnly;

+      SearchRequest result;

+      

+      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 @@
       }

       

       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 @@
       

       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 @@
       }

       

       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 @@
       

       

       public pbc::IPopsicleList<string> CriteriaList {

-        get { return result.criteria_; }

+        get { return PrepareBuilder().criteria_; }

       }

       public int CriteriaCount {

         get { return result.CriteriaCount; }

@@ -314,19 +342,23 @@
       }

       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 @@
         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 @@
           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;

+          }

           

-          ResultItem result = new ResultItem();

+          bool builderIsReadOnly;

+          ResultItem result;

+          

+          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 @@
           }

           

           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 @@
           

           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 @@
           }

           

           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 @@
           }

           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 @@
           }

           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 @@
     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 @@
       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;

+      }

       

-      SearchResponse result = new SearchResponse();

+      bool builderIsReadOnly;

+      SearchResponse result;

+      

+      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 @@
       }

       

       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 @@
       

       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 @@
       }

       

       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 @@
       

       

       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 @@
       }

       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 @@
     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 @@
       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;

+      }

       

-      RefineSearchRequest result = new RefineSearchRequest();

+      bool builderIsReadOnly;

+      RefineSearchRequest result;

+      

+      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 @@
       }

       

       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 @@
       

       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 @@
       }

       

       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 @@
       

       

       public pbc::IPopsicleList<string> CriteriaList {

-        get { return result.criteria_; }

+        get { return PrepareBuilder().criteria_; }

       }

       public int CriteriaCount {

         get { return result.CriteriaCount; }

@@ -1157,19 +1283,23 @@
       }

       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 @@
       }

       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 @@
         return this;

       }

       public Builder ClearPreviousResults() {

+        PrepareBuilder();

         result.hasPreviousResults = false;

         result.previousResults_ = global::Google.ProtocolBuffers.TestProtos.SearchResponse.DefaultInstance;

         return this;