Browse Source

Experimental (and currently unused) behaviour to determine whether or not a message has any required fields.

Jon Skeet 17 năm trước cách đây
mục cha
commit
8f721f5dc7

+ 4 - 0
csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs

@@ -221,6 +221,10 @@ namespace Google.ProtocolBuffers.Descriptors {
       foreach (FieldDescriptor extension in extensions) {
       foreach (FieldDescriptor extension in extensions) {
         extension.CrossLink();
         extension.CrossLink();
       }
       }
+
+      foreach (MessageDescriptor message in messageTypes) {
+        message.CheckRequiredFields();
+      }
     }
     }
     
     
     /// <summary>
     /// <summary>

+ 51 - 0
csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs

@@ -28,6 +28,7 @@ namespace Google.ProtocolBuffers.Descriptors {
     private readonly IList<EnumDescriptor> enumTypes;
     private readonly IList<EnumDescriptor> enumTypes;
     private readonly IList<FieldDescriptor> fields;
     private readonly IList<FieldDescriptor> fields;
     private readonly IList<FieldDescriptor> extensions;
     private readonly IList<FieldDescriptor> extensions;
+    private bool hasRequiredFields;
 
 
     internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
     internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
         : base(proto, file, ComputeFullName(file, parent, proto.Name), typeIndex) {
         : base(proto, file, ComputeFullName(file, parent, proto.Name), typeIndex) {
@@ -83,6 +84,16 @@ namespace Google.ProtocolBuffers.Descriptors {
       get { return enumTypes; }
       get { return enumTypes; }
     }
     }
 
 
+    /// <summary>
+    /// Returns a pre-computed result as to whether this message
+    /// has required fields. This includes optional fields which are
+    /// message types which in turn have required fields, and any 
+    /// extension fields.
+    /// </summary>
+    internal bool HasRequiredFields {
+      get { return hasRequiredFields; }
+    }
+
     /// <summary>
     /// <summary>
     /// Determines if the given field number is an extension.
     /// Determines if the given field number is an extension.
     /// </summary>
     /// </summary>
@@ -131,5 +142,45 @@ namespace Google.ProtocolBuffers.Descriptors {
         extension.CrossLink();
         extension.CrossLink();
       }
       }
     }
     }
+
+    internal void CheckRequiredFields() {
+      IDictionary<MessageDescriptor, byte> alreadySeen = new Dictionary<MessageDescriptor, byte>();
+      hasRequiredFields = CheckRequiredFields(alreadySeen);
+    }
+
+    private bool CheckRequiredFields(IDictionary<MessageDescriptor,byte> alreadySeen) {
+
+      if (alreadySeen.ContainsKey(this)) {
+        // The type is already in the cache. This means that either:
+        // a. The type has no required fields.
+        // b. We are in the midst of checking if the type has required fields,
+        //    somewhere up the stack.  In this case, we know that if the type
+        //    has any required fields, they'll be found when we return to it,
+        //    and the whole call to HasRequiredFields() will return true.
+        //    Therefore, we don't have to check if this type has required fields
+        //    here.
+        return false;
+      }
+      alreadySeen[this] = 0; // Value is irrelevant; we want set semantics
+
+      // If the type allows extensions, an extension with message type could contain
+      // required fields, so we have to be conservative and assume such an
+      // extension exists.
+      if (Proto.ExtensionRangeCount != 0) {
+        return true;
+      }
+
+      foreach (FieldDescriptor field in Fields) {
+        if (field.IsRequired) {
+          return true;
+        }
+        if (field.MappedType == MappedType.Message) {
+          if (field.MessageType.CheckRequiredFields(alreadySeen)) {
+            return true;
+          }
+        }
+      }
+      return false;
+    }
   }
   }
 }
 }

+ 3 - 0
csharp/ProtocolBuffers/GeneratedMessage.cs

@@ -68,6 +68,9 @@ namespace Google.ProtocolBuffers {
 
 
     public override bool IsInitialized {
     public override bool IsInitialized {
       get {
       get {
+       /* if (!DescriptorForType.HasRequiredFields) {
+          return true;
+        }*/
         // Check that all required fields are present.
         // Check that all required fields are present.
         foreach (FieldDescriptor field in DescriptorForType.Fields) {
         foreach (FieldDescriptor field in DescriptorForType.Fields) {
           if (field.IsRequired && !HasField(field)) {
           if (field.IsRequired && !HasField(field)) {