/// <summary> /// Builds a FileDescriptor from its protocol buffer representation. /// </summary> /// <param name="descriptorData">The original serialized descriptor data. /// We have only limited proto2 support, so serializing FileDescriptorProto /// would not necessarily give us this.</param> /// <param name="proto">The protocol message form of the FileDescriptor.</param> /// <param name="dependencies">FileDescriptors corresponding to all of the /// 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">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> private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo) { // Building descriptors involves two steps: translating and linking. // In the translation step (implemented by FileDescriptor's // constructor), we build an object tree mirroring the // FileDescriptorProto's tree and put all of the descriptors into the // DescriptorPool's lookup tables. In the linking step, we look up all // type references in the DescriptorPool, so that, for example, a // FieldDescriptor for an embedded message contains a pointer directly // to the Descriptor for that message's type. We also detect undefined // types in the linking step. if (dependencies == null) { dependencies = new FileDescriptor[0]; } DescriptorPool pool = new DescriptorPool(dependencies); FileDescriptor result = new FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo); // Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we // need. if (dependencies.Length != proto.Dependency.Count) { throw new DescriptorValidationException( result, "Dependencies passed to FileDescriptor.BuildFrom() don't match " + "those listed in the FileDescriptorProto."); } result.CrossLink(); return(result); }
/// <summary> /// Converts the given descriptor binary data into FileDescriptor objects. /// Note: reflection using the returned FileDescriptors is not currently supported. /// </summary> /// <param name="descriptorData">The binary file descriptor proto data. Must not be null, and any /// dependencies must come before the descriptor which depends on them. (If A depends on B, and B /// depends on C, then the descriptors must be presented in the order C, B, A.) This is compatible /// with the order in which protoc provides descriptors to plugins.</param> /// <returns>The file descriptors corresponding to <paramref name="descriptorData"/>.</returns> public static IReadOnlyList <FileDescriptor> BuildFromByteStrings(IEnumerable <ByteString> descriptorData) { ProtoPreconditions.CheckNotNull(descriptorData, nameof(descriptorData)); // TODO: See if we can build a single DescriptorPool instead of building lots of them. // This will all behave correctly, but it's less efficient than we'd like. var descriptors = new List <FileDescriptor>(); var descriptorsByName = new Dictionary <string, FileDescriptor>(); foreach (var data in descriptorData) { var proto = FileDescriptorProto.Parser.ParseFrom(data); var dependencies = new List <FileDescriptor>(); foreach (var dependencyName in proto.Dependency) { FileDescriptor dependency; if (!descriptorsByName.TryGetValue(dependencyName, out dependency)) { throw new ArgumentException($"Dependency missing: {dependencyName}"); } dependencies.Add(dependency); } var pool = new DescriptorPool(dependencies); FileDescriptor descriptor = new FileDescriptor( data, proto, dependencies, pool, allowUnknownDependencies: false, generatedCodeInfo: null); descriptor.CrossLink(); descriptors.Add(descriptor); if (descriptorsByName.ContainsKey(descriptor.Name)) { throw new ArgumentException($"Duplicate descriptor name: {descriptor.Name}"); } descriptorsByName.Add(descriptor.Name, descriptor); } return(new ReadOnlyCollection <FileDescriptor>(descriptors)); }