aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/Google.Protobuf/MessageExtensions.cs
diff options
context:
space:
mode:
Diffstat (limited to 'csharp/src/Google.Protobuf/MessageExtensions.cs')
-rw-r--r--csharp/src/Google.Protobuf/MessageExtensions.cs50
1 files changed, 50 insertions, 0 deletions
diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs
index 62181eb9..e1c57dc4 100644
--- a/csharp/src/Google.Protobuf/MessageExtensions.cs
+++ b/csharp/src/Google.Protobuf/MessageExtensions.cs
@@ -30,7 +30,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
+using Google.Protobuf.Reflection;
+using System.Collections;
using System.IO;
+using System.Linq;
namespace Google.Protobuf
{
@@ -140,6 +143,53 @@ namespace Google.Protobuf
return ByteString.AttachBytes(message.ToByteArray());
}
+ /// <summary>
+ /// Checks if all required fields in a message have values set. For proto3 messages, this returns true
+ /// </summary>
+ public static bool IsInitialized(this IMessage message)
+ {
+ if (message.Descriptor.File.Proto.Syntax != "proto2")
+ {
+ return true;
+ }
+
+ return message.Descriptor
+ .Fields
+ .InDeclarationOrder()
+ .All(f =>
+ {
+ if (f.IsMap)
+ {
+ var map = (IDictionary)f.Accessor.GetValue(message);
+ return map.Values.OfType<IMessage>().All(IsInitialized);
+ }
+ else if (f.IsRepeated && f.MessageType != null)
+ {
+ var enumerable = (IEnumerable)f.Accessor.GetValue(message);
+ return enumerable.Cast<IMessage>().All(IsInitialized);
+ }
+ else if (f.MessageType != null)
+ {
+ if (f.Accessor.HasValue(message))
+ {
+ return ((IMessage)f.Accessor.GetValue(message)).IsInitialized();
+ }
+ else
+ {
+ return !f.IsRequired;
+ }
+ }
+ else if (f.IsRequired)
+ {
+ return f.Accessor.HasValue(message);
+ }
+ else
+ {
+ return true;
+ }
+ });
+ }
+
// Implementations allowing unknown fields to be discarded.
internal static void MergeFrom(this IMessage message, byte[] data, bool discardUnknownFields)
{