瀏覽代碼

Merge pull request #990 from jskeet/naming

Tidying up reflection further
Jon Skeet 9 年之前
父節點
當前提交
41824d93e5
共有 29 個文件被更改,包括 208 次插入245 次删除
  1. 1 1
      csharp/src/AddressBook/Addressbook.cs
  2. 1 1
      csharp/src/Google.Protobuf.Conformance/Conformance.cs
  3. 6 12
      csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
  4. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
  5. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
  6. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
  7. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
  8. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
  9. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
  10. 1 2
      csharp/src/Google.Protobuf/JsonFormatter.cs
  11. 1 2
      csharp/src/Google.Protobuf/JsonParser.cs
  12. 1 1
      csharp/src/Google.Protobuf/Reflection/Descriptor.cs
  13. 5 5
      csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
  14. 21 12
      csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
  15. 42 86
      csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
  16. 36 5
      csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs
  17. 71 91
      csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
  18. 5 10
      csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
  19. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
  20. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
  21. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
  22. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
  23. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
  24. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
  25. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
  26. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
  27. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
  28. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
  29. 1 1
      src/google/protobuf/compiler/csharp/csharp_reflection_class.cc

+ 1 - 1
csharp/src/AddressBook/Addressbook.cs

@@ -32,7 +32,7 @@ namespace Google.Protobuf.Examples.AddressBook {
             "GAEgAygLMhAudHV0b3JpYWwuUGVyc29uQlAKFGNvbS5leGFtcGxlLnR1dG9y",
             "aWFsQhFBZGRyZXNzQm9va1Byb3Rvc6oCJEdvb2dsZS5Qcm90b2J1Zi5FeGFt",
             "cGxlcy5BZGRyZXNzQm9va2IGcHJvdG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person), global::Google.Protobuf.Examples.AddressBook.Person.Parser, new[]{ "Name", "Id", "Email", "Phones" }, null, new[]{ typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType) }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber), global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber.Parser, new[]{ "Number", "Type" }, null, null, null)}),

+ 1 - 1
csharp/src/Google.Protobuf.Conformance/Conformance.cs

@@ -134,7 +134,7 @@ namespace Conformance {
             "QlVGEAESCAoESlNPThACKkAKC0ZvcmVpZ25FbnVtEg8KC0ZPUkVJR05fRk9P",
             "EAASDwoLRk9SRUlHTl9CQVIQARIPCgtGT1JFSUdOX0JBWhACQiEKH2NvbS5n",
             "b29nbGUucHJvdG9idWYuY29uZm9ybWFuY2ViBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.ForeignEnum), }, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat" }, new[]{ "Payload" }, null, null),

+ 6 - 12
csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs

@@ -63,7 +63,7 @@ namespace Google.Protobuf.Reflection
             Assert.AreEqual(UnittestImportProto3Reflection.Descriptor, file.Dependencies[0]);
 
             MessageDescriptor messageType = TestAllTypes.Descriptor;
-            Assert.AreSame(typeof(TestAllTypes), messageType.GeneratedType);
+            Assert.AreSame(typeof(TestAllTypes), messageType.ClrType);
             Assert.AreSame(TestAllTypes.Parser, messageType.Parser);
             Assert.AreEqual(messageType, file.MessageTypes[0]);
             Assert.AreEqual(messageType, file.FindTypeByName<MessageDescriptor>("TestAllTypes"));
@@ -227,18 +227,12 @@ namespace Google.Protobuf.Reflection
         }
 
         [Test]
-        public void ConstructionWithoutGeneratedCodeInfo()
+        public void MapEntryMessageDescriptor()
         {
-            var data = UnittestIssuesReflection.Descriptor.Proto.ToByteArray();
-            var newDescriptor = Google.Protobuf.Reflection.FileDescriptor.InternalBuildGeneratedFileFrom(data, new Reflection.FileDescriptor[] { }, null);
-
-            // We should still be able to get at a field...
-            var messageDescriptor = newDescriptor.FindTypeByName<MessageDescriptor>("ItemField");
-            var fieldDescriptor = messageDescriptor.FindFieldByName("item");
-            // But there shouldn't be an accessor (or a generated type for the message, or parser)
-            Assert.IsNull(fieldDescriptor.Accessor);
-            Assert.IsNull(messageDescriptor.GeneratedType);
-            Assert.IsNull(messageDescriptor.Parser);
+            var descriptor = MapWellKnownTypes.Descriptor.NestedTypes[0];
+            Assert.IsNull(descriptor.Parser);
+            Assert.IsNull(descriptor.ClrType);
+            Assert.IsNull(descriptor.Fields[1].Accessor);
         }
 
         // From TestFieldOrdering:

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs

@@ -147,7 +147,7 @@ namespace Google.Protobuf.TestProtos {
             "dmFsdWUYAiABKAU6AjgBKj8KB01hcEVudW0SEAoMTUFQX0VOVU1fRk9PEAAS",
             "EAoMTUFQX0VOVU1fQkFSEAESEAoMTUFQX0VOVU1fQkFaEAJCIPgBAaoCGkdv",
             "b2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zYgZwcm90bzM="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor, },
           new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.MapEnum), }, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestMap), global::Google.Protobuf.TestProtos.TestMap.Parser, new[]{ "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapInt32Bytes", "MapInt32Enum", "MapInt32ForeignMessage" }, null, null, new pbr::GeneratedCodeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs

@@ -31,7 +31,7 @@ namespace Google.Protobuf.TestProtos {
             "UhAIEg4KCklNUE9SVF9CQVoQCUI8Chhjb20uZ29vZ2xlLnByb3RvYnVmLnRl",
             "c3RIAfgBAaoCGkdvb2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zUABiBnByb3Rv",
             "Mw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportPublicProto3Reflection.Descriptor, },
           new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ImportEnum), }, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.ImportMessage), global::Google.Protobuf.TestProtos.ImportMessage.Parser, new[]{ "D" }, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs

@@ -27,7 +27,7 @@ namespace Google.Protobuf.TestProtos {
             "bzMucHJvdG8SGHByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydCIgChNQdWJsaWNJ",
             "bXBvcnRNZXNzYWdlEgkKAWUYASABKAVCNwoYY29tLmdvb2dsZS5wcm90b2J1",
             "Zi50ZXN0qgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.PublicImportMessage), global::Google.Protobuf.TestProtos.PublicImportMessage.Parser, new[]{ "E" }, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs

@@ -46,7 +46,7 @@ namespace UnitTest.Issues.TestProtos {
             "aXZlQmVsb3cQ+///////////ARIVCghNaW51c09uZRD///////////8BKi4K",
             "DkRlcHJlY2F0ZWRFbnVtEhMKD0RFUFJFQ0FURURfWkVSTxAAEgcKA29uZRAB",
             "Qh9IAaoCGlVuaXRUZXN0Lklzc3Vlcy5UZXN0UHJvdG9zYgZwcm90bzM="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307), global::UnitTest.Issues.TestProtos.Issue307.Parser, null, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce), global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Parser, null, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice), global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice.Parser, null, null, null, null)})}),

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs

@@ -150,7 +150,7 @@ namespace Google.Protobuf.TestProtos {
             "HS5wcm90b2J1Zl91bml0dGVzdC5CYXJSZXF1ZXN0Gh4ucHJvdG9idWZfdW5p",
             "dHRlc3QuQmFyUmVzcG9uc2VCOkINVW5pdHRlc3RQcm90b0gBgAEBiAEBkAEB",
             "+AEBqgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportProto3Reflection.Descriptor, },
           new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ForeignEnum), typeof(global::Google.Protobuf.TestProtos.TestEnumWithDupValue), typeof(global::Google.Protobuf.TestProtos.TestSparseEnum), }, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes), global::Google.Protobuf.TestProtos.TestAllTypes.Parser, new[]{ "SingleInt32", "SingleInt64", "SingleUint32", "SingleUint64", "SingleSint32", "SingleSint64", "SingleFixed32", "SingleFixed64", "SingleSfixed32", "SingleSfixed64", "SingleFloat", "SingleDouble", "SingleBool", "SingleString", "SingleBytes", "SingleNestedMessage", "SingleForeignMessage", "SingleImportMessage", "SingleNestedEnum", "SingleForeignEnum", "SingleImportEnum", "SinglePublicImportMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedImportMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedImportEnum", "RepeatedPublicImportMessage", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes" }, new[]{ "OneofField" }, new[]{ typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage), global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage.Parser, new[]{ "Bb" }, null, null, null)}),

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs

@@ -159,7 +159,7 @@ namespace Google.Protobuf.TestProtos {
             "AiABKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZToCOAFCOQoYY29t",
             "Lmdvb2dsZS5wcm90b2J1Zi50ZXN0UAGqAhpHb29nbGUuUHJvdG9idWYuVGVz",
             "dFByb3Rvc2IGcHJvdG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestWellKnownTypes), global::Google.Protobuf.TestProtos.TestWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, null),

+ 1 - 2
csharp/src/Google.Protobuf/JsonFormatter.cs

@@ -388,8 +388,7 @@ namespace Google.Protobuf
             // If it's the message form, we can extract the value first, which *will* be the (possibly boxed) native value,
             // and then proceed, writing it as if we were definitely in a field. (We never need to wrap it in an extra string...
             // WriteValue will do the right thing.)
-            // TODO: Detect this differently when we have dynamic messages.
-            if (descriptor.File == Int32Value.Descriptor.File)
+            if (descriptor.IsWrapperType)
             {
                 if (value is IMessage)
                 {

+ 1 - 2
csharp/src/Google.Protobuf/JsonParser.cs

@@ -291,8 +291,7 @@ namespace Google.Protobuf
             {
                 // Parse wrapper types as their constituent types.
                 // TODO: What does this mean for null?
-                // TODO: Detect this differently when we have dynamic messages, and put it in one place...
-                if (field.MessageType.IsWellKnownType && field.MessageType.File == Int32Value.Descriptor.File)
+                if (field.MessageType.IsWrapperType)
                 {
                     field = field.MessageType.Fields[WrappersReflection.WrapperValueFieldNumber];
                     fieldType = field.FieldType;

+ 1 - 1
csharp/src/Google.Protobuf/Reflection/Descriptor.cs

@@ -135,7 +135,7 @@ namespace Google.Protobuf.Reflection {
             "X2NvbW1lbnRzGAYgAygJQlgKE2NvbS5nb29nbGUucHJvdG9idWZCEERlc2Ny",
             "aXB0b3JQcm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdvb2dsZS5Qcm90",
             "b2J1Zi5SZWZsZWN0aW9u"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorSet), global::Google.Protobuf.Reflection.FileDescriptorSet.Parser, new[]{ "File" }, null, null, null),

+ 5 - 5
csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs

@@ -43,13 +43,13 @@ namespace Google.Protobuf.Reflection
         private readonly EnumDescriptorProto proto;
         private readonly MessageDescriptor containingType;
         private readonly IList<EnumValueDescriptor> values;
-        private readonly Type generatedType;
+        private readonly Type clrType;
 
-        internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type generatedType)
+        internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type clrType)
             : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
             this.proto = proto;
-            this.generatedType = generatedType;
+            this.clrType = clrType;
             containingType = parent;
 
             if (proto.Value.Count == 0)
@@ -73,9 +73,9 @@ namespace Google.Protobuf.Reflection
         public override string Name { get { return proto.Name; } }
 
         /// <summary>
-        /// The generated type for this enum, or <c>null</c> if the descriptor does not represent a generated type.
+        /// The CLR type for this enum. For generated code, this will be a CLR enum type.
         /// </summary>
-        public Type GeneratedType { get { return generatedType; } }
+        public Type ClrType { get { return clrType; } }
 
         /// <value>
         /// If this is a nested type, get the outer descriptor, otherwise null.

+ 21 - 12
csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs

@@ -62,8 +62,7 @@ namespace Google.Protobuf.Reflection
 
             if (FieldNumber <= 0)
             {
-                throw new DescriptorValidationException(this,
-                                                        "Field numbers must be positive integers.");
+                throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
             }
             containingType = parent;
             // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
@@ -72,7 +71,7 @@ namespace Google.Protobuf.Reflection
                 if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
                 {
                     throw new DescriptorValidationException(this,
-                        "FieldDescriptorProto.oneof_index is out of range for type " + parent.Name);
+                        $"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}");
                 }
                 containingOneof = parent.Oneofs[proto.OneofIndex];
             }
@@ -94,13 +93,22 @@ namespace Google.Protobuf.Reflection
         internal FieldDescriptorProto Proto { get { return proto; } }
 
         /// <summary>
-        /// Returns the accessor for this field, or <c>null</c> if this descriptor does
-        /// not support reflective access.
+        /// Returns the accessor for this field.
         /// </summary>
         /// <remarks>
+        /// <para>
         /// While a <see cref="FieldDescriptor"/> describes the field, it does not provide
         /// any way of obtaining or changing the value of the field within a specific message;
         /// that is the responsibility of the accessor.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, and the value of the map field itself is represented by a dictionary in the
+        /// reflection API. There are never instances of those "hidden" messages, so no accessor is provided
+        /// and this property will return null.
+        /// </para>
         /// </remarks>
         public IFieldAccessor Accessor { get { return accessor; } }
         
@@ -281,7 +289,7 @@ namespace Google.Protobuf.Reflection
                     }
                     else
                     {
-                        throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not a type.");
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a type.");
                     }
                 }
 
@@ -289,8 +297,7 @@ namespace Google.Protobuf.Reflection
                 {
                     if (!(typeDescriptor is MessageDescriptor))
                     {
-                        throw new DescriptorValidationException(this,
-                                                                "\"" + Proto.TypeName + "\" is not a message type.");
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a message type.");
                     }
                     messageType = (MessageDescriptor) typeDescriptor;
 
@@ -303,7 +310,7 @@ namespace Google.Protobuf.Reflection
                 {
                     if (!(typeDescriptor is EnumDescriptor))
                     {
-                        throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not an enum type.");
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not an enum type.");
                     }
                     enumType = (EnumDescriptor) typeDescriptor;
                 }
@@ -333,14 +340,16 @@ namespace Google.Protobuf.Reflection
 
         private IFieldAccessor CreateAccessor(string propertyName)
         {
-            if (containingType.GeneratedType == null || propertyName == null)
+            // If we're given no property name, that's because we really don't want an accessor.
+            // (At the moment, that means it's a map entry message...)
+            if (propertyName == null)
             {
                 return null;
             }
-            var property = containingType.GeneratedType.GetProperty(propertyName);
+            var property = containingType.ClrType.GetProperty(propertyName);
             if (property == null)
             {
-                throw new DescriptorValidationException(this, "Property " + propertyName + " not found in " + containingType.GeneratedType);
+                throw new DescriptorValidationException(this, $"Property {propertyName} not found in {containingType.ClrType}");
             }
             return IsMap ? new MapFieldAccessor(property, this)
                 : IsRepeated ? new RepeatedFieldAccessor(property, this)

+ 42 - 86
csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs

@@ -43,35 +43,26 @@ namespace Google.Protobuf.Reflection
     /// </summary>
     public sealed class FileDescriptor : IDescriptor
     {
-        private readonly ByteString descriptorData;
-        private readonly FileDescriptorProto proto;
-        private readonly IList<MessageDescriptor> messageTypes;
-        private readonly IList<EnumDescriptor> enumTypes;
-        private readonly IList<ServiceDescriptor> services;
-        private readonly IList<FileDescriptor> dependencies;
-        private readonly IList<FileDescriptor> publicDependencies;
-        private readonly DescriptorPool pool;
-        
         private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedCodeInfo generatedCodeInfo)
         {
-            this.descriptorData = descriptorData;
-            this.pool = pool;
-            this.proto = proto;
-            this.dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
+            SerializedData = descriptorData;
+            DescriptorPool = pool;
+            Proto = proto;
+            Dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
 
-            publicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
+            PublicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
 
             pool.AddPackage(Package, this);
 
-            messageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
+            MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
                                                                  (message, index) =>
-                                                                 new MessageDescriptor(message, this, null, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedTypes[index]));
+                                                                 new MessageDescriptor(message, this, null, index, generatedCodeInfo.NestedTypes[index]));
 
-            enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
                                                               (enumType, index) =>
-                                                              new EnumDescriptor(enumType, this, null, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedEnums[index]));
+                                                              new EnumDescriptor(enumType, this, null, index, generatedCodeInfo.NestedEnums[index]));
 
-            services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
+            Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
                                                              (service, index) =>
                                                              new ServiceDescriptor(service, this, index));
         }
@@ -132,99 +123,63 @@ namespace Google.Protobuf.Reflection
         /// <value>
         /// The descriptor in its protocol message representation.
         /// </value>
-        internal FileDescriptorProto Proto
-        {
-            get { return proto; }
-        }
+        internal FileDescriptorProto Proto { get; }
 
         /// <value>
         /// The file name.
         /// </value>
-        public string Name
-        {
-            get { return proto.Name; }
-        }
+        public string Name => Proto.Name;
 
         /// <summary>
         /// The package as declared in the .proto file. This may or may not
         /// be equivalent to the .NET namespace of the generated classes.
         /// </summary>
-        public string Package
-        {
-            get { return proto.Package; }
-        }
+        public string Package => Proto.Package;
 
         /// <value>
         /// Unmodifiable list of top-level message types declared in this file.
         /// </value>
-        public IList<MessageDescriptor> MessageTypes
-        {
-            get { return messageTypes; }
-        }
+        public IList<MessageDescriptor> MessageTypes { get; }
 
         /// <value>
         /// Unmodifiable list of top-level enum types declared in this file.
         /// </value>
-        public IList<EnumDescriptor> EnumTypes
-        {
-            get { return enumTypes; }
-        }
+        public IList<EnumDescriptor> EnumTypes { get; }
 
         /// <value>
         /// Unmodifiable list of top-level services declared in this file.
         /// </value>
-        public IList<ServiceDescriptor> Services
-        {
-            get { return services; }
-        }
+        public IList<ServiceDescriptor> Services { get; }
 
         /// <value>
         /// Unmodifiable list of this file's dependencies (imports).
         /// </value>
-        public IList<FileDescriptor> Dependencies
-        {
-            get { return dependencies; }
-        }
+        public IList<FileDescriptor> Dependencies { get; }
 
         /// <value>
         /// Unmodifiable list of this file's public dependencies (public imports).
         /// </value>
-        public IList<FileDescriptor> PublicDependencies
-        {
-            get { return publicDependencies; }
-        }
+        public IList<FileDescriptor> PublicDependencies { get; }
 
         /// <value>
         /// The original serialized binary form of this descriptor.
         /// </value>
-        public ByteString SerializedData
-        {
-            get { return descriptorData; }
-        }
+        public ByteString SerializedData { get; }
 
         /// <value>
         /// Implementation of IDescriptor.FullName - just returns the same as Name.
         /// </value>
-        string IDescriptor.FullName
-        {
-            get { return Name; }
-        }
+        string IDescriptor.FullName => Name;
 
         /// <value>
         /// Implementation of IDescriptor.File - just returns this descriptor.
         /// </value>
-        FileDescriptor IDescriptor.File
-        {
-            get { return this; }
-        }
+        FileDescriptor IDescriptor.File => this;
 
         /// <value>
         /// Pool containing symbol descriptors.
         /// </value>
-        internal DescriptorPool DescriptorPool
-        {
-            get { return pool; }
-        }
+        internal DescriptorPool DescriptorPool { get; }
 
         /// <summary>
         /// Finds a type (message, enum, service or extension) in the file by name. Does not find nested types.
@@ -245,7 +200,7 @@ namespace Google.Protobuf.Reflection
             {
                 name = Package + "." + name;
             }
-            T result = pool.FindSymbol<T>(name);
+            T result = DescriptorPool.FindSymbol<T>(name);
             if (result != null && result.File == this)
             {
                 return result;
@@ -264,7 +219,7 @@ namespace Google.Protobuf.Reflection
         /// file's dependencies, in the exact order listed in the .proto file. May be null,
         /// in which case it is treated as an empty array.</param>
         /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
-        /// <param name="generatedCodeInfo">Reflection information, if any. May be null, specifically for non-generated code.</param>
+        /// <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param>
         /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
         /// a valid descriptor. This can occur for a number of reasons, such as a field
         /// having an undefined type or because two messages were defined with the same name.</exception>
@@ -291,15 +246,17 @@ namespace Google.Protobuf.Reflection
             // need.
             if (dependencies.Length != proto.Dependency.Count)
             {
-                throw new DescriptorValidationException(result,
-                                                        "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
-                                                        "those listed in the FileDescriptorProto.");
+                throw new DescriptorValidationException(
+                    result,
+                    "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
+                    "those listed in the FileDescriptorProto.");
             }
             for (int i = 0; i < proto.Dependency.Count; i++)
             {
                 if (dependencies[i].Name != proto.Dependency[i])
                 {
-                    throw new DescriptorValidationException(result,
+                    throw new DescriptorValidationException(
+                        result,
                         "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
                         "those listed in the FileDescriptorProto. Expected: " +
                         proto.Dependency[i] + " but was: " + dependencies[i].Name);
@@ -312,28 +269,29 @@ namespace Google.Protobuf.Reflection
 
         private void CrossLink()
         {
-            foreach (MessageDescriptor message in messageTypes)
+            foreach (MessageDescriptor message in MessageTypes)
             {
                 message.CrossLink();
             }
 
-            foreach (ServiceDescriptor service in services)
+            foreach (ServiceDescriptor service in Services)
             {
                 service.CrossLink();
             }
         }
 
         /// <summary>
-        /// Creates an instance for generated code.
+        /// Creates a descriptor for generated code.
         /// </summary>
         /// <remarks>
-        /// The <paramref name="generatedCodeInfo"/> parameter should be null for descriptors which don't correspond to
-        /// generated types. Otherwise, it should be a <see cref="GeneratedCodeInfo"/> with nested types and nested
-        /// enums corresponding to the types and enums contained within the file descriptor.
+        /// This method is only designed to be used by the results of generating code with protoc,
+        /// which creates the appropriate dependencies etc. It has to be public because the generated
+        /// code is "external", but should not be called directly by end users.
         /// </remarks>
-        public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
-                                                                    FileDescriptor[] dependencies,
-                                                                    GeneratedCodeInfo generatedCodeInfo)
+        public static FileDescriptor FromGeneratedCode(
+            byte[] descriptorData,
+            FileDescriptor[] dependencies,
+            GeneratedCodeInfo generatedCodeInfo)
         {
             FileDescriptorProto proto;
             try
@@ -345,8 +303,6 @@ namespace Google.Protobuf.Reflection
                 throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e);
             }
 
-
-
             try
             {
                 // When building descriptors for generated code, we allow unknown
@@ -355,7 +311,7 @@ namespace Google.Protobuf.Reflection
             }
             catch (DescriptorValidationException e)
             {
-                throw new ArgumentException("Invalid embedded descriptor for \"" + proto.Name + "\".", e);
+                throw new ArgumentException($"Invalid embedded descriptor for \"{proto.Name}\".", e);
             }
         }
 
@@ -367,7 +323,7 @@ namespace Google.Protobuf.Reflection
         /// </returns>
         public override string ToString()
         {
-            return "FileDescriptor for " + proto.Name;
+            return $"FileDescriptor for {Name}";
         }
 
         /// <summary>

+ 36 - 5
csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs

@@ -1,3 +1,34 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
 using System;
 
 namespace Google.Protobuf.Reflection
@@ -20,31 +51,31 @@ namespace Google.Protobuf.Reflection
         /// <summary>
         /// Irrelevant for file descriptors; the parser for message descriptors.
         /// </summary>
-        public MessageParser Parser { get; private set; }
+        public MessageParser Parser { get; }
 
         /// <summary>
         /// Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
         /// for fields in the message for message descriptors.
         /// </summary>
-        public string[] PropertyNames { get; private set; }
+        public string[] PropertyNames { get; }
 
         /// <summary>
         /// Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
         /// for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
         /// there will be a "FooCase" property and a "ClearFoo" method.
         /// </summary>
-        public string[] OneofNames { get; private set; }
+        public string[] OneofNames { get; }
 
         /// <summary>
         /// The reflection information for types within this file/message descriptor. Elements may be null
         /// if there is no corresponding generated type, e.g. for map entry types.
         /// </summary>
-        public GeneratedCodeInfo[] NestedTypes { get; private set; }
+        public GeneratedCodeInfo[] NestedTypes { get; }
 
         /// <summary>
         /// The CLR types for enums within this file/message descriptor.
         /// </summary>
-        public Type[] NestedEnums { get; private set; }
+        public Type[] NestedEnums { get; }
 
         /// <summary>
         /// Creates a GeneratedCodeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.

+ 71 - 91
csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs

@@ -56,153 +56,145 @@ namespace Google.Protobuf.Reflection
             "google/protobuf/type.proto",
         };
 
-        private readonly DescriptorProto proto;
-        private readonly MessageDescriptor containingType;
-        private readonly IList<MessageDescriptor> nestedTypes;
-        private readonly IList<EnumDescriptor> enumTypes;
         private readonly IList<FieldDescriptor> fieldsInDeclarationOrder;
         private readonly IList<FieldDescriptor> fieldsInNumberOrder;
         private readonly IDictionary<string, FieldDescriptor> jsonFieldMap;
-        private readonly FieldCollection fields;
-        private readonly IList<OneofDescriptor> oneofs;
-        // CLR representation of the type described by this descriptor, if any.
-        private readonly Type generatedType;
-        private readonly MessageParser parser;
         
         internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedCodeInfo generatedCodeInfo)
             : base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
         {
-            this.proto = proto;
-            parser = generatedCodeInfo == null ? null : generatedCodeInfo.Parser;
-            generatedType = generatedCodeInfo == null ? null : generatedCodeInfo.ClrType;
-
-            containingType = parent;
-
-            oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
+            Proto = proto;
+            Parser = generatedCodeInfo?.Parser;
+            ClrType = generatedCodeInfo?.ClrType;
+            ContainingType = parent;
+
+            // Note use of generatedCodeInfo. rather than generatedCodeInfo?. here... we don't expect
+            // to see any nested oneofs, types or enums in "not actually generated" code... we do
+            // expect fields though (for map entry messages).
+            Oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.OneofDecl,
                 (oneof, index) =>
-                new OneofDescriptor(oneof, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.OneofNames[index]));
+                new OneofDescriptor(oneof, file, this, index, generatedCodeInfo.OneofNames[index]));
 
-            nestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+            NestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.NestedType,
                 (type, index) =>
-                new MessageDescriptor(type, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedTypes[index]));
+                new MessageDescriptor(type, file, this, index, generatedCodeInfo.NestedTypes[index]));
 
-            enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.EnumType,
                 (type, index) =>
-                new EnumDescriptor(type, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedEnums[index]));
+                new EnumDescriptor(type, file, this, index, generatedCodeInfo.NestedEnums[index]));
 
             fieldsInDeclarationOrder = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.Field,
                 (field, index) =>
-                new FieldDescriptor(field, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.PropertyNames[index]));
+                new FieldDescriptor(field, file, this, index, generatedCodeInfo?.PropertyNames[index]));
             fieldsInNumberOrder = new ReadOnlyCollection<FieldDescriptor>(fieldsInDeclarationOrder.OrderBy(field => field.FieldNumber).ToArray());
             // TODO: Use field => field.Proto.JsonName when we're confident it's appropriate. (And then use it in the formatter, too.)
             jsonFieldMap = new ReadOnlyDictionary<string, FieldDescriptor>(fieldsInNumberOrder.ToDictionary(field => JsonFormatter.ToCamelCase(field.Name)));
             file.DescriptorPool.AddSymbol(this);
-            fields = new FieldCollection(this);
-        }
-                
-        /// <summary>
-        /// Returns the total number of nested types and enums, recursively.
-        /// </summary>
-        private int CountTotalGeneratedTypes()
-        {
-            return nestedTypes.Sum(nested => nested.CountTotalGeneratedTypes()) + enumTypes.Count;
+            Fields = new FieldCollection(this);
         }
 
         /// <summary>
         /// The brief name of the descriptor's target.
         /// </summary>
-        public override string Name { get { return proto.Name; } }
+        public override string Name => Proto.Name;
 
-        internal DescriptorProto Proto { get { return proto; } }
+        internal DescriptorProto Proto { get; }
 
         /// <summary>
-        /// The generated type for this message, or <c>null</c> if the descriptor does not represent a generated type.
+        /// The CLR type used to represent message instances from this descriptor.
         /// </summary>
-        public Type GeneratedType { get { return generatedType; } }
+        /// <remarks>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the type returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
+        /// </remarks>
+        public Type ClrType { get; }
 
         /// <summary>
         /// A parser for this message type.
         /// </summary>
         /// <remarks>
+        /// <para>
         /// As <see cref="MessageDescriptor"/> is not generic, this cannot be statically
-        /// typed to the relevant type, but if <see cref="GeneratedType"/> returns a non-null value, the parser returned
+        /// typed to the relevant type, but it should produce objects of a type compatible with <see cref="ClrType"/>.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. No message parser object is created for
+        /// such messages, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the parser returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
         /// </remarks>
-        public MessageParser Parser { get { return parser; } }
+        public MessageParser Parser { get; }
 
         /// <summary>
         /// Returns whether this message is one of the "well known types" which may have runtime/protoc support.
         /// </summary>
-        internal bool IsWellKnownType
-        {
-            get
-            {
-                return File.Package == "google.protobuf" && WellKnownTypeNames.Contains(File.Name);
-            }
-        }
+        internal bool IsWellKnownType => File.Package == "google.protobuf" && WellKnownTypeNames.Contains(File.Name);
+
+        /// <summary>
+        /// Returns whether this message is one of the "wrapper types" used for fields which represent primitive values
+        /// with the addition of presence.
+        /// </summary>
+        internal bool IsWrapperType => File.Package == "google.protobuf" && File.Name == "google/protobuf/wrappers.proto";
 
         /// <value>
         /// If this is a nested type, get the outer descriptor, otherwise null.
         /// </value>
-        public MessageDescriptor ContainingType
-        {
-            get { return containingType; }
-        }
+        public MessageDescriptor ContainingType { get; }
 
         /// <value>
         /// A collection of fields, which can be retrieved by name or field number.
         /// </value>
-        public FieldCollection Fields
-        {
-            get { return fields; }
-        }
+        public FieldCollection Fields { get; }
 
         /// <value>
         /// An unmodifiable list of this message type's nested types.
         /// </value>
-        public IList<MessageDescriptor> NestedTypes
-        {
-            get { return nestedTypes; }
-        }
+        public IList<MessageDescriptor> NestedTypes { get; }
 
         /// <value>
         /// An unmodifiable list of this message type's enum types.
         /// </value>
-        public IList<EnumDescriptor> EnumTypes
-        {
-            get { return enumTypes; }
-        }
+        public IList<EnumDescriptor> EnumTypes { get; }
 
         /// <value>
         /// An unmodifiable list of the "oneof" field collections in this message type.
         /// </value>
-        public IList<OneofDescriptor> Oneofs
-        {
-            get { return oneofs; }
-        }
+        public IList<OneofDescriptor> Oneofs { get; }
 
         /// <summary>
         /// Finds a field by field name.
         /// </summary>
         /// <param name="name">The unqualified name of the field (e.g. "foo").</param>
         /// <returns>The field's descriptor, or null if not found.</returns>
-        public FieldDescriptor FindFieldByName(String name)
-        {
-            return File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
-        }
+        public FieldDescriptor FindFieldByName(String name) => File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
 
         /// <summary>
         /// Finds a field by field number.
         /// </summary>
         /// <param name="number">The field number within this message type.</param>
         /// <returns>The field's descriptor, or null if not found.</returns>
-        public FieldDescriptor FindFieldByNumber(int number)
-        {
-            return File.DescriptorPool.FindFieldByNumber(this, number);
-        }
+        public FieldDescriptor FindFieldByNumber(int number) => File.DescriptorPool.FindFieldByNumber(this, number);
 
         /// <summary>
         /// Finds a nested descriptor by name. The is valid for fields, nested
@@ -210,18 +202,15 @@ namespace Google.Protobuf.Reflection
         /// </summary>
         /// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
         /// <returns>The descriptor, or null if not found.</returns>
-        public T FindDescriptor<T>(string name)
-            where T : class, IDescriptor
-        {
-            return File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
-        }
+        public T FindDescriptor<T>(string name)  where T : class, IDescriptor =>
+            File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
 
         /// <summary>
         /// Looks up and cross-links all fields and nested types.
         /// </summary>
         internal void CrossLink()
         {
-            foreach (MessageDescriptor message in nestedTypes)
+            foreach (MessageDescriptor message in NestedTypes)
             {
                 message.CrossLink();
             }
@@ -231,7 +220,7 @@ namespace Google.Protobuf.Reflection
                 field.CrossLink();
             }
 
-            foreach (OneofDescriptor oneof in oneofs)
+            foreach (OneofDescriptor oneof in Oneofs)
             {
                 oneof.CrossLink();
             }
@@ -253,10 +242,7 @@ namespace Google.Protobuf.Reflection
             /// Returns the fields in the message as an immutable list, in the order in which they
             /// are declared in the source .proto file.
             /// </value>
-            public IList<FieldDescriptor> InDeclarationOrder()
-            {
-                return messageDescriptor.fieldsInDeclarationOrder;
-            }
+            public IList<FieldDescriptor> InDeclarationOrder() => messageDescriptor.fieldsInDeclarationOrder;
 
             /// <value>
             /// Returns the fields in the message as an immutable list, in ascending field number
@@ -264,10 +250,7 @@ namespace Google.Protobuf.Reflection
             /// index in the list to the field number; to retrieve a field by field number, it is better
             /// to use the <see cref="FieldCollection"/> indexer.
             /// </value>
-            public IList<FieldDescriptor> InFieldNumberOrder()
-            {
-                return messageDescriptor.fieldsInNumberOrder;
-            }
+            public IList<FieldDescriptor> InFieldNumberOrder() => messageDescriptor.fieldsInNumberOrder;
 
             // TODO: consider making this public in the future. (Being conservative for now...)
 
@@ -276,10 +259,7 @@ namespace Google.Protobuf.Reflection
             /// in the JSON representation to the field descriptors. For example, a field <c>foo_bar</c>
             /// in the message would result in an entry with a key <c>fooBar</c>.
             /// </value>
-            internal IDictionary<string, FieldDescriptor> ByJsonName()
-            {
-                return messageDescriptor.jsonFieldMap;
-            }
+            internal IDictionary<string, FieldDescriptor> ByJsonName() => messageDescriptor.jsonFieldMap;
 
             /// <summary>
             /// Retrieves the descriptor for the field with the given number.

+ 5 - 10
csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs

@@ -86,8 +86,7 @@ namespace Google.Protobuf.Reflection
         /// in a particular message.
         /// </summary>
         /// <value>
-        /// The accessor used for reflective access, or <c>null</c> if reflection is not
-        /// supported by this descriptor.
+        /// The accessor used for reflective access.
         /// </value>
         public OneofAccessor Accessor { get { return accessor; } }
 
@@ -106,19 +105,15 @@ namespace Google.Protobuf.Reflection
 
         private OneofAccessor CreateAccessor(string clrName)
         {
-            if (containingType.GeneratedType == null || clrName == null)
-            {
-                return null;
-            }
-            var caseProperty = containingType.GeneratedType.GetProperty(clrName + "Case");
+            var caseProperty = containingType.ClrType.GetProperty(clrName + "Case");
             if (caseProperty == null)
             {
-                throw new DescriptorValidationException(this, "Property " + clrName + "Case not found in " + containingType.GeneratedType);
+                throw new DescriptorValidationException(this, $"Property {clrName}Case not found in {containingType.ClrType}");
             }
-            var clearMethod = containingType.GeneratedType.GetMethod("Clear" + clrName);
+            var clearMethod = containingType.ClrType.GetMethod("Clear" + clrName);
             if (clearMethod == null)
             {
-                throw new DescriptorValidationException(this, "Method Clear" + clrName + " not found in " + containingType.GeneratedType);
+                throw new DescriptorValidationException(this, $"Method Clear{clrName} not found in {containingType.ClrType}");
             }
 
             return new OneofAccessor(caseProperty, clearMethod, this);

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Any.cs

@@ -27,7 +27,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQksKE2Nv",
             "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAGgAQGiAgNHUEKqAh5Hb29n",
             "bGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Any), global::Google.Protobuf.WellKnownTypes.Any.Parser, new[]{ "TypeUrl", "Value" }, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Api.cs

@@ -39,7 +39,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCSwoTY29t",
             "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAaABAaICA0dQQqoCHkdvb2ds",
             "ZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Api), global::Google.Protobuf.WellKnownTypes.Api.Parser, new[]{ "Name", "Methods", "Options", "Version", "SourceContext", "Mixins", "Syntax" }, null, null, null),

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs

@@ -28,7 +28,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "ASgFQlAKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAaAB",
             "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
             "dG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Duration), global::Google.Protobuf.WellKnownTypes.Duration.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs

@@ -27,7 +27,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "ZiIHCgVFbXB0eUJNChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
             "UAGgAQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNi",
             "BnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Empty), global::Google.Protobuf.WellKnownTypes.Empty.Parser, null, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs

@@ -27,7 +27,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJRChNjb20uZ29v",
             "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABoAEBogIDR1BCqgIeR29v",
             "Z2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FieldMask), global::Google.Protobuf.WellKnownTypes.FieldMask.Parser, new[]{ "Paths" }, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs

@@ -28,7 +28,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "CUJVChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q",
             "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
             "cHJvdG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.SourceContext), global::Google.Protobuf.WellKnownTypes.SourceContext.Parser, new[]{ "FileName" }, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs

@@ -37,7 +37,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "QUxVRRAAQk4KE2NvbS5nb29nbGUucHJvdG9idWZCC1N0cnVjdFByb3RvUAGg",
             "AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy",
             "b3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.NullValue), }, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Struct), global::Google.Protobuf.WellKnownTypes.Struct.Parser, new[]{ "Fields" }, null, null, new pbr::GeneratedCodeInfo[] { null, }),

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs

@@ -28,7 +28,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "AiABKAVCUQoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q",
             "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
             "cHJvdG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Timestamp), global::Google.Protobuf.WellKnownTypes.Timestamp.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs

@@ -57,7 +57,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "dGF4EhEKDVNZTlRBWF9QUk9UTzIQABIRCg1TWU5UQVhfUFJPVE8zEAFCTAoT",
             "Y29tLmdvb2dsZS5wcm90b2J1ZkIJVHlwZVByb3RvUAGgAQGiAgNHUEKqAh5H",
             "b29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },
           new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax" }, null, null, null),

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs

@@ -32,7 +32,7 @@ namespace Google.Protobuf.WellKnownTypes {
             "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJQ",
             "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQGiAgNH",
             "UEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
             new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.DoubleValue), global::Google.Protobuf.WellKnownTypes.DoubleValue.Parser, new[]{ "Value" }, null, null, null),

+ 1 - 1
src/google/protobuf/compiler/csharp/csharp_reflection_class.cc

@@ -166,7 +166,7 @@ void ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) {
   // -----------------------------------------------------------------
   // Invoke InternalBuildGeneratedFileFrom() to build the file.
   printer->Print(
-      "descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n");
+      "descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,\n");
   printer->Print("    new pbr::FileDescriptor[] { ");
   for (int i = 0; i < file_->dependency_count(); i++) {
     // descriptor.proto is special: we don't allow access to the generated code, but there's