Skip to content

Commit 15d6f79

Browse files
committed
Add key duplication detection. Related to issue #49.
1 parent b104538 commit 15d6f79

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

src/MsgPack/Serialization/SerializationTarget.cs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public static IList<SerializingMember> Prepare( SerializationContext context, Ty
5555
var result = PrepareCore( context, targetType );
5656

5757
VerifyNilImplication( targetType, result );
58+
VerifyKeyUniqueness( result );
5859

5960
return result;
6061
}
@@ -108,7 +109,7 @@ private static IList<SerializingMember> PrepareCore( SerializationContext contex
108109
}
109110

110111
return result;
111-
}
112+
}
112113

113114
// internal for testing
114115
internal static IEnumerable<SerializingMember> GetTargetMembers( Type type )
@@ -167,7 +168,7 @@ internal static IEnumerable<SerializingMember> GetTargetMembers( Type type )
167168
.FirstOrDefault();
168169
var id = item.data.GetNamedArguments()
169170
.Where( arg => arg.GetMemberName() == "Order" )
170-
.Select( arg => ( int? ) arg.GetTypedValue().Value )
171+
.Select( arg => ( int? )arg.GetTypedValue().Value )
171172
.FirstOrDefault();
172173
#if SILVERLIGHT
173174
if ( id == -1 )
@@ -280,5 +281,56 @@ private static void VerifyNilImplication( Type type, IEnumerable<SerializingMemb
280281
}
281282
}
282283
}
284+
285+
private static void VerifyKeyUniqueness( IList<SerializingMember> result )
286+
{
287+
var duplicated = new Dictionary<string, List<MemberInfo>>();
288+
var existents = new Dictionary<string, SerializingMember>();
289+
foreach ( var member in result )
290+
{
291+
if ( member.Contract.Name == null )
292+
{
293+
continue;
294+
}
295+
296+
try
297+
{
298+
existents.Add( member.Contract.Name, member );
299+
}
300+
catch ( ArgumentException )
301+
{
302+
List<MemberInfo> list;
303+
if ( duplicated.TryGetValue( member.Contract.Name, out list ) )
304+
{
305+
list.Add( member.Member );
306+
}
307+
else
308+
{
309+
duplicated.Add( member.Contract.Name, new List<MemberInfo> { existents[ member.Contract.Name ].Member, member.Member } );
310+
}
311+
}
312+
}
313+
314+
if ( duplicated.Count > 0 )
315+
{
316+
throw new InvalidOperationException(
317+
String.Format(
318+
CultureInfo.CurrentCulture,
319+
"Some member keys specified with custom attributes are duplicated. Details: {{{0}}}",
320+
String.Join(
321+
",",
322+
duplicated.Select(
323+
kv => String.Format(
324+
CultureInfo.CurrentCulture,
325+
"\"{0}\":[{1}]",
326+
kv.Key,
327+
String.Join( ",", kv.Value.Select( m => String.Format( "{0}.{1}({2})", m.DeclaringType, m.Name, ( m is FieldInfo ) ? "Field" : "Property" ) ).ToArray() )
328+
)
329+
).ToArray()
330+
)
331+
)
332+
);
333+
}
334+
}
283335
}
284336
}

test/MsgPack.UnitTest/Serialization/SerializationTargetTest.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ public void TestAliasInDataMember()
107107
Assert.That( target.Any( m => m.Contract.Name == "Alias" && m.Contract.Name != m.Member.Name ) );
108108
}
109109

110+
[Test]
111+
public void TestDuplicatedKey()
112+
{
113+
Assert.Throws<InvalidOperationException>( () => SerializationTarget.Prepare( new SerializationContext(), typeof( WithKeyDuplicate ) ) );
114+
}
115+
110116
private static void TestCore<T>( params string[] expectedMemberNames )
111117
{
112118
var expected = expectedMemberNames.OrderBy( n => n ).ToArray();

test/MsgPack.UnitTest/Serialization/SerializationTargets.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@ public DataMamberClass()
247247
#endif // !NETFX_CORE && !SILVERLIGHT
248248
}
249249
}
250+
public class WithKeyDuplicate
251+
{
252+
[MessagePackMember( 0, Name = "Boo" )]
253+
public string Foo { get; set; }
254+
255+
[MessagePackMember( 1, Name = "Boo" )]
256+
public int Bar { get; set; }
257+
}
258+
250259
// ReSharper restore MemberHidesStaticFromOuterClass
251260
// ReSharper restore NotAccessedField.Local
252261
// ReSharper restore UnusedMember.Local

0 commit comments

Comments
 (0)