From 78ea98f56f7a0a028e378aee6394549707e199bc Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 1 Jul 2015 14:47:03 +0100 Subject: Implement reflection properly for fields. - FieldAccessorTable is now non-generic - We don't have a static field per message type in the umbrella class. (Message descriptors are accessed via the file descriptor.) - Removed the "descriptor assigner" complication from the descriptor fixup; without extensions, we don't need it - MapField implements IDictionary (more tests would be good...) - RepeatedField implements IList (more tests would be good) - Use expression trees to build accessors. (Will need to test this on various platforms... probably need a fallback strategy just using reflection directly.) - Added FieldDescriptor.IsMap - Added tests for reflection with generated messages Changes to generated code coming in next commit. --- .../protobuf/compiler/csharp/csharp_message.cc | 37 +++++++++++++--------- .../compiler/csharp/csharp_umbrella_class.cc | 22 +++++-------- 2 files changed, 30 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index 9e2fe9b6..c7a1e290 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -116,8 +116,7 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { // The descriptor for this type. printer->Print( - "internal static pbd::MessageDescriptor internal__$identifier$__Descriptor;\n" - "internal static pb::FieldAccess.FieldAccessorTable<$full_class_name$> internal__$identifier$__FieldAccessorTable;\n", + "internal static pb::FieldAccess.FieldAccessorTable internal__$identifier$__FieldAccessorTable;\n", "identifier", GetUniqueFileScopeIdentifier(descriptor_), "full_class_name", full_class_name()); @@ -130,24 +129,23 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { void MessageGenerator::GenerateStaticVariableInitializers(io::Printer* printer) { map vars; vars["identifier"] = GetUniqueFileScopeIdentifier(descriptor_); - vars["index"] = SimpleItoa(descriptor_->index()); vars["full_class_name"] = full_class_name(); - if (descriptor_->containing_type() != NULL) { - vars["parent"] = GetUniqueFileScopeIdentifier( - descriptor_->containing_type()); - } - printer->Print(vars, "internal__$identifier$__Descriptor = "); - if (!descriptor_->containing_type()) { - printer->Print(vars, "Descriptor.MessageTypes[$index$];\n"); - } else { - printer->Print(vars, "internal__$parent$__Descriptor.NestedTypes[$index$];\n"); + // Work out how to get to the message descriptor (which may be multiply nested) from the file + // descriptor. + string descriptor_chain; + const Descriptor* current_descriptor = descriptor_; + while (current_descriptor->containing_type()) { + descriptor_chain = ".NestedTypes[" + SimpleItoa(current_descriptor->index()) + "]" + descriptor_chain; + current_descriptor = current_descriptor->containing_type(); } + descriptor_chain = "descriptor.MessageTypes[" + SimpleItoa(current_descriptor->index()) + "]" + descriptor_chain; + vars["descriptor_chain"] = descriptor_chain; printer->Print( vars, "internal__$identifier$__FieldAccessorTable = \n" - " new pb::FieldAccess.FieldAccessorTable<$full_class_name$>(internal__$identifier$__Descriptor,\n"); + " new pb::FieldAccess.FieldAccessorTable(typeof($full_class_name$), $descriptor_chain$,\n"); printer->Print(" new string[] { "); for (int i = 0; i < descriptor_->field_count(); i++) { printer->Print("\"$property_name$\", ", @@ -201,13 +199,22 @@ void MessageGenerator::Generate(io::Printer* printer) { "private static readonly uint[] _fieldTags = new uint[] { $tags$ };\n", "tags", JoinStrings(tags, ", ")); + // Access the message descriptor via the relevant file descriptor or containing message descriptor. + if (!descriptor_->containing_type()) { + vars["descriptor_accessor"] = GetFullUmbrellaClassName(descriptor_->file()) + + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]"; + } else { + vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type()) + + ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]"; + } + printer->Print( vars, "public static pbd::MessageDescriptor Descriptor {\n" - " get { return $umbrella_class_name$.internal__$identifier$__Descriptor; }\n" + " get { return $descriptor_accessor$; }\n" "}\n" "\n" - "public pb::FieldAccess.FieldAccessorTable<$class_name$> Fields {\n" + "public pb::FieldAccess.FieldAccessorTable Fields {\n" " get { return $umbrella_class_name$.internal__$identifier$__FieldAccessorTable; }\n" "}\n" "\n" diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc index 03a3b8df..8fbd3e9a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc @@ -176,22 +176,11 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { printer->Print("\"$base64$\"));\n", "base64", base64); printer->Outdent(); printer->Outdent(); - printer->Print( - "pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {\n"); - printer->Indent(); - printer->Print("descriptor = root;\n"); - for (int i = 0; i < file_->message_type_count(); i++) { - MessageGenerator messageGenerator(file_->message_type(i)); - messageGenerator.GenerateStaticVariableInitializers(printer); - } - - printer->Outdent(); - printer->Print("};\n"); // ----------------------------------------------------------------- - // Invoke internalBuildGeneratedFileFrom() to build the file. + // Invoke InternalBuildGeneratedFileFrom() to build the file. printer->Print( - "pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n"); + "descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n"); printer->Print(" new pbd::FileDescriptor[] {\n"); for (int i = 0; i < file_->dependency_count(); i++) { printer->Print( @@ -199,7 +188,12 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) { "full_umbrella_class_name", GetFullUmbrellaClassName(file_->dependency(i))); } - printer->Print(" }, assigner);\n"); + printer->Print(" });\n"); + // Then invoke any other static variable initializers, e.g. field accessors. + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateStaticVariableInitializers(printer); + } printer->Outdent(); printer->Print("}\n"); printer->Print("#endregion\n\n"); -- cgit v1.2.3