Refactored options
diff --git a/src/ProtoGen.Test/DescriptorUtilTest.cs b/src/ProtoGen.Test/DescriptorUtilTest.cs
index 0cbc1c3..2eb60ef 100644
--- a/src/ProtoGen.Test/DescriptorUtilTest.cs
+++ b/src/ProtoGen.Test/DescriptorUtilTest.cs
@@ -5,7 +5,7 @@
 namespace Google.ProtocolBuffers.ProtoGen {
   [TestFixture]
   public class DescriptorUtilTest {
-
+    /* FIXME: Move these around!
     [Test]
     public void ExplicitNamespace() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder {
@@ -64,6 +64,6 @@
       FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "x/y/foo_bar" }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
       Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor));
-    }
+    } */
   }
 }
diff --git a/src/ProtoGen.Test/HelpersTest.cs b/src/ProtoGen.Test/HelpersTest.cs
deleted file mode 100644
index 6896cfb..0000000
--- a/src/ProtoGen.Test/HelpersTest.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using Google.ProtocolBuffers.ProtoGen;
-using NUnit.Framework;
-
-namespace Google.ProtocolBuffers.ProtoGen {
-  [TestFixture]
-  public class HelpersTest {
-
-    [Test]
-    public void UnderscoresToPascalCase() {
-      Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("Foo_bar"));
-      Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("foo_bar"));
-      Assert.AreEqual("Foo0Bar", Helpers.UnderscoresToPascalCase("Foo0bar"));
-      Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("Foo_+_Bar"));
-    }
-
-    [Test]
-    public void UnderscoresToCamelCase() {
-      Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("Foo_bar"));
-      Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("foo_bar"));
-      Assert.AreEqual("foo0Bar", Helpers.UnderscoresToCamelCase("Foo0bar"));
-      Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("Foo_+_Bar"));
-    }
-
-    [Test]
-    public void StripSuffix() {
-      string text = "FooBar";
-      Assert.IsFalse(Helpers.StripSuffix(ref text, "Foo"));
-      Assert.AreEqual("FooBar", text);
-      Assert.IsTrue(Helpers.StripSuffix(ref text, "Bar"));
-      Assert.AreEqual("Foo", text);
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/ProtoGen.Test/ProtoGen.Test.csproj b/src/ProtoGen.Test/ProtoGen.Test.csproj
index 805c69a..a133449 100644
--- a/src/ProtoGen.Test/ProtoGen.Test.csproj
+++ b/src/ProtoGen.Test/ProtoGen.Test.csproj
@@ -47,7 +47,6 @@
     <Compile Include="DependencyResolutionTest.cs" />
     <Compile Include="DescriptorUtilTest.cs" />
     <Compile Include="GeneratorTest.cs" />
-    <Compile Include="HelpersTest.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
diff --git a/src/ProtoGen/DescriptorUtil.cs b/src/ProtoGen/DescriptorUtil.cs
index 72df575..1d479bf 100644
--- a/src/ProtoGen/DescriptorUtil.cs
+++ b/src/ProtoGen/DescriptorUtil.cs
@@ -10,80 +10,11 @@
   /// </summary>
   internal static class DescriptorUtil {
 
-    internal static bool NestClasses(IDescriptor descriptor) {
-      // Defaults to false
-      return descriptor.File.Options.GetExtension(CSharpOptions.CSharpNestClasses);
-    }
-
-    internal static string GetNamespace(FileDescriptor descriptor) {
-      if (descriptor.Name == "google/protobuf/descriptor.proto") {
-        return typeof(DescriptorProtoFile).Namespace;
-      }
-      return descriptor.Options.HasExtension(CSharpOptions.CSharpNamespace) ?
-          descriptor.Options.GetExtension(CSharpOptions.CSharpNamespace) : descriptor.Package;
-    }
-
-    // Groups are hacky:  The name of the field is just the lower-cased name
-    // of the group type.  In C#, though, we would like to retain the original
-    // capitalization of the type name.
-    internal static string GetFieldName(FieldDescriptor descriptor) {
-      if (descriptor.FieldType == FieldType.Group) {
-        return descriptor.MessageType.Name;
-      } else {
-        return descriptor.Name;
-      }
-    }
-
-    internal static string GetClassName(IDescriptor descriptor) {
-      return ToCSharpName(descriptor.FullName, descriptor.File);
-    }
-
-    internal static string GetFullUmbrellaClassName(FileDescriptor descriptor) {
-      string result = GetNamespace(descriptor);
+    internal static string GetFullUmbrellaClassName(IDescriptor descriptor) {
+      CSharpFileOptions options = descriptor.File.CSharpOptions;
+      string result = options.Namespace;
       if (result != "") result += '.';
-      result += GetUmbrellaClassName(descriptor);
-      return "global::" + result;
-    }
-
-    internal static string GetUmbrellaClassName(FileDescriptor descriptor) {
-      if (descriptor.Name == "google/protobuf/descriptor.proto") {
-        return typeof(DescriptorProtoFile).Name;
-      }
-      FileOptions options = descriptor.Options;
-      if (options.HasExtension(CSharpOptions.CSharpUmbrellaClassname)) {
-        return descriptor.Options.GetExtension(CSharpOptions.CSharpUmbrellaClassname);
-      }
-      int lastSlash = descriptor.Name.LastIndexOf('/');
-      string baseName = descriptor.Name.Substring(lastSlash + 1);
-      return Helpers.UnderscoresToPascalCase(StripProto(baseName));
-    }
-
-    private static string StripProto(string text) {
-      if (!Helpers.StripSuffix(ref text, ".protodevel")) {
-        Helpers.StripSuffix(ref text, ".proto");
-      }
-      return text;
-    }
-
-    private static string ToCSharpName(string name, FileDescriptor file) {
-      string result;
-      if (!NestClasses(file)) {
-        result = GetNamespace(file);
-      } else {
-        result = GetUmbrellaClassName(file);
-      }
-      if (result != "") {
-        result += '.';
-      }
-      string classname;
-      if (file.Package == "") {
-        classname = name;
-      } else {
-        // Strip the proto package from full_name since we've replaced it with
-        // the C# namespace.
-        classname = name.Substring(file.Package.Length + 1);
-      }
-      result += classname.Replace(".", ".Types.");
+      result += options.UmbrellaClassname;
       return "global::" + result;
     }
 
diff --git a/src/ProtoGen/ExtensionGenerator.cs b/src/ProtoGen/ExtensionGenerator.cs
index d5a233b..d1acacd 100644
--- a/src/ProtoGen/ExtensionGenerator.cs
+++ b/src/ProtoGen/ExtensionGenerator.cs
@@ -9,15 +9,15 @@
     }
 
     public void Generate(TextGenerator writer) {
-      string name = Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(Descriptor));
+      string name = NameHelpers.UnderscoresToPascalCase(GetFieldName(Descriptor));
 
       string type;
       switch (Descriptor.MappedType) {
         case MappedType.Message:
-          type = DescriptorUtil.GetClassName(Descriptor.MessageType);
+          type = GetClassName(Descriptor.MessageType);
           break;
         case MappedType.Enum:
-          type = DescriptorUtil.GetClassName(Descriptor.EnumType);
+          type = GetClassName(Descriptor.EnumType);
           break;
         default:
           type = DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
diff --git a/src/ProtoGen/FieldGeneratorBase.cs b/src/ProtoGen/FieldGeneratorBase.cs
index 6c8f541..a6e086e 100644
--- a/src/ProtoGen/FieldGeneratorBase.cs
+++ b/src/ProtoGen/FieldGeneratorBase.cs
@@ -50,7 +50,7 @@
             if (!Descriptor.HasDefaultValue) {
               return "pb::ByteString.Empty";
             }
-            return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", DescriptorUtil.GetClassName(Descriptor.ContainingType), Descriptor.Index);
+            return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
           case FieldType.String:
             if (AllPrintableAscii(Descriptor.Proto.DefaultValue)) {
               // All chars are ASCII and printable.  In this case we only
@@ -61,7 +61,7 @@
                   .Replace("\"", "\\\"")
                   + "\"";
             }
-            return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", DescriptorUtil.GetClassName(Descriptor.ContainingType), Descriptor.Index);
+            return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index);
           case FieldType.Enum:
             return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name;
           case FieldType.Message:
@@ -88,11 +88,11 @@
     }
 
     protected string CapitalizedName {
-      get { return Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(Descriptor)); }
+      get { return NameHelpers.UnderscoresToPascalCase(GetFieldName(Descriptor)); }
     }
 
     protected string Name {
-      get { return Helpers.UnderscoresToCamelCase(DescriptorUtil.GetFieldName(Descriptor)); }
+      get { return NameHelpers.UnderscoresToCamelCase(GetFieldName(Descriptor)); }
     }
 
     protected int Number {
@@ -103,10 +103,10 @@
       get {
         switch (Descriptor.FieldType) {
           case FieldType.Enum:
-            return DescriptorUtil.GetClassName(Descriptor.EnumType);
+            return GetClassName(Descriptor.EnumType);
           case FieldType.Message:
           case FieldType.Group:
-            return DescriptorUtil.GetClassName(Descriptor.MessageType);
+            return GetClassName(Descriptor.MessageType);
           default:
             return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
         }
diff --git a/src/ProtoGen/Generator.cs b/src/ProtoGen/Generator.cs
index b447d42..f7a82cc 100644
--- a/src/ProtoGen/Generator.cs
+++ b/src/ProtoGen/Generator.cs
@@ -30,11 +30,8 @@
       foreach (string inputFile in options.InputFiles) {
         FileDescriptorSet descriptorProtos;       
         ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
-        extensionRegistry.Add(CSharpOptions.CSharpUmbrellaClassname);
-        extensionRegistry.Add(CSharpOptions.CSharpMultipleFiles);
-        extensionRegistry.Add(CSharpOptions.CSharpNamespace);
-        extensionRegistry.Add(CSharpOptions.CSharpNestClasses);
-        extensionRegistry.Add(CSharpOptions.CSharpPublicClasses);
+        extensionRegistry.Add(CSharpFileOptions.CSharpOptions);
+        extensionRegistry.Add(CSharpFieldOptions.CSharpOptions);
         using (Stream inputStream = File.OpenRead(inputFile)) {
           descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry);
         }
@@ -51,12 +48,9 @@
     /// already have been resolved.
     /// </summary>
     private void Generate(FileDescriptor descriptor) {
-      string umbrellaClass = DescriptorUtil.GetUmbrellaClassName(descriptor);
-      string ns = DescriptorUtil.GetNamespace(descriptor);
-      using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, umbrellaClass + ".cs"))) {
-        TextGenerator writer = new TextGenerator(textWriter);
-        
-        UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor);
+      UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor);
+      using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, descriptor.CSharpOptions.UmbrellaClassname + ".cs"))) {
+        TextGenerator writer = new TextGenerator(textWriter);        
         ucg.Generate(writer);
         /*
         GenerateSiblings(umbrellaSource, descriptor, descriptor.MessageTypes);
diff --git a/src/ProtoGen/Helpers.cs b/src/ProtoGen/Helpers.cs
index 74697bf..a6a0e6c 100644
--- a/src/ProtoGen/Helpers.cs
+++ b/src/ProtoGen/Helpers.cs
@@ -8,71 +8,11 @@
   /// Helpers to resolve class names etc.
   /// </summary>
   internal static class Helpers {
-    internal static string UnderscoresToPascalCase(string input) {
-      return UnderscoresToPascalOrCamelCase(input, true);
-    }
-
-    internal static string UnderscoresToCamelCase(string input) {
-      return UnderscoresToPascalOrCamelCase(input, false);
-    }
-
     internal static void WriteNamespaces(TextGenerator writer) {
       writer.WriteLine("using pb = global::Google.ProtocolBuffers;");
       writer.WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;");
       writer.WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;");
       writer.WriteLine("using scg = global::System.Collections.Generic;");
     }
-
-    /// <summary>
-    /// Converts a string to Pascal or Camel case. The first letter is capitalized or
-    /// lower-cased depending on <paramref name="pascal"/> is true. 
-    /// After the first letter, any punctuation is removed but triggers capitalization
-    /// of the next letter. Digits are preserved but trigger capitalization of the next
-    /// letter.
-    /// All capitalisation is done in the invariant culture. 
-    /// </summary>
-    private static string UnderscoresToPascalOrCamelCase(string input, bool pascal) {
-      StringBuilder result = new StringBuilder();
-      bool capitaliseNext = pascal;
-      for (int i=0; i < input.Length; i++) {
-        char c = input[i];
-        if ('a' <= c && c <= 'z') {
-          if (capitaliseNext) {
-            result.Append(char.ToUpperInvariant(c));
-          } else {
-            result.Append(c);
-          }
-          capitaliseNext = false;
-        } else if ('A' <= c && c <= 'Z') {
-          if (i == 0 && !pascal) {
-            // Force first letter to lower-case unless explicitly told to
-            // capitalize it.
-            result.Append(char.ToLowerInvariant(c));
-          } else {
-            // Capital letters after the first are left as-is.
-            result.Append(c);
-          }
-          capitaliseNext = false;
-        } else if ('0' <= c && c <= '9') {
-          result.Append(c);
-          capitaliseNext = true;
-        } else {
-          capitaliseNext = true;
-        }
-      }
-      return result.ToString();
-    }
-
-    /// <summary>
-    /// Attempts to strip a suffix from a string, returning whether
-    /// or not the suffix was actually present.
-    /// </summary>
-    internal static bool StripSuffix(ref string text, string suffix) {
-      if (text.EndsWith(suffix)) {
-        text = text.Substring(0, text.Length - suffix.Length);
-        return true;
-      }
-      return false;
-    }
   }
 }
diff --git a/src/ProtoGen/MessageGenerator.cs b/src/ProtoGen/MessageGenerator.cs
index 52dc6d0..f877ac6 100644
--- a/src/ProtoGen/MessageGenerator.cs
+++ b/src/ProtoGen/MessageGenerator.cs
@@ -15,7 +15,7 @@
     }
 
     private string FullClassName {
-      get { return DescriptorUtil.GetClassName(Descriptor); }
+      get { return GetClassName(Descriptor); }
     }
 
     /// <summary>
@@ -38,7 +38,7 @@
       string identifier = GetUniqueFileScopeIdentifier(Descriptor);
 
       // The descriptor for this type.
-      string access = Descriptor.File.Options.GetExtension(CSharpOptions.CSharpNestClasses) ? "private" : "internal";
+      string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal";
       writer.WriteLine("{0} static readonly pbd::MessageDescriptor internal__{1}__Descriptor", access, identifier);
       if (Descriptor.ContainingType == null) {
         writer.WriteLine("    = Descriptor.MessageTypes[{0}];", Descriptor.Index);
@@ -51,7 +51,7 @@
           FullClassName, identifier);
       writer.Print("        new string[] { ");
       foreach (FieldDescriptor field in Descriptor.Fields) {
-        writer.Write("\"{0}\", ", Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(field)));
+        writer.Write("\"{0}\", ", NameHelpers.UnderscoresToPascalCase(GetFieldName(field)));
       }
       writer.WriteLine("});");
 
@@ -80,12 +80,12 @@
       writer.WriteLine("}");
       writer.WriteLine();
       writer.WriteLine("public static pbd::MessageDescriptor Descriptor {");
-      writer.WriteLine("  get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor.File),
+      writer.WriteLine("  get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
           GetUniqueFileScopeIdentifier(Descriptor));
       writer.WriteLine("}");
       writer.WriteLine();
       writer.WriteLine("protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{", ClassName);
-      writer.WriteLine("  get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor.File),
+      writer.WriteLine("  get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
           GetUniqueFileScopeIdentifier(Descriptor));
       writer.WriteLine("}");
       writer.WriteLine();
@@ -186,7 +186,7 @@
       writer.WriteLine();
     }
 
-    private static void GenerateSerializeOneField(TextGenerator writer, FieldDescriptor fieldDescriptor) {
+    private void GenerateSerializeOneField(TextGenerator writer, FieldDescriptor fieldDescriptor) {
       SourceGenerators.CreateFieldGenerator(fieldDescriptor).GenerateSerializationCode(writer);
     }
 
@@ -415,7 +415,7 @@
       // "has" fields into a single bitfield.
       foreach (FieldDescriptor field in Descriptor.Fields) {
         if (field.IsRequired) {
-          writer.WriteLine("if (!has{0}) return false;", Helpers.UnderscoresToPascalCase(field.Name));
+          writer.WriteLine("if (!has{0}) return false;", NameHelpers.UnderscoresToPascalCase(field.Name));
         }
       }
   
@@ -425,9 +425,9 @@
             !HasRequiredFields(field.MessageType, new Dictionary<MessageDescriptor, object>())) {
           continue;
         }
-        string propertyName = Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(field));
+        string propertyName = NameHelpers.UnderscoresToPascalCase(GetFieldName(field));
         if (field.IsRepeated) {
-          writer.WriteLine("foreach ({0} element in {1}List) {{", DescriptorUtil.GetClassName(field.MessageType), propertyName);
+          writer.WriteLine("foreach ({0} element in {1}List) {{", GetClassName(field.MessageType), propertyName);
           writer.WriteLine("  if (!element.IsInitialized) return false;");
           writer.WriteLine("}");
         } else if (field.IsOptional) {
diff --git a/src/ProtoGen/ProtoGen.csproj b/src/ProtoGen/ProtoGen.csproj
index f48df42..126c1d0 100644
--- a/src/ProtoGen/ProtoGen.csproj
+++ b/src/ProtoGen/ProtoGen.csproj
@@ -36,6 +36,8 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="DescriptorUtil.cs" />
diff --git a/src/ProtoGen/ServiceGenerator.cs b/src/ProtoGen/ServiceGenerator.cs
index d36eec1..ebc9d46 100644
--- a/src/ProtoGen/ServiceGenerator.cs
+++ b/src/ProtoGen/ServiceGenerator.cs
@@ -20,17 +20,17 @@
       writer.Indent();
 
       foreach (MethodDescriptor method in Descriptor.Methods) {
-        writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel, Helpers.UnderscoresToPascalCase(method.Name));
+        writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel, NameHelpers.UnderscoresToPascalCase(method.Name));
         writer.WriteLine("    pb::IRpcController controller,");
-        writer.WriteLine("    {0} request,", DescriptorUtil.GetClassName(method.InputType));
-        writer.WriteLine("    global::System.Action<{0}> done);", DescriptorUtil.GetClassName(method.OutputType));
+        writer.WriteLine("    {0} request,", GetClassName(method.InputType));
+        writer.WriteLine("    global::System.Action<{0}> done);", GetClassName(method.OutputType));
       }
 
       // Generate Descriptor and DescriptorForType.
       writer.WriteLine();
       writer.WriteLine("{0} static pbd::ServiceDescriptor Descriptor {{", ClassAccessLevel);
       writer.WriteLine("  get {{ return {0}.Descriptor.Services[{1}]; }}",
-          DescriptorUtil.GetUmbrellaClassName(Descriptor.File), Descriptor.Index);
+        Descriptor.File.CSharpOptions.UmbrellaClassname, Descriptor.Index);
       writer.WriteLine("}");
       writer.WriteLine("{0} pbd::ServiceDescriptor DescriptorForType {{", ClassAccessLevel);
       writer.WriteLine("  get { return Descriptor; }");
@@ -62,8 +62,8 @@
       foreach (MethodDescriptor method in Descriptor.Methods) {
         writer.WriteLine("case {0}:", method.Index);
         writer.WriteLine("  this.{0}(controller, ({1}) request,",
-            Helpers.UnderscoresToPascalCase(method.Name), DescriptorUtil.GetClassName(method.InputType));
-        writer.WriteLine("      pb::RpcUtil.SpecializeCallback<{0}>(", DescriptorUtil.GetClassName(method.OutputType));
+            NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType));
+        writer.WriteLine("      pb::RpcUtil.SpecializeCallback<{0}>(", GetClassName(method.OutputType));
         writer.WriteLine("      done));");
         writer.WriteLine("  return;");
       }
@@ -89,7 +89,7 @@
       foreach (MethodDescriptor method in Descriptor.Methods) {
         writer.WriteLine("case {0}:", method.Index);
         writer.WriteLine("  return {0}.DefaultInstance;", 
-          DescriptorUtil.GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType));
+          GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType));
       }
       writer.WriteLine("default:");
       writer.WriteLine("  throw new global::System.InvalidOperationException(\"Can't get here.\");");
@@ -105,7 +105,7 @@
       writer.WriteLine("  return new Stub(channel);");
       writer.WriteLine("}");
       writer.WriteLine();
-      writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, DescriptorUtil.GetClassName(Descriptor));
+      writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, GetClassName(Descriptor));
       writer.Indent();
       writer.WriteLine("internal Stub(pb::IRpcChannel channel) {");
       writer.WriteLine("  this.channel = channel;");
@@ -119,15 +119,15 @@
 
       foreach (MethodDescriptor method in Descriptor.Methods) {
         writer.WriteLine();
-        writer.WriteLine("public override void {0}(", Helpers.UnderscoresToPascalCase(method.Name));
+        writer.WriteLine("public override void {0}(", NameHelpers.UnderscoresToPascalCase(method.Name));
         writer.WriteLine("    pb::IRpcController controller,");
-        writer.WriteLine("    {0} request,", DescriptorUtil.GetClassName(method.InputType));
-        writer.WriteLine("    global::System.Action<{0}> done) {{", DescriptorUtil.GetClassName(method.OutputType));
+        writer.WriteLine("    {0} request,", GetClassName(method.InputType));
+        writer.WriteLine("    global::System.Action<{0}> done) {{", GetClassName(method.OutputType));
         writer.Indent();
         writer.WriteLine("channel.CallMethod(Descriptor.Methods[{0}],", method.Index);
-        writer.WriteLine("    controller, request, {0}.DefaultInstance,", DescriptorUtil.GetClassName(method.OutputType));
+        writer.WriteLine("    controller, request, {0}.DefaultInstance,", GetClassName(method.OutputType));
         writer.WriteLine("    pb::RpcUtil.GeneralizeCallback<{0}, {0}.Builder>(done, {0}.DefaultInstance));",
-            DescriptorUtil.GetClassName(method.OutputType));
+            GetClassName(method.OutputType));
         writer.Outdent();
         writer.WriteLine("}");
       }
diff --git a/src/ProtoGen/SourceGeneratorBase.cs b/src/ProtoGen/SourceGeneratorBase.cs
index 7787d59..6abe1dd 100644
--- a/src/ProtoGen/SourceGeneratorBase.cs
+++ b/src/ProtoGen/SourceGeneratorBase.cs
@@ -1,5 +1,5 @@
+using System;
 using System.Collections.Generic;
-using Google.ProtocolBuffers.DescriptorProtos;
 using Google.ProtocolBuffers.Descriptors;
 
 namespace Google.ProtocolBuffers.ProtoGen {
@@ -15,19 +15,51 @@
       get { return descriptor; }
     }
 
-    protected string ClassAccessLevel {
-      get { 
-        // Default to public
-        return !descriptor.File.Options.HasExtension(CSharpOptions.CSharpPublicClasses)
-            || descriptor.File.Options.GetExtension(CSharpOptions.CSharpPublicClasses) ? "public" : "internal";
+    internal static string GetClassName(IDescriptor descriptor) {
+      return ToCSharpName(descriptor.FullName, descriptor.File);
+    }
+
+    // Groups are hacky:  The name of the field is just the lower-cased name
+    // of the group type.  In C#, though, we would like to retain the original
+    // capitalization of the type name.
+    internal static string GetFieldName(FieldDescriptor descriptor) {
+      if (descriptor.FieldType == FieldType.Group) {
+        return descriptor.MessageType.Name;
+      } else {
+        return descriptor.Name;
       }
     }
 
-    public bool MultipleFiles {
-      get { return descriptor.File.Options.GetExtension(CSharpOptions.CSharpMultipleFiles); }
+    private static string ToCSharpName(string name, FileDescriptor file) {
+      string result = file.CSharpOptions.Namespace;
+      if (file.CSharpOptions.NestClasses) {
+        if (result != "") {
+          result += ".";
+        }
+        result += file.CSharpOptions.UmbrellaClassname;
+      }
+      if (result != "") {
+        result += '.';
+      }
+      string classname;
+      if (file.Package == "") {
+        classname = name;
+      } else {
+        // Strip the proto package from full_name since we've replaced it with
+        // the C# namespace.
+        classname = name.Substring(file.Package.Length + 1);
+      }
+      result += classname.Replace(".", ".Types.");
+      return "global::" + result;
     }
 
-    protected static void WriteChildren<TChild>(TextGenerator writer, string region, IEnumerable<TChild> children) 
+    protected string ClassAccessLevel {
+      get { 
+        return descriptor.File.CSharpOptions.PublicClasses ? "public" : "internal";
+      }
+    }
+
+    protected void WriteChildren<TChild>(TextGenerator writer, string region, IEnumerable<TChild> children) 
         where TChild : IDescriptor {
       // Copy the set of children; makes access easier
       List<TChild> copy = new List<TChild>(children);
diff --git a/src/ProtoGen/UmbrellaClassGenerator.cs b/src/ProtoGen/UmbrellaClassGenerator.cs
index cbb5068..938507b 100644
--- a/src/ProtoGen/UmbrellaClassGenerator.cs
+++ b/src/ProtoGen/UmbrellaClassGenerator.cs
@@ -13,6 +13,10 @@
       : base(descriptor) {
     }
 
+    public string UmbrellaClassName {
+      get { throw new NotImplementedException(); }
+    }
+
     public void Generate(TextGenerator writer) {
       WriteIntroduction(writer);
       WriteDescriptor(writer);
@@ -23,18 +27,18 @@
       }
       writer.WriteLine("#endregion");
       // The class declaration either gets closed before or after the children are written.
-      if (!DescriptorUtil.NestClasses(Descriptor)) {
+      if (!Descriptor.CSharpOptions.NestClasses) {
         writer.Outdent();
         writer.WriteLine("}");
       }
       WriteChildren(writer, "Enums", Descriptor.EnumTypes);
       WriteChildren(writer, "Messages", Descriptor.MessageTypes);
       WriteChildren(writer, "Services", Descriptor.Services);
-      if (DescriptorUtil.NestClasses(Descriptor)) {
+      if (Descriptor.CSharpOptions.NestClasses) {
         writer.Outdent();
         writer.WriteLine("}");
       }
-      if (DescriptorUtil.GetNamespace(Descriptor) != "") {
+      if (Descriptor.CSharpOptions.Namespace != "") {
         writer.Outdent();
         writer.WriteLine("}");
       }
@@ -45,13 +49,13 @@
       writer.WriteLine();
       Helpers.WriteNamespaces(writer);
 
-      if (DescriptorUtil.GetNamespace(Descriptor) != "") {
-        writer.WriteLine("namespace {0} {{", DescriptorUtil.GetNamespace(Descriptor));
+      if (Descriptor.CSharpOptions.Namespace != "") {
+        writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace);
         writer.Indent();
         writer.WriteLine();
       }
 
-      writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, DescriptorUtil.GetUmbrellaClassName(Descriptor));
+      writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, Descriptor.CSharpOptions.UmbrellaClassname);
       writer.WriteLine();
       writer.Indent();
     }
@@ -79,11 +83,6 @@
 
       writer.WriteLine("new pbd::FileDescriptor[] {");
       foreach (FileDescriptor dependency in Descriptor.Dependencies) {
-        // TODO(jonskeet): The normal code won't work for the bootstrapping descriptor, because we don't get unknown fields :(
-        if (dependency.Package == "google.protobuf" && dependency.Name.EndsWith("descriptor.proto")) {
-          writer.WriteLine("  global::" + typeof(DescriptorProtoFile).FullName + ".Descriptor, ");
-          continue;
-        }
         writer.WriteLine("  {0}.Descriptor, ", DescriptorUtil.GetFullUmbrellaClassName(dependency));
       }
       writer.WriteLine("});");
diff --git a/src/ProtocolBuffers.Test/NameHelpersTest.cs b/src/ProtocolBuffers.Test/NameHelpersTest.cs
new file mode 100644
index 0000000..0bdab19
--- /dev/null
+++ b/src/ProtocolBuffers.Test/NameHelpersTest.cs
@@ -0,0 +1,32 @@
+using NUnit.Framework;
+
+namespace Google.ProtocolBuffers {
+  [TestFixture]
+  public class NameHelpersTest {
+
+    [Test]
+    public void UnderscoresToPascalCase() {
+      Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("Foo_bar"));
+      Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("foo_bar"));
+      Assert.AreEqual("Foo0Bar", NameHelpers.UnderscoresToPascalCase("Foo0bar"));
+      Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("Foo_+_Bar"));
+    }
+
+    [Test]
+    public void UnderscoresToCamelCase() {
+      Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("Foo_bar"));
+      Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("foo_bar"));
+      Assert.AreEqual("foo0Bar", NameHelpers.UnderscoresToCamelCase("Foo0bar"));
+      Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("Foo_+_Bar"));
+    }
+
+    [Test]
+    public void StripSuffix() {
+      string text = "FooBar";
+      Assert.IsFalse(NameHelpers.StripSuffix(ref text, "Foo"));
+      Assert.AreEqual("FooBar", text);
+      Assert.IsTrue(NameHelpers.StripSuffix(ref text, "Bar"));
+      Assert.AreEqual("Foo", text);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj b/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
index 7f84da0..836ee2d 100644
--- a/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
+++ b/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
@@ -42,6 +42,8 @@
       <HintPath>..\..\lib\Rhino.Mocks.dll</HintPath>
     </Reference>
     <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AbstractMessageTest.cs" />
@@ -55,6 +57,7 @@
     <Compile Include="MessageStreamIteratorTest.cs" />
     <Compile Include="MessageStreamWriterTest.cs" />
     <Compile Include="MessageTest.cs" />
+    <Compile Include="NameHelpersTest.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ReflectionTester.cs" />
     <Compile Include="ServiceTest.cs" />
diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs
index 8a1def5..ff777cb 100644
--- a/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs
+++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs
@@ -109,9 +109,9 @@
         "Zi5NZXNzYWdlT3B0aW9ucxjvi9IDIAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0" + 
         "LkNvbXBsZXhPcHRpb25UeXBlMzpXCgtjb21wbGV4b3B0NhIfLmdvb2dsZS5w" + 
         "cm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjMy88DIAEoCjIeLnByb3RvYnVmX3Vu" + 
-        "aXR0ZXN0LkNvbXBsZXhPcHQ2QlCC4gkhR29vZ2xlLlByb3RvY29sQnVmZmVy" + 
-        "cy5UZXN0UHJvdG9ziuIJHlVuaXRUZXN0Q3VzdG9tT3B0aW9uc1Byb3RvRmls" + 
-        "ZfDowR3qrcDlJA=="),
+        "aXR0ZXN0LkNvbXBsZXhPcHQ2Qk/CPkMKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZl" + 
+        "cnMuVGVzdFByb3RvcxIeVW5pdFRlc3RDdXN0b21PcHRpb25zUHJvdG9GaWxl" + 
+        "8OjBHeqtwOUk"),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs
index 9dcbf1f..c31de51 100644
--- a/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs
+++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs
@@ -21,9 +21,9 @@
         "ci5wcm90byKhAQoZVGVzdEVtYmVkT3B0aW1pemVkRm9yU2l6ZRJBChBvcHRp" + 
         "b25hbF9tZXNzYWdlGAEgASgLMicucHJvdG9idWZfdW5pdHRlc3QuVGVzdE9w" + 
         "dGltaXplZEZvclNpemUSQQoQcmVwZWF0ZWRfbWVzc2FnZRgCIAMoCzInLnBy" + 
-        "b3RvYnVmX3VuaXR0ZXN0LlRlc3RPcHRpbWl6ZWRGb3JTaXplQkxIAYLiCSFH" + 
-        "b29nbGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQcm90b3OK4gkhVW5pdFRlc3RF" + 
-        "bWJlZE9wdGltaXplRm9yUHJvdG9GaWxl"),
+        "b3RvYnVmX3VuaXR0ZXN0LlRlc3RPcHRpbWl6ZWRGb3JTaXplQktIAcI+Rgoh" + 
+        "R29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEiFVbml0VGVzdEVt" + 
+        "YmVkT3B0aW1pemVGb3JQcm90b0ZpbGU="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs
index c8f5bef..c774c64 100644
--- a/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs
+++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs
@@ -19,9 +19,9 @@
         "b3B0aW9ucy5wcm90bxogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJv" + 
         "dG8iGgoNSW1wb3J0TWVzc2FnZRIJCgFkGAEgASgFKjwKCkltcG9ydEVudW0S" + 
         "DgoKSU1QT1JUX0ZPTxAHEg4KCklNUE9SVF9CQVIQCBIOCgpJTVBPUlRfQkFa" + 
-        "EAlCXAoYY29tLmdvb2dsZS5wcm90b2J1Zi50ZXN0SAGC4gkhR29vZ2xlLlBy" + 
-        "b3RvY29sQnVmZmVycy5UZXN0UHJvdG9ziuIJF1VuaXRUZXN0SW1wb3J0UHJv" + 
-        "dG9GaWxl"),
+        "EAlCWwoYY29tLmdvb2dsZS5wcm90b2J1Zi50ZXN0SAHCPjwKIUdvb2dsZS5Q" + 
+        "cm90b2NvbEJ1ZmZlcnMuVGVzdFByb3RvcxIXVW5pdFRlc3RJbXBvcnRQcm90" + 
+        "b0ZpbGU="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs
index 72b06d3..e83794e 100644
--- a/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs
+++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs
@@ -28,9 +28,9 @@
         "U2V0GPm7XiABKAsyKy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWVzc2FnZVNl" + 
         "dEV4dGVuc2lvbjIibgoNUmF3TWVzc2FnZVNldBIzCgRpdGVtGAEgAygKMiUu" + 
         "cHJvdG9idWZfdW5pdHRlc3QuUmF3TWVzc2FnZVNldC5JdGVtGigKBEl0ZW0S" + 
-        "DwoHdHlwZV9pZBgCIAIoBRIPCgdtZXNzYWdlGAMgAigMQkZIAYLiCSFHb29n" + 
-        "bGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQcm90b3OK4gkbVW5pdFRlc3RNZXNz" + 
-        "YWdlU2V0UHJvdG9GaWxl"),
+        "DwoHdHlwZV9pZBgCIAIoBRIPCgdtZXNzYWdlGAMgAigMQkVIAcI+QAohR29v" + 
+        "Z2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEhtVbml0VGVzdE1lc3Nh" + 
+        "Z2VTZXRQcm90b0ZpbGU="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs
index cc55577..3129ec4 100644
--- a/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs
+++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs
@@ -26,9 +26,9 @@
         "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZSIpChxU" + 
         "ZXN0UmVxdWlyZWRPcHRpbWl6ZWRGb3JTaXplEgkKAXgYASACKAUiWgocVGVz" + 
         "dE9wdGlvbmFsT3B0aW1pemVkRm9yU2l6ZRI6CgFvGAEgASgLMi8ucHJvdG9i" + 
-        "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZUJHSAKC" + 
-        "4gkhR29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9ziuIJHFVuaXRU" + 
-        "ZXN0T3B0aW1pemVGb3JQcm90b0ZpbGU="),
+        "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZUJGSALC" + 
+        "PkEKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZlcnMuVGVzdFByb3RvcxIcVW5pdFRl" + 
+        "c3RPcHRpbWl6ZUZvclByb3RvRmlsZQ=="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs
index 9e706b0..03195c9 100644
--- a/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs
+++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs
@@ -284,9 +284,9 @@
         "dW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYVSABKAk6AzEyM0ICCAE6QgoT" + 
         "bXlfZXh0ZW5zaW9uX3N0cmluZxIlLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RG" + 
         "aWVsZE9yZGVyaW5ncxgyIAEoCTo/ChBteV9leHRlbnNpb25faW50EiUucHJv" + 
-        "dG9idWZfdW5pdHRlc3QuVGVzdEZpZWxkT3JkZXJpbmdzGAUgASgFQktCDVVu" + 
-        "aXR0ZXN0UHJvdG9IAYLiCSFHb29nbGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQ" + 
-        "cm90b3OK4gkRVW5pdFRlc3RQcm90b0ZpbGU="),
+        "dG9idWZfdW5pdHRlc3QuVGVzdEZpZWxkT3JkZXJpbmdzGAUgASgFQkpCDVVu" + 
+        "aXR0ZXN0UHJvdG9IAcI+NgohR29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0" + 
+        "UHJvdG9zEhFVbml0VGVzdFByb3RvRmlsZQ=="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
diff --git a/src/ProtocolBuffers.Test/TestProtos/___7469.tmp b/src/ProtocolBuffers.Test/TestProtos/___7469.tmp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/ProtocolBuffers.Test/TestProtos/___7469.tmp
diff --git a/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs b/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs
index 14d6bb6..55a3003 100644
--- a/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs
+++ b/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs
@@ -15,35 +15,381 @@
     private static readonly pbd::FileDescriptor descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(
         global::System.Convert.FromBase64String(
         "CiRnb29nbGUvcHJvdG9idWYvY3NoYXJwX29wdGlvbnMucHJvdG8SD2dvb2ds" + 
-        "ZS5wcm90b2J1ZhogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG86" + 
-        "NwoPQ1NoYXJwTmFtZXNwYWNlEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRp" + 
-        "b25zGKCcASABKAk6PwoXQ1NoYXJwVW1icmVsbGFDbGFzc25hbWUSHC5nb29n" + 
-        "bGUucHJvdG9idWYuRmlsZU9wdGlvbnMYoZwBIAEoCTo7ChNDU2hhcnBNdWx0" + 
-        "aXBsZUZpbGVzEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKKcASAB" + 
-        "KAg6OQoRQ1NoYXJwTmVzdENsYXNzZXMSHC5nb29nbGUucHJvdG9idWYuRmls" + 
-        "ZU9wdGlvbnMYo5wBIAEoCDo7ChNDU2hhcnBQdWJsaWNDbGFzc2VzEhwuZ29v" + 
-        "Z2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKScASABKAhCPILiCSdHb29nbGUu" + 
-        "UHJvdG9jb2xCdWZmZXJzLkRlc2NyaXB0b3JQcm90b3OK4gkNQ1NoYXJwT3B0" + 
-        "aW9ucw=="),
+        "ZS5wcm90b2J1ZhogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG8i" + 
+        "4wEKEUNTaGFycEZpbGVPcHRpb25zEhEKCW5hbWVzcGFjZRgBIAEoCRIaChJ1" + 
+        "bWJyZWxsYV9jbGFzc25hbWUYAiABKAkSFgoOcHVibGljX2NsYXNzZXMYAyAB" + 
+        "KAgSFgoObXVsdGlwbGVfZmlsZXMYBCABKAgSFAoMbmVzdF9jbGFzc2VzGAUg" + 
+        "ASgIMlkKDmNzaGFycF9vcHRpb25zEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVP" + 
+        "cHRpb25zGOgHIAEoCzIiLmdvb2dsZS5wcm90b2J1Zi5DU2hhcnBGaWxlT3B0" + 
+        "aW9ucyKIAQoSQ1NoYXJwRmllbGRPcHRpb25zEhUKDXByb3BlcnR5X25hbWUY" + 
+        "ASABKAkyWwoOY3NoYXJwX29wdGlvbnMSHS5nb29nbGUucHJvdG9idWYuRmll" + 
+        "bGRPcHRpb25zGOgHIAEoCzIjLmdvb2dsZS5wcm90b2J1Zi5DU2hhcnBGaWVs" + 
+        "ZE9wdGlvbnM="),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
         });
     #endregion
     
-    #region Extensions
-    public static readonly pb::GeneratedExtensionBase<string> CSharpNamespace =
-        pb::GeneratedSingleExtension<string>.CreateInstance(Descriptor.Extensions[0]);
-    public static readonly pb::GeneratedExtensionBase<string> CSharpUmbrellaClassname =
-        pb::GeneratedSingleExtension<string>.CreateInstance(Descriptor.Extensions[1]);
-    public static readonly pb::GeneratedExtensionBase<bool> CSharpMultipleFiles =
-        pb::GeneratedSingleExtension<bool>.CreateInstance(Descriptor.Extensions[2]);
-    public static readonly pb::GeneratedExtensionBase<bool> CSharpNestClasses =
-        pb::GeneratedSingleExtension<bool>.CreateInstance(Descriptor.Extensions[3]);
-    public static readonly pb::GeneratedExtensionBase<bool> CSharpPublicClasses =
-        pb::GeneratedSingleExtension<bool>.CreateInstance(Descriptor.Extensions[4]);
-    #endregion
-    
     #region Static variables
+    internal static readonly pbd::MessageDescriptor internal__static_google_protobuf_CSharpFileOptions__Descriptor
+        = Descriptor.MessageTypes[0];
+    internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions, global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions.Builder> internal__static_google_protobuf_CSharpFileOptions__FieldAccessorTable
+        = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions, global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions.Builder>(internal__static_google_protobuf_CSharpFileOptions__Descriptor,
+            new string[] { "Namespace", "UmbrellaClassname", "PublicClasses", "MultipleFiles", "NestClasses", });
+    internal static readonly pbd::MessageDescriptor internal__static_google_protobuf_CSharpFieldOptions__Descriptor
+        = Descriptor.MessageTypes[1];
+    internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions, global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions.Builder> internal__static_google_protobuf_CSharpFieldOptions__FieldAccessorTable
+        = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions, global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions.Builder>(internal__static_google_protobuf_CSharpFieldOptions__Descriptor,
+            new string[] { "PropertyName", });
     #endregion
   }
+  #region Messages
+  public sealed partial class CSharpFileOptions : pb::GeneratedMessage<CSharpFileOptions, CSharpFileOptions.Builder> {
+    private static readonly CSharpFileOptions defaultInstance = new Builder().BuildPartial();
+    public static CSharpFileOptions DefaultInstance {
+      get { return defaultInstance; }
+    }
+    
+    public override CSharpFileOptions DefaultInstanceForType {
+      get { return defaultInstance; }
+    }
+    
+    protected override CSharpFileOptions ThisMessage {
+      get { return this; }
+    }
+    
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFileOptions__Descriptor; }
+    }
+    
+    protected override pb::FieldAccess.FieldAccessorTable<CSharpFileOptions, CSharpFileOptions.Builder> InternalFieldAccessors {
+      get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFileOptions__FieldAccessorTable; }
+    }
+    
+    public static readonly pb::GeneratedExtensionBase<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions> CSharpOptions =
+        pb::GeneratedSingleExtension<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions>.CreateInstance(Descriptor.Extensions[0]);
+    private bool hasNamespace;
+    private string namespace_ = "";
+    public bool HasNamespace {
+      get { return hasNamespace; }
+    }
+    public string Namespace {
+      get { return namespace_; }
+    }
+    
+    private bool hasUmbrellaClassname;
+    private string umbrellaClassname_ = "";
+    public bool HasUmbrellaClassname {
+      get { return hasUmbrellaClassname; }
+    }
+    public string UmbrellaClassname {
+      get { return umbrellaClassname_; }
+    }
+    
+    private bool hasPublicClasses;
+    private bool publicClasses_ = false;
+    public bool HasPublicClasses {
+      get { return hasPublicClasses; }
+    }
+    public bool PublicClasses {
+      get { return publicClasses_; }
+    }
+    
+    private bool hasMultipleFiles;
+    private bool multipleFiles_ = false;
+    public bool HasMultipleFiles {
+      get { return hasMultipleFiles; }
+    }
+    public bool MultipleFiles {
+      get { return multipleFiles_; }
+    }
+    
+    private bool hasNestClasses;
+    private bool nestClasses_ = false;
+    public bool HasNestClasses {
+      get { return hasNestClasses; }
+    }
+    public bool NestClasses {
+      get { return nestClasses_; }
+    }
+    
+    public static CSharpFileOptions ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static CSharpFileOptions ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static CSharpFileOptions ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static CSharpFileOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static CSharpFileOptions ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static CSharpFileOptions ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static CSharpFileOptions ParseFrom(pb::CodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static CSharpFileOptions ParseFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(CSharpFileOptions prototype) {
+      return (Builder) new Builder().MergeFrom(prototype);
+    }
+    
+    public sealed partial class Builder : pb::GeneratedBuilder<CSharpFileOptions, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {}
+      
+      CSharpFileOptions result = new CSharpFileOptions();
+      
+      protected override CSharpFileOptions MessageBeingBuilt {
+        get { return result; }
+      }
+      
+      public override Builder Clear() {
+        result = new CSharpFileOptions();
+        return this;
+      }
+      
+      public override Builder Clone() {
+        return new Builder().MergeFrom(result);
+      }
+      
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return CSharpFileOptions.Descriptor; }
+      }
+      
+      public override CSharpFileOptions DefaultInstanceForType {
+        get { return CSharpFileOptions.DefaultInstance; }
+      }
+      
+      public override CSharpFileOptions BuildPartial() {
+        CSharpFileOptions returnMe = result;
+        result = null;
+        return returnMe;
+      }
+      
+      
+      public bool HasNamespace {
+        get { return result.HasNamespace; }
+      }
+      public string Namespace {
+        get { return result.Namespace; }
+        set { SetNamespace(value); }
+      }
+      public Builder SetNamespace(string value) {
+        result.hasNamespace = true;
+        result.namespace_ = value;
+        return this;
+      }
+      public Builder ClearNamespace() {
+        result.hasNamespace = false;
+        result.namespace_ = "";
+        return this;
+      }
+      
+      public bool HasUmbrellaClassname {
+        get { return result.HasUmbrellaClassname; }
+      }
+      public string UmbrellaClassname {
+        get { return result.UmbrellaClassname; }
+        set { SetUmbrellaClassname(value); }
+      }
+      public Builder SetUmbrellaClassname(string value) {
+        result.hasUmbrellaClassname = true;
+        result.umbrellaClassname_ = value;
+        return this;
+      }
+      public Builder ClearUmbrellaClassname() {
+        result.hasUmbrellaClassname = false;
+        result.umbrellaClassname_ = "";
+        return this;
+      }
+      
+      public bool HasPublicClasses {
+        get { return result.HasPublicClasses; }
+      }
+      public bool PublicClasses {
+        get { return result.PublicClasses; }
+        set { SetPublicClasses(value); }
+      }
+      public Builder SetPublicClasses(bool value) {
+        result.hasPublicClasses = true;
+        result.publicClasses_ = value;
+        return this;
+      }
+      public Builder ClearPublicClasses() {
+        result.hasPublicClasses = false;
+        result.publicClasses_ = false;
+        return this;
+      }
+      
+      public bool HasMultipleFiles {
+        get { return result.HasMultipleFiles; }
+      }
+      public bool MultipleFiles {
+        get { return result.MultipleFiles; }
+        set { SetMultipleFiles(value); }
+      }
+      public Builder SetMultipleFiles(bool value) {
+        result.hasMultipleFiles = true;
+        result.multipleFiles_ = value;
+        return this;
+      }
+      public Builder ClearMultipleFiles() {
+        result.hasMultipleFiles = false;
+        result.multipleFiles_ = false;
+        return this;
+      }
+      
+      public bool HasNestClasses {
+        get { return result.HasNestClasses; }
+      }
+      public bool NestClasses {
+        get { return result.NestClasses; }
+        set { SetNestClasses(value); }
+      }
+      public Builder SetNestClasses(bool value) {
+        result.hasNestClasses = true;
+        result.nestClasses_ = value;
+        return this;
+      }
+      public Builder ClearNestClasses() {
+        result.hasNestClasses = false;
+        result.nestClasses_ = false;
+        return this;
+      }
+    }
+  }
+  
+  public sealed partial class CSharpFieldOptions : pb::GeneratedMessage<CSharpFieldOptions, CSharpFieldOptions.Builder> {
+    private static readonly CSharpFieldOptions defaultInstance = new Builder().BuildPartial();
+    public static CSharpFieldOptions DefaultInstance {
+      get { return defaultInstance; }
+    }
+    
+    public override CSharpFieldOptions DefaultInstanceForType {
+      get { return defaultInstance; }
+    }
+    
+    protected override CSharpFieldOptions ThisMessage {
+      get { return this; }
+    }
+    
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFieldOptions__Descriptor; }
+    }
+    
+    protected override pb::FieldAccess.FieldAccessorTable<CSharpFieldOptions, CSharpFieldOptions.Builder> InternalFieldAccessors {
+      get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFieldOptions__FieldAccessorTable; }
+    }
+    
+    public static readonly pb::GeneratedExtensionBase<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions> CSharpOptions =
+        pb::GeneratedSingleExtension<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions>.CreateInstance(Descriptor.Extensions[0]);
+    private bool hasPropertyName;
+    private string propertyName_ = "";
+    public bool HasPropertyName {
+      get { return hasPropertyName; }
+    }
+    public string PropertyName {
+      get { return propertyName_; }
+    }
+    
+    public static CSharpFieldOptions ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static CSharpFieldOptions ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static CSharpFieldOptions ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static CSharpFieldOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static CSharpFieldOptions ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static CSharpFieldOptions ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static CSharpFieldOptions ParseFrom(pb::CodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static CSharpFieldOptions ParseFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(CSharpFieldOptions prototype) {
+      return (Builder) new Builder().MergeFrom(prototype);
+    }
+    
+    public sealed partial class Builder : pb::GeneratedBuilder<CSharpFieldOptions, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {}
+      
+      CSharpFieldOptions result = new CSharpFieldOptions();
+      
+      protected override CSharpFieldOptions MessageBeingBuilt {
+        get { return result; }
+      }
+      
+      public override Builder Clear() {
+        result = new CSharpFieldOptions();
+        return this;
+      }
+      
+      public override Builder Clone() {
+        return new Builder().MergeFrom(result);
+      }
+      
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return CSharpFieldOptions.Descriptor; }
+      }
+      
+      public override CSharpFieldOptions DefaultInstanceForType {
+        get { return CSharpFieldOptions.DefaultInstance; }
+      }
+      
+      public override CSharpFieldOptions BuildPartial() {
+        CSharpFieldOptions returnMe = result;
+        result = null;
+        return returnMe;
+      }
+      
+      
+      public bool HasPropertyName {
+        get { return result.HasPropertyName; }
+      }
+      public string PropertyName {
+        get { return result.PropertyName; }
+        set { SetPropertyName(value); }
+      }
+      public Builder SetPropertyName(string value) {
+        result.hasPropertyName = true;
+        result.propertyName_ = value;
+        return this;
+      }
+      public Builder ClearPropertyName() {
+        result.hasPropertyName = false;
+        result.propertyName_ = "";
+        return this;
+      }
+    }
+  }
+  
+  #endregion
+  
 }
diff --git a/src/ProtocolBuffers/Descriptors/FileDescriptor.cs b/src/ProtocolBuffers/Descriptors/FileDescriptor.cs
index ebb6b15..79e034a 100644
--- a/src/ProtocolBuffers/Descriptors/FileDescriptor.cs
+++ b/src/ProtocolBuffers/Descriptors/FileDescriptor.cs
@@ -50,6 +50,8 @@
     private readonly IList<FieldDescriptor> extensions;
     private readonly IList<FileDescriptor> dependencies;
     private readonly DescriptorPool pool;
+    private CSharpFileOptions csharpFileOptions;
+    private readonly object optionsLock = new object();
     
     private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool) {
       this.pool = pool;
@@ -71,6 +73,44 @@
         (field, index) => new FieldDescriptor(field, this, null, index, true));
     }
 
+    private CSharpFileOptions BuildOrFakeCSharpOptions() {
+      // TODO(jonskeet): Check if we could use FileDescriptorProto.Descriptor.Name - interesting bootstrap issues
+      if (proto.Name == "google/protobuf/descriptor.proto") {
+        return new CSharpFileOptions.Builder {
+          Namespace = "Google.ProtocolBuffers.DescriptorProtos",
+          UmbrellaClassname = "DescriptorProtoFile", NestClasses = false, MultipleFiles = false, PublicClasses = true
+        }.Build();
+      }
+      if (proto.Name == "google/protobuf/csharp_options.proto") {
+        return new CSharpFileOptions.Builder {
+          Namespace = "Google.ProtocolBuffers.DescriptorProtos",
+          UmbrellaClassname = "CSharpOptions", NestClasses = false, MultipleFiles = false, PublicClasses = true
+        }.Build();
+      }
+      CSharpFileOptions.Builder builder = CSharpFileOptions.CreateBuilder();
+      if (proto.Options.HasExtension(CSharpFileOptions.CSharpOptions)) {
+        builder.MergeFrom(proto.Options.GetExtension(CSharpFileOptions.CSharpOptions));
+      }
+      if (!builder.HasNamespace) {
+        builder.Namespace = Package;
+      }
+      if (!builder.HasMultipleFiles) {
+        builder.MultipleFiles = false;
+      }
+      if (!builder.HasNestClasses) {
+        builder.NestClasses = false;
+      }
+      if (!builder.HasPublicClasses) {
+        builder.PublicClasses = true;
+      }
+      if (!builder.HasUmbrellaClassname) {
+        int lastSlash = Name.LastIndexOf('/');
+        string baseName = Name.Substring(lastSlash + 1);
+        builder.UmbrellaClassname = NameHelpers.UnderscoresToPascalCase(NameHelpers.StripProto(baseName));        
+      }
+      return builder.Build();
+    }
+
     /// <value>
     /// The descriptor in its protocol message representation.
     /// </value>
@@ -85,6 +125,22 @@
       get { return proto.Options; }
     }
 
+    /// <summary>
+    /// Returns the C#-specific options for this file descriptor. This will always be
+    /// completely filled in.
+    /// FIXME: This isn't thread-safe. Can't do it at construction time due to bootstrapping issues.
+    /// </summary>
+    public CSharpFileOptions CSharpOptions {
+      get {
+        lock (optionsLock) {
+          if (csharpFileOptions == null) {
+            csharpFileOptions = BuildOrFakeCSharpOptions();
+          }
+        }
+        return csharpFileOptions;
+      }
+    }
+
     /// <value>
     /// The file name.
     /// </value>
@@ -250,7 +306,7 @@
     
     /// <summary>
     /// This method is to be called by generated code only.  It is equivalent
-    /// to BuilderFrom except that the FileDescriptorProto is encoded in
+    /// to BuildFrom except that the FileDescriptorProto is encoded in
     /// protocol buffer wire format.
     /// </summary>
     public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
diff --git a/src/ProtocolBuffers/NameHelpers.cs b/src/ProtocolBuffers/NameHelpers.cs
new file mode 100644
index 0000000..8b297f9
--- /dev/null
+++ b/src/ProtocolBuffers/NameHelpers.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.ProtocolBuffers {
+  /// <summary>
+  /// Helpers for converting names to pascal case etc.
+  /// </summary>
+  internal class NameHelpers {
+
+    internal static string UnderscoresToPascalCase(string input) {
+      return UnderscoresToPascalOrCamelCase(input, true);
+    }
+
+    internal static string UnderscoresToCamelCase(string input) {
+      return UnderscoresToPascalOrCamelCase(input, false);
+    }
+
+    /// <summary>
+    /// Converts a string to Pascal or Camel case. The first letter is capitalized or
+    /// lower-cased depending on <paramref name="pascal"/> is true. 
+    /// After the first letter, any punctuation is removed but triggers capitalization
+    /// of the next letter. Digits are preserved but trigger capitalization of the next
+    /// letter.
+    /// All capitalisation is done in the invariant culture. 
+    /// </summary>
+    private static string UnderscoresToPascalOrCamelCase(string input, bool pascal) {
+      StringBuilder result = new StringBuilder();
+      bool capitaliseNext = pascal;
+      for (int i = 0; i < input.Length; i++) {
+        char c = input[i];
+        if ('a' <= c && c <= 'z') {
+          if (capitaliseNext) {
+            result.Append(char.ToUpperInvariant(c));
+          } else {
+            result.Append(c);
+          }
+          capitaliseNext = false;
+        } else if ('A' <= c && c <= 'Z') {
+          if (i == 0 && !pascal) {
+            // Force first letter to lower-case unless explicitly told to
+            // capitalize it.
+            result.Append(char.ToLowerInvariant(c));
+          } else {
+            // Capital letters after the first are left as-is.
+            result.Append(c);
+          }
+          capitaliseNext = false;
+        } else if ('0' <= c && c <= '9') {
+          result.Append(c);
+          capitaliseNext = true;
+        } else {
+          capitaliseNext = true;
+        }
+      }
+      return result.ToString();
+    }
+
+    internal static string StripProto(string text) {
+      if (!StripSuffix(ref text, ".protodevel")) {
+        StripSuffix(ref text, ".proto");
+      }
+      return text;
+    }
+
+    /// <summary>
+    /// Attempts to strip a suffix from a string, returning whether
+    /// or not the suffix was actually present.
+    /// </summary>
+    internal static bool StripSuffix(ref string text, string suffix) {
+      if (text.EndsWith(suffix)) {
+        text = text.Substring(0, text.Length - suffix.Length);
+        return true;
+      }
+      return false;
+    }
+  }
+}
diff --git a/src/ProtocolBuffers/ProtocolBuffers.csproj b/src/ProtocolBuffers/ProtocolBuffers.csproj
index 3f76aa7..6a746cc 100644
--- a/src/ProtocolBuffers/ProtocolBuffers.csproj
+++ b/src/ProtocolBuffers/ProtocolBuffers.csproj
@@ -97,6 +97,7 @@
     <Compile Include="IService.cs" />
     <Compile Include="MessageStreamIterator.cs" />
     <Compile Include="MessageStreamWriter.cs" />
+    <Compile Include="NameHelpers.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RpcUtil.cs" />
     <Compile Include="TextFormat.cs" />