First pass at implementation and testing of reusable builders.
diff --git a/src/AddressBook/AddressBookProtos.cs b/src/AddressBook/AddressBookProtos.cs
index 4d391f0..8bb19df 100644
--- a/src/AddressBook/AddressBookProtos.cs
+++ b/src/AddressBook/AddressBookProtos.cs
@@ -223,7 +223,7 @@
         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 @@
           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 @@
           }

           

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

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

           

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

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

       

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

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

       

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

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

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

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

       

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

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

       

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

       

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

       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;

       }