From 8a0312b20156aa4df092cb6b3c665ef48cb6fa54 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 16 Jul 2015 17:03:06 +0100 Subject: First pass at wrapper types. - We do still generate the message types, as otherwise reflection breaks, even though it doesn't actually use those types. - JSON handling hasn't been implemented yet --- csharp/src/ProtocolBuffers/Collections/MapField.cs | 34 ++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'csharp/src/ProtocolBuffers/Collections/MapField.cs') diff --git a/csharp/src/ProtocolBuffers/Collections/MapField.cs b/csharp/src/ProtocolBuffers/Collections/MapField.cs index 0f379eaa..ead45737 100644 --- a/csharp/src/ProtocolBuffers/Collections/MapField.cs +++ b/csharp/src/ProtocolBuffers/Collections/MapField.cs @@ -51,14 +51,38 @@ namespace Google.Protobuf.Collections public sealed class MapField : IDeepCloneable>, IFreezable, IDictionary, IEquatable>, IDictionary { // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.) + private bool allowNullValues; private bool frozen; private readonly Dictionary>> map = new Dictionary>>(); private readonly LinkedList> list = new LinkedList>(); + /// + /// Constructs a new map field, defaulting the value nullability to only allow null values for message types + /// and non-nullable value types. + /// + public MapField() : this(typeof(IMessage).IsAssignableFrom(typeof(TValue)) || Nullable.GetUnderlyingType(typeof(TValue)) != null) + { + } + + /// + /// Constructs a new map field, overriding the choice of whether null values are permitted in the map. + /// This is used by wrapper types, where maps with string and bytes wrappers as the value types + /// support null values. + /// + /// Whether null values are permitted in the map or not. + public MapField(bool allowNullValues) + { + if (allowNullValues && typeof(TValue).IsValueType && Nullable.GetUnderlyingType(typeof(TValue)) == null) + { + throw new ArgumentException("allowNullValues", "Non-nullable value types do not support null values"); + } + this.allowNullValues = allowNullValues; + } + public MapField Clone() { - var clone = new MapField(); + var clone = new MapField(allowNullValues); // Keys are never cloneable. Values might be. if (typeof(IDeepCloneable).IsAssignableFrom(typeof(TValue))) { @@ -138,7 +162,8 @@ namespace Google.Protobuf.Collections set { ThrowHelper.ThrowIfNull(key, "key"); - if (value == null && (typeof(TValue) == typeof(ByteString) || typeof(TValue) == typeof(string))) + // value == null check here is redundant, but avoids boxing. + if (value == null && !allowNullValues) { ThrowHelper.ThrowIfNull(value, "value"); } @@ -225,6 +250,11 @@ namespace Google.Protobuf.Collections } } + /// + /// Returns whether or not this map allows values to be null. + /// + public bool AllowsNullValues { get { return allowNullValues; } } + public int Count { get { return list.Count; } } public bool IsReadOnly { get { return frozen; } } -- cgit v1.2.3