diff options
author | Jon Skeet <skeet@pobox.com> | 2008-08-14 20:35:25 +0100 |
---|---|---|
committer | Jon Skeet <skeet@pobox.com> | 2008-08-14 20:35:25 +0100 |
commit | cabd06d12fd7bd53c1896e8f77617cc00de70c4c (patch) | |
tree | ffae881275c3f2dd6d4021b355a1a477fa1470b7 /csharp/ProtocolBuffers | |
parent | 794409b379305d18dd0bb4d9ee1cabfd9b6da2d5 (diff) | |
download | protobuf-cabd06d12fd7bd53c1896e8f77617cc00de70c4c.tar.gz protobuf-cabd06d12fd7bd53c1896e8f77617cc00de70c4c.tar.bz2 protobuf-cabd06d12fd7bd53c1896e8f77617cc00de70c4c.zip |
More tests, and implementation of UninitializedMessageException description.
Diffstat (limited to 'csharp/ProtocolBuffers')
-rw-r--r-- | csharp/ProtocolBuffers/AbstractBuilder.cs | 4 | ||||
-rw-r--r-- | csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs | 75 | ||||
-rw-r--r-- | csharp/ProtocolBuffers/DynamicMessage.cs | 13 | ||||
-rw-r--r-- | csharp/ProtocolBuffers/GeneratedBuilder.cs | 6 | ||||
-rw-r--r-- | csharp/ProtocolBuffers/IBuilder.cs | 4 | ||||
-rw-r--r-- | csharp/ProtocolBuffers/UninitializedMessageException.cs | 98 |
6 files changed, 128 insertions, 72 deletions
diff --git a/csharp/ProtocolBuffers/AbstractBuilder.cs b/csharp/ProtocolBuffers/AbstractBuilder.cs index d65c0911..94077d4f 100644 --- a/csharp/ProtocolBuffers/AbstractBuilder.cs +++ b/csharp/ProtocolBuffers/AbstractBuilder.cs @@ -12,7 +12,7 @@ namespace Google.ProtocolBuffers { /// </summary> public abstract class AbstractBuilder : IBuilder { #region Unimplemented members of IBuilder - public abstract bool Initialized { get; } + public abstract bool IsInitialized { get; } public abstract IDictionary<FieldDescriptor, object> AllFields { get; } public abstract object this[FieldDescriptor field] { get; set; } public abstract MessageDescriptor DescriptorForType { get; } @@ -78,7 +78,7 @@ namespace Google.ProtocolBuffers { // implementations). // TODO(jonskeet): Provide a function somewhere called makeDeepCopy() // which allows people to make secure deep copies of messages. - foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) { + foreach (KeyValuePair<FieldDescriptor, object> entry in other.AllFields) { FieldDescriptor field = entry.Key; if (field.IsRepeated) { // Concatenate repeated fields diff --git a/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs b/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs index 14e1f177..a7772cf8 100644 --- a/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs +++ b/csharp/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs @@ -278,9 +278,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { #region Messages public sealed partial class FileDescriptorProto : pb::GeneratedMessage<FileDescriptorProto, FileDescriptorProto.Builder> { - // Use FileDescriptorProto.CreateBuilder() to construct. - private FileDescriptorProto() {} - private static readonly FileDescriptorProto defaultInstance = new FileDescriptorProto(); public static FileDescriptorProto DefaultInstance { get { return defaultInstance; } @@ -471,7 +468,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::FileDescriptorProto ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::FileDescriptorProto parseFrom(byte[] data, + public static self::FileDescriptorProto ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -960,9 +957,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class DescriptorProto : pb::GeneratedMessage<DescriptorProto, DescriptorProto.Builder> { - // Use DescriptorProto.CreateBuilder() to construct. - private DescriptorProto() {} - private static readonly DescriptorProto defaultInstance = new DescriptorProto(); public static DescriptorProto DefaultInstance { get { return defaultInstance; } @@ -983,9 +977,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { #region Nested types public static class Types { public sealed partial class ExtensionRange : pb::GeneratedMessage<ExtensionRange, ExtensionRange.Builder> { - // Use ExtensionRange.CreateBuilder() to construct. - private ExtensionRange() {} - private static readonly ExtensionRange defaultInstance = new ExtensionRange(); public static ExtensionRange DefaultInstance { get { return defaultInstance; } @@ -1069,7 +1060,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::DescriptorProto.Types.ExtensionRange ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::DescriptorProto.Types.ExtensionRange parseFrom(byte[] data, + public static self::DescriptorProto.Types.ExtensionRange ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -1389,7 +1380,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::DescriptorProto ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::DescriptorProto parseFrom(byte[] data, + public static self::DescriptorProto ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -1867,9 +1858,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class FieldDescriptorProto : pb::GeneratedMessage<FieldDescriptorProto, FieldDescriptorProto.Builder> { - // Use FieldDescriptorProto.CreateBuilder() to construct. - private FieldDescriptorProto() {} - private static readonly FieldDescriptorProto defaultInstance = new FieldDescriptorProto(); public static FieldDescriptorProto DefaultInstance { get { return defaultInstance; } @@ -2079,7 +2067,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::FieldDescriptorProto ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::FieldDescriptorProto parseFrom(byte[] data, + public static self::FieldDescriptorProto ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -2428,9 +2416,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class EnumDescriptorProto : pb::GeneratedMessage<EnumDescriptorProto, EnumDescriptorProto.Builder> { - // Use EnumDescriptorProto.CreateBuilder() to construct. - private EnumDescriptorProto() {} - private static readonly EnumDescriptorProto defaultInstance = new EnumDescriptorProto(); public static EnumDescriptorProto DefaultInstance { get { return defaultInstance; } @@ -2532,7 +2517,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::EnumDescriptorProto ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::EnumDescriptorProto parseFrom(byte[] data, + public static self::EnumDescriptorProto ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -2774,9 +2759,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class EnumValueDescriptorProto : pb::GeneratedMessage<EnumValueDescriptorProto, EnumValueDescriptorProto.Builder> { - // Use EnumValueDescriptorProto.CreateBuilder() to construct. - private EnumValueDescriptorProto() {} - private static readonly EnumValueDescriptorProto defaultInstance = new EnumValueDescriptorProto(); public static EnumValueDescriptorProto DefaultInstance { get { return defaultInstance; } @@ -2876,7 +2858,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::EnumValueDescriptorProto ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::EnumValueDescriptorProto parseFrom(byte[] data, + public static self::EnumValueDescriptorProto ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -3085,9 +3067,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class ServiceDescriptorProto : pb::GeneratedMessage<ServiceDescriptorProto, ServiceDescriptorProto.Builder> { - // Use ServiceDescriptorProto.CreateBuilder() to construct. - private ServiceDescriptorProto() {} - private static readonly ServiceDescriptorProto defaultInstance = new ServiceDescriptorProto(); public static ServiceDescriptorProto DefaultInstance { get { return defaultInstance; } @@ -3189,7 +3168,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::ServiceDescriptorProto ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::ServiceDescriptorProto parseFrom(byte[] data, + public static self::ServiceDescriptorProto ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -3431,9 +3410,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class MethodDescriptorProto : pb::GeneratedMessage<MethodDescriptorProto, MethodDescriptorProto.Builder> { - // Use MethodDescriptorProto.CreateBuilder() to construct. - private MethodDescriptorProto() {} - private static readonly MethodDescriptorProto defaultInstance = new MethodDescriptorProto(); public static MethodDescriptorProto DefaultInstance { get { return defaultInstance; } @@ -3549,7 +3525,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::MethodDescriptorProto ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::MethodDescriptorProto parseFrom(byte[] data, + public static self::MethodDescriptorProto ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -3784,9 +3760,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class FileOptions : pb::GeneratedMessage<FileOptions, FileOptions.Builder> { - // Use FileOptions.CreateBuilder() to construct. - private FileOptions() {} - private static readonly FileOptions defaultInstance = new FileOptions(); public static FileOptions DefaultInstance { get { return defaultInstance; } @@ -3991,7 +3964,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::FileOptions ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::FileOptions parseFrom(byte[] data, + public static self::FileOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -4340,9 +4313,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class MessageOptions : pb::GeneratedMessage<MessageOptions, MessageOptions.Builder> { - // Use MessageOptions.CreateBuilder() to construct. - private MessageOptions() {} - private static readonly MessageOptions defaultInstance = new MessageOptions(); public static MessageOptions DefaultInstance { get { return defaultInstance; } @@ -4410,7 +4380,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::MessageOptions ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::MessageOptions parseFrom(byte[] data, + public static self::MessageOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -4546,9 +4516,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class FieldOptions : pb::GeneratedMessage<FieldOptions, FieldOptions.Builder> { - // Use FieldOptions.CreateBuilder() to construct. - private FieldOptions() {} - private static readonly FieldOptions defaultInstance = new FieldOptions(); public static FieldOptions DefaultInstance { get { return defaultInstance; } @@ -4641,7 +4608,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::FieldOptions ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::FieldOptions parseFrom(byte[] data, + public static self::FieldOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -4808,9 +4775,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class EnumOptions : pb::GeneratedMessage<EnumOptions, EnumOptions.Builder> { - // Use EnumOptions.CreateBuilder() to construct. - private EnumOptions() {} - private static readonly EnumOptions defaultInstance = new EnumOptions(); public static EnumOptions DefaultInstance { get { return defaultInstance; } @@ -4862,7 +4826,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::EnumOptions ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::EnumOptions parseFrom(byte[] data, + public static self::EnumOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -4972,9 +4936,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class EnumValueOptions : pb::GeneratedMessage<EnumValueOptions, EnumValueOptions.Builder> { - // Use EnumValueOptions.CreateBuilder() to construct. - private EnumValueOptions() {} - private static readonly EnumValueOptions defaultInstance = new EnumValueOptions(); public static EnumValueOptions DefaultInstance { get { return defaultInstance; } @@ -5026,7 +4987,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::EnumValueOptions ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::EnumValueOptions parseFrom(byte[] data, + public static self::EnumValueOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -5136,9 +5097,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class ServiceOptions : pb::GeneratedMessage<ServiceOptions, ServiceOptions.Builder> { - // Use ServiceOptions.CreateBuilder() to construct. - private ServiceOptions() {} - private static readonly ServiceOptions defaultInstance = new ServiceOptions(); public static ServiceOptions DefaultInstance { get { return defaultInstance; } @@ -5190,7 +5148,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::ServiceOptions ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::ServiceOptions parseFrom(byte[] data, + public static self::ServiceOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); @@ -5300,9 +5258,6 @@ namespace Google.ProtocolBuffers.DescriptorProtos { } public sealed partial class MethodOptions : pb::GeneratedMessage<MethodOptions, MethodOptions.Builder> { - // Use MethodOptions.CreateBuilder() to construct. - private MethodOptions() {} - private static readonly MethodOptions defaultInstance = new MethodOptions(); public static MethodOptions DefaultInstance { get { return defaultInstance; } @@ -5354,7 +5309,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos { public static self::MethodOptions ParseFrom(byte[] data) { return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); } - public static self::MethodOptions parseFrom(byte[] data, + public static self::MethodOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) .BuildParsed(); diff --git a/csharp/ProtocolBuffers/DynamicMessage.cs b/csharp/ProtocolBuffers/DynamicMessage.cs index 5ffbdfbb..675c4c18 100644 --- a/csharp/ProtocolBuffers/DynamicMessage.cs +++ b/csharp/ProtocolBuffers/DynamicMessage.cs @@ -5,6 +5,11 @@ using System.Text; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers { + + /// <summary> + /// An implementation of IMessage that can represent arbitrary types, given a MessageaDescriptor. + /// TODO: Implement appropriate generics. + /// </summary> public class DynamicMessage : AbstractMessage { private readonly MessageDescriptor type; @@ -242,7 +247,7 @@ namespace Google.ProtocolBuffers { return this; } - public override IBuilder MergeFrom(IMessage other) { + public override IBuilder MergeFrom(IMessage other) { if (other.DescriptorForType != type) { throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type."); } @@ -251,7 +256,7 @@ namespace Google.ProtocolBuffers { } protected override IMessage BuildImpl() { - if (!Initialized) { + if (!IsInitialized) { throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)); } return BuildPartialImpl(); @@ -263,7 +268,7 @@ namespace Google.ProtocolBuffers { /// </summary> /// <returns></returns> internal DynamicMessage BuildParsed() { - if (!Initialized) { + if (!IsInitialized) { throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).AsInvalidProtocolBufferException(); } return (DynamicMessage) BuildPartialImpl(); @@ -283,7 +288,7 @@ namespace Google.ProtocolBuffers { return result; } - public override bool Initialized { + public override bool IsInitialized { get { return fields.IsInitializedWithRespectTo(type); } } diff --git a/csharp/ProtocolBuffers/GeneratedBuilder.cs b/csharp/ProtocolBuffers/GeneratedBuilder.cs index 154aa05f..a4114b5d 100644 --- a/csharp/ProtocolBuffers/GeneratedBuilder.cs +++ b/csharp/ProtocolBuffers/GeneratedBuilder.cs @@ -26,7 +26,7 @@ namespace Google.ProtocolBuffers { get { return MessageBeingBuilt.FieldAccesseorsFromBuilder; } } - public override bool Initialized { + public override bool IsInitialized { get { return MessageBeingBuilt.IsInitialized; } } @@ -212,7 +212,7 @@ namespace Google.ProtocolBuffers { /// TODO(jonskeet): This used to be generated for each class. Find out why. /// </summary> public TMessage BuildParsed() { - if (!Initialized) { + if (!IsInitialized) { throw new UninitializedMessageException(MessageBeingBuilt).AsInvalidProtocolBufferException(); } return BuildPartial(); @@ -223,7 +223,7 @@ namespace Google.ProtocolBuffers { /// TODO(jonskeet): This used to be generated for each class. Find out why. /// </summary> public TMessage Build() { - if (!Initialized) { + if (!IsInitialized) { throw new UninitializedMessageException(MessageBeingBuilt); } return BuildPartial(); diff --git a/csharp/ProtocolBuffers/IBuilder.cs b/csharp/ProtocolBuffers/IBuilder.cs index b46842cd..dcb3d272 100644 --- a/csharp/ProtocolBuffers/IBuilder.cs +++ b/csharp/ProtocolBuffers/IBuilder.cs @@ -33,7 +33,7 @@ namespace Google.ProtocolBuffers { /// Returns true iff all required fields in the message and all /// embedded messages are set. /// </summary> - bool Initialized { get; } + bool IsInitialized { get; } /// <summary> /// Behaves like the equivalent property in IMessage<T>. @@ -172,7 +172,7 @@ namespace Google.ProtocolBuffers { /// required fields, it will throw an UninitializedMessageException. /// There are a few good ways to deal with this: /// <list> - /// <item>Call Initialized to verify to verify that all required fields are + /// <item>Call IsInitialized to verify to verify that all required fields are /// set before building.</item> /// <item>Parse the message separately using one of the static ParseFrom /// methods, then use MergeFrom(IMessage<T>) to merge it with diff --git a/csharp/ProtocolBuffers/UninitializedMessageException.cs b/csharp/ProtocolBuffers/UninitializedMessageException.cs index 530f2057..01cdd2f1 100644 --- a/csharp/ProtocolBuffers/UninitializedMessageException.cs +++ b/csharp/ProtocolBuffers/UninitializedMessageException.cs @@ -14,15 +14,111 @@ // See the License for the specific language governing permissions and // limitations under the License. using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Google.ProtocolBuffers.Collections; +using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers { public class UninitializedMessageException : Exception { - public UninitializedMessageException(IMessage message) { + private readonly IList<string> missingFields; + + public UninitializedMessageException(IMessage message) + : this(FindMissingFields(message)) { + } + + private UninitializedMessageException(IList<string> missingFields) + : base(BuildDescription(missingFields)) { + this.missingFields = Lists.AsReadOnly(missingFields); } + + /// <summary> + /// Converts this exception into an InvalidProtocolBufferException. + /// When a parsed message is missing required fields, this should be thrown + /// instead of UninitializedMessageException. + /// </summary> public InvalidProtocolBufferException AsInvalidProtocolBufferException() { return new InvalidProtocolBufferException(Message); } + + /// <summary> + /// Constructs the description string for a given list of missing fields. + /// </summary> + private static string BuildDescription(IEnumerable<string> missingFields) { + StringBuilder description = new StringBuilder("Message missing required fields: "); + bool first = true; + foreach(string field in missingFields) { + if (first) { + first = false; + } else { + description.Append(", "); + } + description.Append(field); + } + return description.ToString(); + } + + /// <summary> + /// Returns a list of the full "paths" of missing required + /// fields in the specified message. + /// </summary> + private static IList<String> FindMissingFields(IMessage message) { + List<String> results = new List<String>(); + FindMissingFields(message, "", results); + return results; + } + + /// <summary> + /// Recursive helper implementing FindMissingFields. + /// </summary> + private static void FindMissingFields(IMessage message, String prefix, List<String> results) { + foreach (FieldDescriptor field in message.DescriptorForType.Fields) { + if (field.IsRequired && !message.HasField(field)) { + results.Add(prefix + field.Name); + } + } + + foreach (KeyValuePair<FieldDescriptor, object> entry in message.AllFields) { + FieldDescriptor field = entry.Key; + object value = entry.Value; + + if (field.MappedType == MappedType.Message) { + if (field.IsRepeated) { + int i = 0; + foreach (object element in (IEnumerable) value) { + FindMissingFields((IMessage) element, SubMessagePrefix(prefix, field, i++), results); + } + } else { + if (message.HasField(field)) { + FindMissingFields((IMessage) value, SubMessagePrefix(prefix, field, -1), results); + } + } + } + } + } + + private static String SubMessagePrefix(String prefix, FieldDescriptor field, int index) { + StringBuilder result = new StringBuilder(prefix); + if (field.IsExtension) { + result.Append('(') + .Append(field.FullName) + .Append(')'); + } else { + result.Append(field.Name); + } + if (index != -1) { + result.Append('[') + .Append(index) + .Append(']'); + } + result.Append('.'); + return result.ToString(); + } } } + + + |