diff options
author | Jon Skeet <jonskeet@google.com> | 2015-07-16 17:03:06 +0100 |
---|---|---|
committer | Jon Skeet <jonskeet@google.com> | 2015-07-16 17:03:06 +0100 |
commit | 8a0312b20156aa4df092cb6b3c665ef48cb6fa54 (patch) | |
tree | 8a5864fa5e8481ed8b04a25404cf51bc1818a37e /csharp/src/ProtocolBuffers/Collections/MapField.cs | |
parent | 8d47ec4f3e3368c5f4e7ac195f20978abc8a692f (diff) | |
download | protobuf-8a0312b20156aa4df092cb6b3c665ef48cb6fa54.tar.gz protobuf-8a0312b20156aa4df092cb6b3c665ef48cb6fa54.tar.bz2 protobuf-8a0312b20156aa4df092cb6b3c665ef48cb6fa54.zip |
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
Diffstat (limited to 'csharp/src/ProtocolBuffers/Collections/MapField.cs')
-rw-r--r-- | csharp/src/ProtocolBuffers/Collections/MapField.cs | 34 |
1 files changed, 32 insertions, 2 deletions
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<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IFreezable, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, 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<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map = new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(); private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>(); + /// <summary> + /// Constructs a new map field, defaulting the value nullability to only allow null values for message types + /// and non-nullable value types. + /// </summary> + public MapField() : this(typeof(IMessage).IsAssignableFrom(typeof(TValue)) || Nullable.GetUnderlyingType(typeof(TValue)) != null) + { + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="allowNullValues">Whether null values are permitted in the map or not.</param> + 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<TKey, TValue> Clone() { - var clone = new MapField<TKey, TValue>(); + var clone = new MapField<TKey, TValue>(allowNullValues); // Keys are never cloneable. Values might be. if (typeof(IDeepCloneable<TValue>).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 } } + /// <summary> + /// Returns whether or not this map allows values to be null. + /// </summary> + public bool AllowsNullValues { get { return allowNullValues; } } + public int Count { get { return list.Count; } } public bool IsReadOnly { get { return frozen; } } |