Skip to content

Commit

Permalink
1) Adding support for excluding [NonSerialized] members from serializ…
Browse files Browse the repository at this point in the history
…ation, this is prerequisite for dotnet#2.

2) Adding support for ReadOnlyDictionary.
  • Loading branch information
SGuyGe committed Feb 16, 2016
1 parent e38e54f commit c560f98
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
Expand Down Expand Up @@ -149,6 +149,7 @@
<Compile Include="$(JsonSources)\ByteArrayHelperWithString.cs" />
<Compile Include="$(JsonSources)\JsonEncodingStreamWrapper.cs" />
<Compile Include="$(JsonSources)\JsonFormatGeneratorStatics.cs" Condition="!$(NetNative)" />
<Compile Include="System\Runtime\Serialization\SerializableInfo.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netcore50aot'">
<TargetingPackReference Include="System.Private.CoreLib.Augments" />
Expand All @@ -158,4 +159,4 @@
<None Include="project.json" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -439,16 +439,12 @@ static internal bool IsNonAttributedTypeValidForSerialization(Type type)
}
}

private static string[] s_knownSerializableTypeNames = new string[] {
"System.Collections.Queue",
"System.Collections.Stack",
"System.Globalization.CultureInfo",
"System.Version",
private static string[] s_knownSerializableGenericTypeNames = new string[] {
"System.Collections.Generic.KeyValuePair`2",
"System.Collections.Generic.Queue`1",
"System.Collections.Generic.Stack`1",
"System.Collections.ObjectModel.ReadOnlyCollection`1",
"System.Collections.ObjectModel.ReadOnlyDictionary`2",
"System.Collections.Generic.Queue`1;_syncRoot",
"System.Collections.Generic.Stack`1;_syncRoot",
"System.Collections.ObjectModel.ReadOnlyCollection`1;_syncRoot",
"System.Collections.ObjectModel.ReadOnlyDictionary`2;_syncRoot,_keys,_values",
"System.Tuple`1",
"System.Tuple`2",
"System.Tuple`3",
Expand All @@ -459,26 +455,106 @@ static internal bool IsNonAttributedTypeValidForSerialization(Type type)
"System.Tuple`8",
};

private static string[] s_knownSerializableNonGenericTypeNames = new string[] {
"System.Collections.Queue;_syncRoot",
"System.Collections.Stack;_syncRoot",
"System.Globalization.CultureInfo",
"System.Version",
};

private static object s_knownSerializableGenericTypeInfosLock = new object();
private static volatile IDictionary<string, SerializableInfo> s_knownSerializableGenericTypeInfos;
private static IDictionary<string, SerializableInfo> KnownSerializableGenericTypes
{
get
{
if (s_knownSerializableGenericTypeInfos == null)
{
lock (s_knownSerializableGenericTypeInfosLock)
{
if (s_knownSerializableGenericTypeInfos == null)
{
s_knownSerializableGenericTypeInfos = new Dictionary<string, SerializableInfo>();
InitializeKnownSerializableTypesFromStringList(s_knownSerializableGenericTypeNames, s_knownSerializableGenericTypeInfos);
}
}
}
return s_knownSerializableGenericTypeInfos;
}
}

private static object s_knownSerializableNonGenericTypeInfosLock = new object();
private static volatile IDictionary<string, SerializableInfo> s_knownSerializableNonGenericTypeInfos;
private static IDictionary<string, SerializableInfo> KnownSerializableNonGenericTypes
{
get
{
if (s_knownSerializableNonGenericTypeInfos == null)
{
lock (s_knownSerializableNonGenericTypeInfosLock)
{
if (s_knownSerializableNonGenericTypeInfos == null)
{
s_knownSerializableNonGenericTypeInfos = new Dictionary<string, SerializableInfo>();
InitializeKnownSerializableTypesFromStringList(s_knownSerializableNonGenericTypeNames, s_knownSerializableNonGenericTypeInfos);
}
}
}
return s_knownSerializableNonGenericTypeInfos;
}
}

private static void InitializeKnownSerializableTypesFromStringList(string[] listOfTypes, IDictionary<string, SerializableInfo> dict)
{
Debug.Assert(listOfTypes != null);
Debug.Assert(dict != null);
foreach (string str in listOfTypes)
{
SerializableInfo si = SerializableInfo.Parse(str);
dict.Add(si.TypeName, si);
}
}

internal static bool IsKnownSerializableType(Type type)
{
// Applies to known types that DCS understands how to serialize/deserialize
//

// Ajdust for generic type
if (type.GetTypeInfo().IsGenericType && !type.GetTypeInfo().IsGenericTypeDefinition)
if (type.GetTypeInfo().IsGenericType)
{
type = type.GetGenericTypeDefinition();
if (!type.GetTypeInfo().IsGenericTypeDefinition)
{
type = type.GetTypeInfo().GetGenericTypeDefinition();
}
return Enumerable.Contains(KnownSerializableGenericTypes.Keys, type.FullName);
}

// Check for known types
if (Enumerable.Contains(s_knownSerializableTypeNames, type.FullName))
else if (Enumerable.Contains(KnownSerializableNonGenericTypes.Keys, type.FullName))
{
return true;
}
//Enable ClassDataContract to give support to Exceptions.
if (Globals.TypeOfException.IsAssignableFrom(type))
else if (Globals.TypeOfException.IsAssignableFrom(type))
{
//Enable ClassDataContract to give support to Exceptions.
return true;
}

return false;
}

internal static bool IsNonSerializedMember(Type type, string memberName)
{
if (type.GetTypeInfo().IsGenericType)
{
Type genericTypeDef = type.GetTypeInfo().IsGenericTypeDefinition ? type : type.GetTypeInfo().GetGenericTypeDefinition();
if (KnownSerializableGenericTypes.Keys.Contains(genericTypeDef.FullName))
{
return Enumerable.Contains(KnownSerializableGenericTypes[genericTypeDef.FullName].NonSerializedMembers, memberName);
}
}
else if (KnownSerializableNonGenericTypes.Keys.Contains(type.FullName))
{
return Enumerable.Contains(KnownSerializableNonGenericTypes[type.FullName].NonSerializedMembers, memberName);
}
return false;
}

Expand Down Expand Up @@ -1073,8 +1149,7 @@ private void ImportDataMembers()

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

private bool SetIfGetOnlyCollection(DataMember memberContract)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime.Serialization
{
using System;
using System.Diagnostics;

public class SerializableInfo
{
public string TypeName { get; set; }
public string[] NonSerializedMembers { get; set; }

private SerializableInfo(string typeName, string[] nonSerializedMembers)
{
Debug.Assert(!string.IsNullOrEmpty(typeName));
Debug.Assert(nonSerializedMembers != null);
TypeName = typeName;
NonSerializedMembers = nonSerializedMembers;
}

public static SerializableInfo Parse(string str)
{
if (string.IsNullOrEmpty(str))
{
throw new ArgumentNullException("str");
}
string[] parts = str.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0)
{
throw new ArgumentException("str");
}
string typeName = parts[0];
string[] nonSerializedMembers = new string[0];
if (parts.Length == 2)
{
nonSerializedMembers = parts[1].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
SerializableInfo si = new SerializableInfo(typeName, nonSerializedMembers);
return si;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,20 @@ public static void DCJS_ReadOnlyCollection()
Assert.StrictEqual(value[1], deserializedValue[1]);
}

[Fact]
public static void DCJS_ReadOnlyDictionary()
{
var dict = new Dictionary<string, int>();
dict["Foo"] = 1;
dict["Bar"] = 2;
ReadOnlyDictionary<string, int> value = new ReadOnlyDictionary<string, int>(dict);
var deserializedValue = SerializeAndDeserialize(value, @"{""_dictionary"":[{""Key"":""Foo"",""Value"":1},{""Key"":""Bar"",""Value"":2}]}");

Assert.StrictEqual(value.Count, deserializedValue.Count);
Assert.StrictEqual(value["Foo"], deserializedValue["Foo"]);
Assert.StrictEqual(value["Bar"], deserializedValue["Bar"]);
}

[Fact]
public static void DCJS_KeyValuePair()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,20 @@ public static void DCS_ReadOnlyCollection()
Assert.StrictEqual(value[1], deserializedValue[1]);
}

[Fact]
public static void DCS_ReadOnlyDictionary()
{
var dict = new Dictionary<string, int>();
dict["Foo"] = 1;
dict["Bar"] = 2;
ReadOnlyDictionary<string, int> value = new ReadOnlyDictionary<string, int>(dict);
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>");

Assert.StrictEqual(value.Count, deserializedValue.Count);
Assert.StrictEqual(value["Foo"], deserializedValue["Foo"]);
Assert.StrictEqual(value["Bar"], deserializedValue["Bar"]);
}

[Fact]
public static void DCS_KeyValuePair()
{
Expand Down

0 comments on commit c560f98

Please sign in to comment.