Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
73c003c3
Commit
73c003c3
authored
Jan 13, 2016
by
Jan Tattermusch
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1089 from jskeet/map-null
Prohibit null values in maps
parents
937ef23a
9e4f354f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
86 additions
and
126 deletions
+86
-126
MapFieldTest.cs
csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
+2
-54
GeneratedMessageTest.cs
csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
+35
-1
JsonFormatterTest.cs
csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
+0
-7
UnittestWellKnownTypes.cs
...Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
+9
-9
WrappersTest.cs
...p/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
+5
-6
MapField.cs
csharp/src/Google.Protobuf/Collections/MapField.cs
+20
-33
Any.cs
csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
+3
-3
Api.cs
csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
+0
-1
Empty.cs
csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
+3
-3
FieldMask.cs
csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
+1
-1
Timestamp.cs
csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
+3
-3
Type.cs
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
+0
-0
Wrappers.cs
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
+4
-3
csharp_map_field.cc
src/google/protobuf/compiler/csharp/csharp_map_field.cc
+1
-2
No files found.
csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
View file @
73c003c3
...
...
@@ -56,7 +56,7 @@ namespace Google.Protobuf.Collections
}
[
Test
]
public
void
NullValues
()
public
void
NullValues
Prohibited
()
{
TestNullValues
<
int
?>(
0
);
TestNullValues
(
""
);
...
...
@@ -65,19 +65,12 @@ namespace Google.Protobuf.Collections
private
void
TestNullValues
<
T
>(
T
nonNullValue
)
{
var
map
=
new
MapField
<
int
,
T
>(
false
);
var
map
=
new
MapField
<
int
,
T
>();
var
nullValue
=
(
T
)
(
object
)
null
;
Assert
.
Throws
<
ArgumentNullException
>(()
=>
map
.
Add
(
0
,
nullValue
));
Assert
.
Throws
<
ArgumentNullException
>(()
=>
map
[
0
]
=
nullValue
);
map
.
Add
(
1
,
nonNullValue
);
map
[
1
]
=
nonNullValue
;
// Doesn't throw...
map
=
new
MapField
<
int
,
T
>(
true
);
map
.
Add
(
0
,
nullValue
);
map
[
0
]
=
nullValue
;
map
.
Add
(
1
,
nonNullValue
);
map
[
1
]
=
nonNullValue
;
}
[
Test
]
...
...
@@ -160,27 +153,6 @@ namespace Google.Protobuf.Collections
EqualityTester
.
AssertInequality
(
map1
,
map2
);
}
[
Test
]
public
void
EqualityHandlesNullValues
()
{
var
map1
=
new
MapField
<
string
,
ForeignMessage
>();
map1
.
Add
(
"a"
,
new
ForeignMessage
{
C
=
10
});
map1
.
Add
(
"b"
,
null
);
var
map2
=
new
MapField
<
string
,
ForeignMessage
>();
map2
.
Add
(
"a"
,
new
ForeignMessage
{
C
=
10
});
map2
.
Add
(
"b"
,
null
);
EqualityTester
.
AssertEquality
(
map1
,
map2
);
// Check the null value isn't ignored entirely...
Assert
.
IsTrue
(
map1
.
Remove
(
"b"
));
EqualityTester
.
AssertInequality
(
map1
,
map2
);
map1
.
Add
(
"b"
,
new
ForeignMessage
());
EqualityTester
.
AssertInequality
(
map1
,
map2
);
map1
[
"b"
]
=
null
;
EqualityTester
.
AssertEquality
(
map1
,
map2
);
}
[
Test
]
public
void
Add_Dictionary
()
{
...
...
@@ -453,30 +425,6 @@ namespace Google.Protobuf.Collections
Assert
.
Throws
<
ArgumentNullException
>(()
=>
dictionary
[
"x"
]
=
null
);
}
[
Test
]
public
void
AllowNullValues_Property
()
{
// Non-message reference type values are non-nullable by default, but can be overridden
Assert
.
IsFalse
(
new
MapField
<
int
,
string
>().
AllowsNullValues
);
Assert
.
IsFalse
(
new
MapField
<
int
,
string
>(
false
).
AllowsNullValues
);
Assert
.
IsTrue
(
new
MapField
<
int
,
string
>(
true
).
AllowsNullValues
);
// Non-nullable value type values are never nullable
Assert
.
IsFalse
(
new
MapField
<
int
,
int
>().
AllowsNullValues
);
Assert
.
IsFalse
(
new
MapField
<
int
,
int
>(
false
).
AllowsNullValues
);
Assert
.
Throws
<
ArgumentException
>(()
=>
new
MapField
<
int
,
int
>(
true
));
// Message type values are nullable by default, but can be overridden
Assert
.
IsTrue
(
new
MapField
<
int
,
TestAllTypes
>().
AllowsNullValues
);
Assert
.
IsFalse
(
new
MapField
<
int
,
TestAllTypes
>(
false
).
AllowsNullValues
);
Assert
.
IsTrue
(
new
MapField
<
int
,
TestAllTypes
>(
true
).
AllowsNullValues
);
// Nullable value type values are nullable by default, but can be overridden
Assert
.
IsTrue
(
new
MapField
<
int
,
int
?>().
AllowsNullValues
);
Assert
.
IsFalse
(
new
MapField
<
int
,
int
?>(
false
).
AllowsNullValues
);
Assert
.
IsTrue
(
new
MapField
<
int
,
int
?>(
true
).
AllowsNullValues
);
}
[
Test
]
public
void
KeysReturnsLiveView
()
{
...
...
csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
View file @
73c003c3
...
...
@@ -221,7 +221,7 @@ namespace Google.Protobuf
},
MapInt32ForeignMessage
=
{
{
0
,
new
ForeignMessage
{
C
=
10
}
},
{
5
,
n
ull
},
{
5
,
n
ew
ForeignMessage
()
},
},
MapInt32Enum
=
{
{
1
,
MapEnum
.
MAP_ENUM_BAR
},
...
...
@@ -268,6 +268,40 @@ namespace Google.Protobuf
Assert
.
AreEqual
(
nestedMessage
,
parsed
.
MapInt32ForeignMessage
[
0
]);
}
[
Test
]
public
void
MapWithOnlyKey_PrimitiveValue
()
{
// Hand-craft the stream to contain a single entry with just a key.
var
memoryStream
=
new
MemoryStream
();
var
output
=
new
CodedOutputStream
(
memoryStream
);
output
.
WriteTag
(
TestMap
.
MapInt32DoubleFieldNumber
,
WireFormat
.
WireType
.
LengthDelimited
);
int
key
=
10
;
output
.
WriteLength
(
1
+
CodedOutputStream
.
ComputeInt32Size
(
key
));
output
.
WriteTag
(
1
,
WireFormat
.
WireType
.
Varint
);
output
.
WriteInt32
(
key
);
output
.
Flush
();
var
parsed
=
TestMap
.
Parser
.
ParseFrom
(
memoryStream
.
ToArray
());
Assert
.
AreEqual
(
0.0
,
parsed
.
MapInt32Double
[
key
]);
}
[
Test
]
public
void
MapWithOnlyKey_MessageValue
()
{
// Hand-craft the stream to contain a single entry with just a key.
var
memoryStream
=
new
MemoryStream
();
var
output
=
new
CodedOutputStream
(
memoryStream
);
output
.
WriteTag
(
TestMap
.
MapInt32ForeignMessageFieldNumber
,
WireFormat
.
WireType
.
LengthDelimited
);
int
key
=
10
;
output
.
WriteLength
(
1
+
CodedOutputStream
.
ComputeInt32Size
(
key
));
output
.
WriteTag
(
1
,
WireFormat
.
WireType
.
Varint
);
output
.
WriteInt32
(
key
);
output
.
Flush
();
var
parsed
=
TestMap
.
Parser
.
ParseFrom
(
memoryStream
.
ToArray
());
Assert
.
AreEqual
(
new
ForeignMessage
(),
parsed
.
MapInt32ForeignMessage
[
key
]);
}
[
Test
]
public
void
MapIgnoresExtraFieldsWithinEntryMessages
()
{
...
...
csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
View file @
73c003c3
...
...
@@ -195,13 +195,6 @@ namespace Google.Protobuf
AssertJson
(
"{ 'repeatedForeignEnum': [ ] }"
,
JsonFormatter
.
Default
.
Format
(
message
));
}
[
Test
]
public
void
NullValueForMessage
()
{
var
message
=
new
TestMap
{
MapInt32ForeignMessage
=
{
{
10
,
null
}
}
};
AssertJson
(
"{ 'mapInt32ForeignMessage': { '10': null } }"
,
JsonFormatter
.
Default
.
Format
(
message
));
}
[
Test
]
[
TestCase
(
"a\u17b4b"
,
"a\\u17b4b"
)]
// Explicit
[
TestCase
(
"a\u0601b"
,
"a\\u0601b"
)]
// Ranged
...
...
csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
View file @
73c003c3
...
...
@@ -2080,7 +2080,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
DoubleFieldFieldNumber
=
10
;
private
static
readonly
pbc
::
MapField
<
int
,
double
?>.
Codec
_map_doubleField_codec
=
new
pbc
::
MapField
<
int
,
double
?>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForStructWrapper
<
double
>(
18
),
82
);
private
readonly
pbc
::
MapField
<
int
,
double
?>
doubleField_
=
new
pbc
::
MapField
<
int
,
double
?>(
true
);
private
readonly
pbc
::
MapField
<
int
,
double
?>
doubleField_
=
new
pbc
::
MapField
<
int
,
double
?>();
public
pbc
::
MapField
<
int
,
double
?>
DoubleField
{
get
{
return
doubleField_
;
}
}
...
...
@@ -2089,7 +2089,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
FloatFieldFieldNumber
=
11
;
private
static
readonly
pbc
::
MapField
<
int
,
float
?>.
Codec
_map_floatField_codec
=
new
pbc
::
MapField
<
int
,
float
?>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForStructWrapper
<
float
>(
18
),
90
);
private
readonly
pbc
::
MapField
<
int
,
float
?>
floatField_
=
new
pbc
::
MapField
<
int
,
float
?>(
true
);
private
readonly
pbc
::
MapField
<
int
,
float
?>
floatField_
=
new
pbc
::
MapField
<
int
,
float
?>();
public
pbc
::
MapField
<
int
,
float
?>
FloatField
{
get
{
return
floatField_
;
}
}
...
...
@@ -2098,7 +2098,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
Int64FieldFieldNumber
=
12
;
private
static
readonly
pbc
::
MapField
<
int
,
long
?>.
Codec
_map_int64Field_codec
=
new
pbc
::
MapField
<
int
,
long
?>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForStructWrapper
<
long
>(
18
),
98
);
private
readonly
pbc
::
MapField
<
int
,
long
?>
int64Field_
=
new
pbc
::
MapField
<
int
,
long
?>(
true
);
private
readonly
pbc
::
MapField
<
int
,
long
?>
int64Field_
=
new
pbc
::
MapField
<
int
,
long
?>();
public
pbc
::
MapField
<
int
,
long
?>
Int64Field
{
get
{
return
int64Field_
;
}
}
...
...
@@ -2107,7 +2107,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
Uint64FieldFieldNumber
=
13
;
private
static
readonly
pbc
::
MapField
<
int
,
ulong
?>.
Codec
_map_uint64Field_codec
=
new
pbc
::
MapField
<
int
,
ulong
?>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForStructWrapper
<
ulong
>(
18
),
106
);
private
readonly
pbc
::
MapField
<
int
,
ulong
?>
uint64Field_
=
new
pbc
::
MapField
<
int
,
ulong
?>(
true
);
private
readonly
pbc
::
MapField
<
int
,
ulong
?>
uint64Field_
=
new
pbc
::
MapField
<
int
,
ulong
?>();
public
pbc
::
MapField
<
int
,
ulong
?>
Uint64Field
{
get
{
return
uint64Field_
;
}
}
...
...
@@ -2116,7 +2116,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
Int32FieldFieldNumber
=
14
;
private
static
readonly
pbc
::
MapField
<
int
,
int
?>.
Codec
_map_int32Field_codec
=
new
pbc
::
MapField
<
int
,
int
?>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForStructWrapper
<
int
>(
18
),
114
);
private
readonly
pbc
::
MapField
<
int
,
int
?>
int32Field_
=
new
pbc
::
MapField
<
int
,
int
?>(
true
);
private
readonly
pbc
::
MapField
<
int
,
int
?>
int32Field_
=
new
pbc
::
MapField
<
int
,
int
?>();
public
pbc
::
MapField
<
int
,
int
?>
Int32Field
{
get
{
return
int32Field_
;
}
}
...
...
@@ -2125,7 +2125,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
Uint32FieldFieldNumber
=
15
;
private
static
readonly
pbc
::
MapField
<
int
,
uint
?>.
Codec
_map_uint32Field_codec
=
new
pbc
::
MapField
<
int
,
uint
?>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForStructWrapper
<
uint
>(
18
),
122
);
private
readonly
pbc
::
MapField
<
int
,
uint
?>
uint32Field_
=
new
pbc
::
MapField
<
int
,
uint
?>(
true
);
private
readonly
pbc
::
MapField
<
int
,
uint
?>
uint32Field_
=
new
pbc
::
MapField
<
int
,
uint
?>();
public
pbc
::
MapField
<
int
,
uint
?>
Uint32Field
{
get
{
return
uint32Field_
;
}
}
...
...
@@ -2134,7 +2134,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
BoolFieldFieldNumber
=
16
;
private
static
readonly
pbc
::
MapField
<
int
,
bool
?>.
Codec
_map_boolField_codec
=
new
pbc
::
MapField
<
int
,
bool
?>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForStructWrapper
<
bool
>(
18
),
130
);
private
readonly
pbc
::
MapField
<
int
,
bool
?>
boolField_
=
new
pbc
::
MapField
<
int
,
bool
?>(
true
);
private
readonly
pbc
::
MapField
<
int
,
bool
?>
boolField_
=
new
pbc
::
MapField
<
int
,
bool
?>();
public
pbc
::
MapField
<
int
,
bool
?>
BoolField
{
get
{
return
boolField_
;
}
}
...
...
@@ -2143,7 +2143,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
StringFieldFieldNumber
=
17
;
private
static
readonly
pbc
::
MapField
<
int
,
string
>.
Codec
_map_stringField_codec
=
new
pbc
::
MapField
<
int
,
string
>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForClassWrapper
<
string
>(
18
),
138
);
private
readonly
pbc
::
MapField
<
int
,
string
>
stringField_
=
new
pbc
::
MapField
<
int
,
string
>(
true
);
private
readonly
pbc
::
MapField
<
int
,
string
>
stringField_
=
new
pbc
::
MapField
<
int
,
string
>();
public
pbc
::
MapField
<
int
,
string
>
StringField
{
get
{
return
stringField_
;
}
}
...
...
@@ -2152,7 +2152,7 @@ namespace Google.Protobuf.TestProtos {
public
const
int
BytesFieldFieldNumber
=
18
;
private
static
readonly
pbc
::
MapField
<
int
,
pb
::
ByteString
>.
Codec
_map_bytesField_codec
=
new
pbc
::
MapField
<
int
,
pb
::
ByteString
>.
Codec
(
pb
::
FieldCodec
.
ForInt32
(
8
),
pb
::
FieldCodec
.
ForClassWrapper
<
pb
::
ByteString
>(
18
),
146
);
private
readonly
pbc
::
MapField
<
int
,
pb
::
ByteString
>
bytesField_
=
new
pbc
::
MapField
<
int
,
pb
::
ByteString
>(
true
);
private
readonly
pbc
::
MapField
<
int
,
pb
::
ByteString
>
bytesField_
=
new
pbc
::
MapField
<
int
,
pb
::
ByteString
>();
public
pbc
::
MapField
<
int
,
pb
::
ByteString
>
BytesField
{
get
{
return
bytesField_
;
}
}
...
...
csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
View file @
73c003c3
...
...
@@ -151,6 +151,8 @@ namespace Google.Protobuf.WellKnownTypes
[
Test
]
public
void
MapWrappersSerializeDeserialize
()
{
// Note: no null values here, as they are prohibited in map fields
// (despite being representable).
var
message
=
new
MapWellKnownTypes
{
BoolField
=
{
{
10
,
false
},
{
20
,
true
}
},
...
...
@@ -158,13 +160,12 @@ namespace Google.Protobuf.WellKnownTypes
{
-
1
,
ByteString
.
CopyFrom
(
1
,
2
,
3
)
},
{
10
,
ByteString
.
CopyFrom
(
4
,
5
,
6
)
},
{
1000
,
ByteString
.
Empty
},
{
10000
,
null
}
},
DoubleField
=
{
{
1
,
12.5
},
{
10
,
-
1.5
},
{
20
,
0d
}
},
FloatField
=
{
{
2
,
123.25f
},
{
3
,
-
20f
},
{
4
,
0f
}
},
Int32Field
=
{
{
5
,
int
.
MaxValue
},
{
6
,
int
.
MinValue
},
{
7
,
0
}
},
Int64Field
=
{
{
8
,
long
.
MaxValue
},
{
9
,
long
.
MinValue
},
{
10
,
0L
}
},
StringField
=
{
{
11
,
"First"
},
{
12
,
"Second"
},
{
13
,
""
}
,
{
14
,
null
}
},
StringField
=
{
{
11
,
"First"
},
{
12
,
"Second"
},
{
13
,
""
}
},
Uint32Field
=
{
{
15
,
uint
.
MaxValue
},
{
16
,
uint
.
MinValue
},
{
17
,
0U
}
},
Uint64Field
=
{
{
18
,
ulong
.
MaxValue
},
{
19
,
ulong
.
MinValue
},
{
20
,
0U
L
}
},
};
...
...
@@ -224,13 +225,11 @@ namespace Google.Protobuf.WellKnownTypes
[
Test
]
public
void
Reflection_MapFields
()
{
// Just a single example... note that we can't have a null value here
var
message
=
new
MapWellKnownTypes
{
Int32Field
=
{
{
1
,
2
}
,
{
3
,
null
}
}
};
// Just a single example... note that we can't have a null value here
despite the value type being int?
var
message
=
new
MapWellKnownTypes
{
Int32Field
=
{
{
1
,
2
}
}
};
var
fields
=
MapWellKnownTypes
.
Descriptor
.
Fields
;
var
dictionary
=
(
IDictionary
)
fields
[
MapWellKnownTypes
.
Int32FieldFieldNumber
].
Accessor
.
GetValue
(
message
);
Assert
.
AreEqual
(
2
,
dictionary
[
1
]);
Assert
.
IsNull
(
dictionary
[
3
]);
Assert
.
IsTrue
(
dictionary
.
Contains
(
3
));
}
[
Test
]
...
...
csharp/src/Google.Protobuf/Collections/MapField.cs
View file @
73c003c3
...
...
@@ -53,6 +53,13 @@ namespace Google.Protobuf.Collections
/// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
/// </para>
/// <para>
/// Null values are not permitted in the map, either for wrapper types or regular messages.
/// If a map is deserialized from a data stream and the value is missing from an entry, a default value
/// is created instead. For primitive types, that is the regular default value (0, the empty string and so
/// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
/// encoded value for the field.
/// </para>
/// <para>
/// This implementation does not generally prohibit the use of key/value types which are not
/// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
/// that all operations will work in such cases.
...
...
@@ -61,34 +68,10 @@ namespace Google.Protobuf.Collections
public
sealed
class
MapField
<
TKey
,
TValue
>
:
IDeepCloneable
<
MapField
<
TKey
,
TValue
>>,
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
readonly
bool
allowNullValues
;
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
;
}
/// <summary>
/// Creates a deep clone of this object.
/// </summary>
...
...
@@ -97,13 +80,13 @@ namespace Google.Protobuf.Collections
/// </returns>
public
MapField
<
TKey
,
TValue
>
Clone
()
{
var
clone
=
new
MapField
<
TKey
,
TValue
>(
allowNullValues
);
var
clone
=
new
MapField
<
TKey
,
TValue
>();
// Keys are never cloneable. Values might be.
if
(
typeof
(
IDeepCloneable
<
TValue
>).
IsAssignableFrom
(
typeof
(
TValue
)))
{
foreach
(
var
pair
in
list
)
{
clone
.
Add
(
pair
.
Key
,
pair
.
Value
==
null
?
pair
.
Value
:
((
IDeepCloneable
<
TValue
>)
pair
.
Value
).
Clone
());
clone
.
Add
(
pair
.
Key
,
((
IDeepCloneable
<
TValue
>)
pair
.
Value
).
Clone
());
}
}
else
...
...
@@ -217,7 +200,7 @@ namespace Google.Protobuf.Collections
{
Preconditions
.
CheckNotNullUnconstrained
(
key
,
"key"
);
// value == null check here is redundant, but avoids boxing.
if
(
value
==
null
&&
!
allowNullValues
)
if
(
value
==
null
)
{
Preconditions
.
CheckNotNullUnconstrained
(
value
,
"value"
);
}
...
...
@@ -246,7 +229,7 @@ namespace Google.Protobuf.Collections
public
ICollection
<
TValue
>
Values
{
get
{
return
new
MapView
<
TValue
>(
this
,
pair
=>
pair
.
Value
,
ContainsValue
);
}
}
/// <summary>
/// Adds the specified entries to the map.
/// Adds the specified entries to the map.
The keys and values are not automatically cloned.
/// </summary>
/// <param name="entries">The entries to add to the map.</param>
public
void
Add
(
IDictionary
<
TKey
,
TValue
>
entries
)
...
...
@@ -346,11 +329,6 @@ namespace Google.Protobuf.Collections
}
}
/// <summary>
/// Returns whether or not this map allows values to be null.
/// </summary>
public
bool
AllowsNullValues
{
get
{
return
allowNullValues
;
}
}
/// <summary>
/// Gets the number of elements contained in the map.
/// </summary>
...
...
@@ -632,6 +610,8 @@ namespace Google.Protobuf.Collections
/// </summary>
internal
class
MessageAdapter
:
IMessage
{
private
static
readonly
byte
[]
ZeroLengthMessageStreamData
=
new
byte
[]
{
0
};
private
readonly
Codec
codec
;
internal
TKey
Key
{
get
;
set
;
}
internal
TValue
Value
{
get
;
set
;
}
...
...
@@ -665,6 +645,13 @@ namespace Google.Protobuf.Collections
input
.
SkipLastField
();
}
}
// Corner case: a map entry with a key but no value, where the value type is a message.
// Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
if
(
Value
==
null
)
{
Value
=
codec
.
valueCodec
.
Read
(
new
CodedInputStream
(
ZeroLengthMessageStreamData
));
}
}
public
void
WriteTo
(
CodedOutputStream
output
)
...
...
csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
View file @
73c003c3
...
...
@@ -61,8 +61,8 @@ namespace Google.Protobuf.WellKnownTypes {
///
/// If the embedded message type is well-known and has a custom JSON
/// representation, that representation will be embedded adding a field
/// `value` which holds the custom JSON in addition to the
the
`@type`
/// field. Example (for message [google.protobuf.Duration][
google.protobuf.Duration
]):
/// `value` which holds the custom JSON in addition to the `@type`
/// field. Example (for message [google.protobuf.Duration][]):
///
/// {
/// "@type": "type.googleapis.com/google.protobuf.Duration",
...
...
@@ -110,7 +110,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// * If no schema is provided, `https` is assumed.
/// * The last segment of the URL's path must represent the fully
/// qualified name of the type (as in `path/google.protobuf.Duration`).
/// * An HTTP GET on the URL must yield a [google.protobuf.Type][
google.protobuf.Type
]
/// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
/// value in binary format, or produce an error.
/// * Applications are allowed to cache lookup results based on the
/// URL, or have them precompiled into a binary to avoid any
...
...
csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
View file @
73c003c3
...
...
@@ -653,7 +653,6 @@ namespace Google.Protobuf.WellKnownTypes {
///
/// package google.storage.v2;
/// service Storage {
/// // (-- see AccessControl.GetAcl --)
/// rpc GetAcl(GetAclRequest) returns (Acl);
///
/// // Get a data record.
...
...
csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
View file @
73c003c3
...
...
@@ -24,9 +24,9 @@ namespace Google.Protobuf.WellKnownTypes {
byte
[]
descriptorData
=
global
::
System
.
Convert
.
FromBase64String
(
string
.
Concat
(
"Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1"
,
"ZiIHCgVFbXB0eUJ
N
ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv"
,
"UAGgAQ
GiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNi
"
,
"BnByb3RvMw=="
));
"ZiIHCgVFbXB0eUJ
Q
ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv"
,
"UAGgAQ
H4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw
"
,
"
ZXNi
BnByb3RvMw=="
));
descriptor
=
pbr
::
FileDescriptor
.
FromGeneratedCode
(
descriptorData
,
new
pbr
::
FileDescriptor
[]
{
},
new
pbr
::
GeneratedCodeInfo
(
null
,
new
pbr
::
GeneratedCodeInfo
[]
{
...
...
csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
View file @
73c003c3
...
...
@@ -69,7 +69,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// z: 8
///
/// The result will not contain specific values for fields x,y and z
/// (the
re
value will be set to the default, and omitted in proto text
/// (the
ir
value will be set to the default, and omitted in proto text
/// output):
///
/// f {
...
...
csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
View file @
73c003c3
...
...
@@ -25,9 +25,9 @@ namespace Google.Protobuf.WellKnownTypes {
string
.
Concat
(
"Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv"
,
"dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY"
,
"AiABKAVC
UQ
oTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q"
,
"AaABA
aICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG
"
,
"cHJvdG8z"
));
"AiABKAVC
VA
oTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q"
,
"AaABA
fgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBl
"
,
"c
2IGc
HJvdG8z"
));
descriptor
=
pbr
::
FileDescriptor
.
FromGeneratedCode
(
descriptorData
,
new
pbr
::
FileDescriptor
[]
{
},
new
pbr
::
GeneratedCodeInfo
(
null
,
new
pbr
::
GeneratedCodeInfo
[]
{
...
...
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
View file @
73c003c3
This diff is collapsed.
Click to expand it.
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
View file @
73c003c3
...
...
@@ -29,9 +29,10 @@ namespace Google.Protobuf.WellKnownTypes {
"KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1"
,
"ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo"
,
"DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS"
,
"DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJQ"
,
"ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQGiAgNH"
,
"UEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="
));
"DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJT"
,
"ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQH4AQGi"
,
"AgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3Rv"
,
"Mw=="
));
descriptor
=
pbr
::
FileDescriptor
.
FromGeneratedCode
(
descriptorData
,
new
pbr
::
FileDescriptor
[]
{
},
new
pbr
::
GeneratedCodeInfo
(
null
,
new
pbr
::
GeneratedCodeInfo
[]
{
...
...
src/google/protobuf/compiler/csharp/csharp_map_field.cc
View file @
73c003c3
...
...
@@ -62,7 +62,6 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
descriptor_
->
message_type
()
->
FindFieldByName
(
"value"
);
variables_
[
"key_type_name"
]
=
type_name
(
key_descriptor
);
variables_
[
"value_type_name"
]
=
type_name
(
value_descriptor
);
variables_
[
"true_for_wrappers"
]
=
IsWrapperType
(
value_descriptor
)
?
"true"
:
""
;
scoped_ptr
<
FieldGeneratorBase
>
key_generator
(
CreateFieldGenerator
(
key_descriptor
,
1
));
scoped_ptr
<
FieldGeneratorBase
>
value_generator
(
CreateFieldGenerator
(
value_descriptor
,
2
));
...
...
@@ -76,7 +75,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
printer
->
Print
(
variables_
,
", $tag$);
\n
"
"private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>(
$true_for_wrappers$
);
\n
"
);
"private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();
\n
"
);
WritePropertyDocComment
(
printer
,
descriptor_
);
AddDeprecatedFlag
(
printer
);
printer
->
Print
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment