Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit c560f98

Browse files
committed
1) Adding support for excluding [NonSerialized] members from serialization, this is prerequisite for #2.
2) Adding support for ReadOnlyDictionary.
1 parent e38e54f commit c560f98

File tree

5 files changed

+168
-21
lines changed

5 files changed

+168
-21
lines changed

src/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
33
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
44
<PropertyGroup>
@@ -149,6 +149,7 @@
149149
<Compile Include="$(JsonSources)\ByteArrayHelperWithString.cs" />
150150
<Compile Include="$(JsonSources)\JsonEncodingStreamWrapper.cs" />
151151
<Compile Include="$(JsonSources)\JsonFormatGeneratorStatics.cs" Condition="!$(NetNative)" />
152+
<Compile Include="System\Runtime\Serialization\SerializableInfo.cs" />
152153
</ItemGroup>
153154
<ItemGroup Condition="'$(TargetGroup)'=='netcore50aot'">
154155
<TargetingPackReference Include="System.Private.CoreLib.Augments" />
@@ -158,4 +159,4 @@
158159
<None Include="project.json" />
159160
</ItemGroup>
160161
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
161-
</Project>
162+
</Project>

src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -439,16 +439,12 @@ static internal bool IsNonAttributedTypeValidForSerialization(Type type)
439439
}
440440
}
441441

442-
private static string[] s_knownSerializableTypeNames = new string[] {
443-
"System.Collections.Queue",
444-
"System.Collections.Stack",
445-
"System.Globalization.CultureInfo",
446-
"System.Version",
442+
private static string[] s_knownSerializableGenericTypeNames = new string[] {
447443
"System.Collections.Generic.KeyValuePair`2",
448-
"System.Collections.Generic.Queue`1",
449-
"System.Collections.Generic.Stack`1",
450-
"System.Collections.ObjectModel.ReadOnlyCollection`1",
451-
"System.Collections.ObjectModel.ReadOnlyDictionary`2",
444+
"System.Collections.Generic.Queue`1;_syncRoot",
445+
"System.Collections.Generic.Stack`1;_syncRoot",
446+
"System.Collections.ObjectModel.ReadOnlyCollection`1;_syncRoot",
447+
"System.Collections.ObjectModel.ReadOnlyDictionary`2;_syncRoot,_keys,_values",
452448
"System.Tuple`1",
453449
"System.Tuple`2",
454450
"System.Tuple`3",
@@ -459,26 +455,106 @@ static internal bool IsNonAttributedTypeValidForSerialization(Type type)
459455
"System.Tuple`8",
460456
};
461457

458+
private static string[] s_knownSerializableNonGenericTypeNames = new string[] {
459+
"System.Collections.Queue;_syncRoot",
460+
"System.Collections.Stack;_syncRoot",
461+
"System.Globalization.CultureInfo",
462+
"System.Version",
463+
};
464+
465+
private static object s_knownSerializableGenericTypeInfosLock = new object();
466+
private static volatile IDictionary<string, SerializableInfo> s_knownSerializableGenericTypeInfos;
467+
private static IDictionary<string, SerializableInfo> KnownSerializableGenericTypes
468+
{
469+
get
470+
{
471+
if (s_knownSerializableGenericTypeInfos == null)
472+
{
473+
lock (s_knownSerializableGenericTypeInfosLock)
474+
{
475+
if (s_knownSerializableGenericTypeInfos == null)
476+
{
477+
s_knownSerializableGenericTypeInfos = new Dictionary<string, SerializableInfo>();
478+
InitializeKnownSerializableTypesFromStringList(s_knownSerializableGenericTypeNames, s_knownSerializableGenericTypeInfos);
479+
}
480+
}
481+
}
482+
return s_knownSerializableGenericTypeInfos;
483+
}
484+
}
485+
486+
private static object s_knownSerializableNonGenericTypeInfosLock = new object();
487+
private static volatile IDictionary<string, SerializableInfo> s_knownSerializableNonGenericTypeInfos;
488+
private static IDictionary<string, SerializableInfo> KnownSerializableNonGenericTypes
489+
{
490+
get
491+
{
492+
if (s_knownSerializableNonGenericTypeInfos == null)
493+
{
494+
lock (s_knownSerializableNonGenericTypeInfosLock)
495+
{
496+
if (s_knownSerializableNonGenericTypeInfos == null)
497+
{
498+
s_knownSerializableNonGenericTypeInfos = new Dictionary<string, SerializableInfo>();
499+
InitializeKnownSerializableTypesFromStringList(s_knownSerializableNonGenericTypeNames, s_knownSerializableNonGenericTypeInfos);
500+
}
501+
}
502+
}
503+
return s_knownSerializableNonGenericTypeInfos;
504+
}
505+
}
506+
507+
private static void InitializeKnownSerializableTypesFromStringList(string[] listOfTypes, IDictionary<string, SerializableInfo> dict)
508+
{
509+
Debug.Assert(listOfTypes != null);
510+
Debug.Assert(dict != null);
511+
foreach (string str in listOfTypes)
512+
{
513+
SerializableInfo si = SerializableInfo.Parse(str);
514+
dict.Add(si.TypeName, si);
515+
}
516+
}
517+
462518
internal static bool IsKnownSerializableType(Type type)
463519
{
464520
// Applies to known types that DCS understands how to serialize/deserialize
465521
//
466522

467-
// Ajdust for generic type
468-
if (type.GetTypeInfo().IsGenericType && !type.GetTypeInfo().IsGenericTypeDefinition)
523+
if (type.GetTypeInfo().IsGenericType)
469524
{
470-
type = type.GetGenericTypeDefinition();
525+
if (!type.GetTypeInfo().IsGenericTypeDefinition)
526+
{
527+
type = type.GetTypeInfo().GetGenericTypeDefinition();
528+
}
529+
return Enumerable.Contains(KnownSerializableGenericTypes.Keys, type.FullName);
471530
}
472-
473-
// Check for known types
474-
if (Enumerable.Contains(s_knownSerializableTypeNames, type.FullName))
531+
else if (Enumerable.Contains(KnownSerializableNonGenericTypes.Keys, type.FullName))
475532
{
476533
return true;
477534
}
478-
//Enable ClassDataContract to give support to Exceptions.
479-
if (Globals.TypeOfException.IsAssignableFrom(type))
535+
else if (Globals.TypeOfException.IsAssignableFrom(type))
536+
{
537+
//Enable ClassDataContract to give support to Exceptions.
480538
return true;
539+
}
540+
541+
return false;
542+
}
481543

544+
internal static bool IsNonSerializedMember(Type type, string memberName)
545+
{
546+
if (type.GetTypeInfo().IsGenericType)
547+
{
548+
Type genericTypeDef = type.GetTypeInfo().IsGenericTypeDefinition ? type : type.GetTypeInfo().GetGenericTypeDefinition();
549+
if (KnownSerializableGenericTypes.Keys.Contains(genericTypeDef.FullName))
550+
{
551+
return Enumerable.Contains(KnownSerializableGenericTypes[genericTypeDef.FullName].NonSerializedMembers, memberName);
552+
}
553+
}
554+
else if (KnownSerializableNonGenericTypes.Keys.Contains(type.FullName))
555+
{
556+
return Enumerable.Contains(KnownSerializableNonGenericTypes[type.FullName].NonSerializedMembers, memberName);
557+
}
482558
return false;
483559
}
484560

@@ -1073,8 +1149,7 @@ private void ImportDataMembers()
10731149

10741150
private static bool CanSerializeMember(FieldInfo field)
10751151
{
1076-
return field != null &&
1077-
field.FieldType != Globals.TypeOfObject; // Don't really know how to serialize plain System.Object instance;
1152+
return field != null && !ClassDataContract.IsNonSerializedMember(field.DeclaringType, field.Name);
10781153
}
10791154

10801155
private bool SetIfGetOnlyCollection(DataMember memberContract)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//-----------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
//-----------------------------------------------------------------------------
4+
namespace System.Runtime.Serialization
5+
{
6+
using System;
7+
using System.Diagnostics;
8+
9+
public class SerializableInfo
10+
{
11+
public string TypeName { get; set; }
12+
public string[] NonSerializedMembers { get; set; }
13+
14+
private SerializableInfo(string typeName, string[] nonSerializedMembers)
15+
{
16+
Debug.Assert(!string.IsNullOrEmpty(typeName));
17+
Debug.Assert(nonSerializedMembers != null);
18+
TypeName = typeName;
19+
NonSerializedMembers = nonSerializedMembers;
20+
}
21+
22+
public static SerializableInfo Parse(string str)
23+
{
24+
if (string.IsNullOrEmpty(str))
25+
{
26+
throw new ArgumentNullException("str");
27+
}
28+
string[] parts = str.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
29+
if (parts.Length == 0)
30+
{
31+
throw new ArgumentException("str");
32+
}
33+
string typeName = parts[0];
34+
string[] nonSerializedMembers = new string[0];
35+
if (parts.Length == 2)
36+
{
37+
nonSerializedMembers = parts[1].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
38+
}
39+
SerializableInfo si = new SerializableInfo(typeName, nonSerializedMembers);
40+
return si;
41+
}
42+
}
43+
}

src/System.Runtime.Serialization.Json/tests/DataContractJsonSerializer.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,20 @@ public static void DCJS_ReadOnlyCollection()
15961596
Assert.StrictEqual(value[1], deserializedValue[1]);
15971597
}
15981598

1599+
[Fact]
1600+
public static void DCJS_ReadOnlyDictionary()
1601+
{
1602+
var dict = new Dictionary<string, int>();
1603+
dict["Foo"] = 1;
1604+
dict["Bar"] = 2;
1605+
ReadOnlyDictionary<string, int> value = new ReadOnlyDictionary<string, int>(dict);
1606+
var deserializedValue = SerializeAndDeserialize(value, @"{""_dictionary"":[{""Key"":""Foo"",""Value"":1},{""Key"":""Bar"",""Value"":2}]}");
1607+
1608+
Assert.StrictEqual(value.Count, deserializedValue.Count);
1609+
Assert.StrictEqual(value["Foo"], deserializedValue["Foo"]);
1610+
Assert.StrictEqual(value["Bar"], deserializedValue["Bar"]);
1611+
}
1612+
15991613
[Fact]
16001614
public static void DCJS_KeyValuePair()
16011615
{

src/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,20 @@ public static void DCS_ReadOnlyCollection()
17401740
Assert.StrictEqual(value[1], deserializedValue[1]);
17411741
}
17421742

1743+
[Fact]
1744+
public static void DCS_ReadOnlyDictionary()
1745+
{
1746+
var dict = new Dictionary<string, int>();
1747+
dict["Foo"] = 1;
1748+
dict["Bar"] = 2;
1749+
ReadOnlyDictionary<string, int> value = new ReadOnlyDictionary<string, int>(dict);
1750+
var deserializedValue = SerializeAndDeserialize(value, @"<ReadOnlyDictionaryOfstringint xmlns=""http://schemas.datacontract.org/2004/07/System.Collections.ObjectModel"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><_dictionary xmlns:a=""http://schemas.microsoft.com/2003/10/Serialization/Arrays""><a:KeyValueOfstringint><a:Key>Foo</a:Key><a:Value>1</a:Value></a:KeyValueOfstringint><a:KeyValueOfstringint><a:Key>Bar</a:Key><a:Value>2</a:Value></a:KeyValueOfstringint></_dictionary></ReadOnlyDictionaryOfstringint>");
1751+
1752+
Assert.StrictEqual(value.Count, deserializedValue.Count);
1753+
Assert.StrictEqual(value["Foo"], deserializedValue["Foo"]);
1754+
Assert.StrictEqual(value["Bar"], deserializedValue["Bar"]);
1755+
}
1756+
17431757
[Fact]
17441758
public static void DCS_KeyValuePair()
17451759
{

0 commit comments

Comments
 (0)