aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/ProtocolBuffers/Collections/MapField.cs
diff options
context:
space:
mode:
authorJon Skeet <jonskeet@google.com>2015-07-16 17:03:06 +0100
committerJon Skeet <jonskeet@google.com>2015-07-16 17:03:06 +0100
commit8a0312b20156aa4df092cb6b3c665ef48cb6fa54 (patch)
tree8a5864fa5e8481ed8b04a25404cf51bc1818a37e /csharp/src/ProtocolBuffers/Collections/MapField.cs
parent8d47ec4f3e3368c5f4e7ac195f20978abc8a692f (diff)
downloadprotobuf-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.cs34
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; } }