diff options
Diffstat (limited to 'csharp/src/ProtocolBuffers/Collections')
-rw-r--r-- | csharp/src/ProtocolBuffers/Collections/MapField.cs | 34 | ||||
-rw-r--r-- | csharp/src/ProtocolBuffers/Collections/RepeatedField.cs | 2 |
2 files changed, 33 insertions, 3 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; } } diff --git a/csharp/src/ProtocolBuffers/Collections/RepeatedField.cs b/csharp/src/ProtocolBuffers/Collections/RepeatedField.cs index 8375ae0b..9bab41ea 100644 --- a/csharp/src/ProtocolBuffers/Collections/RepeatedField.cs +++ b/csharp/src/ProtocolBuffers/Collections/RepeatedField.cs @@ -123,7 +123,7 @@ namespace Google.Protobuf.Collections { int dataSize = CalculatePackedDataSize(codec); return CodedOutputStream.ComputeRawVarint32Size(tag) + - CodedOutputStream.ComputeRawVarint32Size((uint)dataSize) + + CodedOutputStream.ComputeLengthSize(dataSize) + dataSize; } else |