Completed abstract lite builder and message
diff --git a/src/ProtocolBuffers/AbstractMessage.cs b/src/ProtocolBuffers/AbstractMessage.cs
index 9cb38c3..4486430 100644
--- a/src/ProtocolBuffers/AbstractMessage.cs
+++ b/src/ProtocolBuffers/AbstractMessage.cs
@@ -42,7 +42,7 @@
   /// <summary>
   /// Implementation of the non-generic IMessage interface as far as possible.
   /// </summary>
-  public abstract class AbstractMessage<TMessage, TBuilder> : IMessage<TMessage, TBuilder> 
+  public abstract class AbstractMessage<TMessage, TBuilder> : AbstractMessageLite<TMessage, TBuilder>, IMessage<TMessage, TBuilder> 
       where TMessage : AbstractMessage<TMessage, TBuilder> 
       where TBuilder : AbstractBuilder<TMessage, TBuilder> {
     /// <summary>
@@ -59,28 +59,13 @@
     public abstract int GetRepeatedFieldCount(FieldDescriptor field);
     public abstract object this[FieldDescriptor field, int index] { get; }
     public abstract UnknownFieldSet UnknownFields { get; }
-    public abstract TMessage DefaultInstanceForType { get; }
-    public abstract TBuilder CreateBuilderForType();
-    public abstract TBuilder ToBuilder();
     #endregion
-    
-    public IBuilder WeakCreateBuilderForType() {
-      return CreateBuilderForType();
-    }
 
-    public IBuilder WeakToBuilder() {
-      return ToBuilder();
-    }
-
-    IMessageLite IMessageLite.WeakDefaultInstanceForType {
-      get { return DefaultInstanceForType; }
-    }
-
-    public IMessage WeakDefaultInstanceForType {
-      get { return DefaultInstanceForType; }
-    }
-
-    public virtual bool IsInitialized {
+    /// <summary>
+    /// Returns true iff all required fields in the message and all embedded
+    /// messages are set.
+    /// </summary>
+    public override bool IsInitialized {
       get {
         // Check that all required fields are present.
         foreach (FieldDescriptor field in DescriptorForType.Fields) {
@@ -116,7 +101,19 @@
       return TextFormat.PrintToString(this);
     }
 
-    public virtual void WriteTo(CodedOutputStream output) {
+    /// <summary>
+    /// Serializes the message and writes it to the given output stream.
+    /// This does not flush or close the stream.
+    /// </summary>
+    /// <remarks>
+    /// Protocol Buffers are not self-delimiting. Therefore, if you write
+    /// any more data to the stream after the message, you must somehow ensure
+    /// that the parser on the receiving end does not interpret this as being
+    /// part of the protocol message. One way of doing this is by writing the size
+    /// of the message before the data, then making sure you limit the input to
+    /// that size when receiving the data. Alternatively, use WriteDelimitedTo(Stream).
+    /// </remarks>
+    public override void WriteTo(CodedOutputStream output) {
       foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
         FieldDescriptor field = entry.Key;
         if (field.IsRepeated) {
@@ -151,7 +148,11 @@
       }
     }
 
-    public virtual int SerializedSize {
+    /// <summary>
+    /// Returns the number of bytes required to encode this message.
+    /// The result is only computed on the first call and memoized after that.
+    /// </summary>
+    public override int SerializedSize {
       get {
         if (memoizedSize != null) {
           return memoizedSize.Value;
@@ -192,33 +193,12 @@
       }
     }
 
-    public ByteString ToByteString() {
-      ByteString.CodedBuilder output = new ByteString.CodedBuilder(SerializedSize);
-      WriteTo(output.CodedOutput);
-      return output.Build();
-    }
-
-    public byte[] ToByteArray() {
-      byte[] result = new byte[SerializedSize];
-      CodedOutputStream output = CodedOutputStream.CreateInstance(result);
-      WriteTo(output);
-      output.CheckNoSpaceLeft();
-      return result;
-    }
-
-    public void WriteTo(Stream output) {
-      CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
-      WriteTo(codedOutput);
-      codedOutput.Flush();
-    }
-
-    public void WriteDelimitedTo(Stream output) {
-      CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
-      codedOutput.WriteRawVarint32((uint) SerializedSize);
-      WriteTo(codedOutput);
-      codedOutput.Flush();
-    }
-
+    /// <summary>
+    /// Compares the specified object with this message for equality.
+    /// Returns true iff the given object is a message of the same type
+    /// (as defined by DescriptorForType) and has identical values
+    /// for all its fields.
+    /// </summary>
     public override bool Equals(object other) {
       if (other == this) {
         return true;
@@ -230,6 +210,10 @@
       return Dictionaries.Equals(AllFields, otherMessage.AllFields) && UnknownFields.Equals(otherMessage.UnknownFields);
     }
 
+    /// <summary>
+    /// Returns the hash code value for this message.
+    /// TODO(jonskeet): Specify the hash algorithm, but better than the Java one!
+    /// </summary>
     public override int GetHashCode() {
       int hash = 41;
       hash = (19 * hash) + DescriptorForType.GetHashCode();
@@ -238,11 +222,20 @@
       return hash;
     }
 
-    IBuilderLite IMessageLite.WeakCreateBuilderForType() {
-      return WeakCreateBuilderForType(); }
-
-    IBuilderLite IMessageLite.WeakToBuilder() {
-      return WeakToBuilder();
+    #region Explicit Members
+    
+    IBuilder IMessage.WeakCreateBuilderForType() {
+      return CreateBuilderForType();
     }
+
+    IBuilder IMessage.WeakToBuilder() {
+      return ToBuilder();
+    }
+
+    IMessage IMessage.WeakDefaultInstanceForType {
+      get { return DefaultInstanceForType; }
+    }
+
+    #endregion
   }
 }