Skip to content

Commit

Permalink
Merge pull request #160 from akkadotnet/dev
Browse files Browse the repository at this point in the history
v0.9.13 Release
  • Loading branch information
Aaronontheweb authored Feb 10, 2020
2 parents 2cf4598 + f24687b commit 457a5e7
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 21 deletions.
5 changes: 2 additions & 3 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
### 0.9.12 January 20 2020 ####
### 0.9.13 February 09 2020 ####

* Added version tolerance during deserialization.
* Added `ArrayList` and non-generic `IEnumerable` support.
* [Added support for serializing and deserializing `IDictionary<TKey, TValue>`](https://github.com/akkadotnet/Hyperion/pull/156)
135 changes: 135 additions & 0 deletions src/Hyperion.Tests/GenericDictionarySerializerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using System;
using System.Collections;
using System.Collections.Generic;
using FluentAssertions;
using Xunit;

namespace Hyperion.Tests
{
public class GenericDictionarySerializerTests : TestBase
{
[Fact]
public void CanSerializeDictionary()
{
var customDict = new CustomDictionary<string, int>(new Dictionary<string, int>()
{
["key"] = 1
});
SerializeAndAssertEquivalent(customDict);
}

private void SerializeAndAssertEquivalent<T>(T expected)
{
Serialize(expected);
Reset();
var res = Deserialize<T>();
res.Should().BeEquivalentTo(expected);
AssertMemoryStreamConsumed();
}

/// <summary>
/// Just a custom class wrapper for another <see cref="IDictionary{TKey,TValue}"/>
/// </summary>
class CustomDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly IDictionary<TKey, TValue> _dictGeneric;

/// <summary>
/// For serialization
/// </summary>
public CustomDictionary() : this(new Dictionary<TKey, TValue>())
{
}

public CustomDictionary(Dictionary<TKey, TValue> dict)
{
_dictGeneric = dict;
}

/// <inheritdoc />
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dictGeneric.GetEnumerator();
}

/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable) _dictGeneric).GetEnumerator();
}

/// <inheritdoc />
public void Add(KeyValuePair<TKey, TValue> item)
{
_dictGeneric.Add(item);
}

/// <inheritdoc />
public void Clear()
{
_dictGeneric.Clear();
}

/// <inheritdoc />
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _dictGeneric.Contains(item);
}

/// <inheritdoc />
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_dictGeneric.CopyTo(array, arrayIndex);
}

/// <inheritdoc />
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return _dictGeneric.Remove(item);
}

/// <inheritdoc />
public int Count => _dictGeneric.Count;

/// <inheritdoc />
public bool IsReadOnly => _dictGeneric.IsReadOnly;

/// <inheritdoc />
public void Add(TKey key, TValue value)
{
_dictGeneric.Add(key, value);
}

/// <inheritdoc />
public bool ContainsKey(TKey key)
{
return _dictGeneric.ContainsKey(key);
}

/// <inheritdoc />
public bool Remove(TKey key)
{
return _dictGeneric.Remove(key);
}

/// <inheritdoc />
public bool TryGetValue(TKey key, out TValue value)
{
return _dictGeneric.TryGetValue(key, out value);
}

/// <inheritdoc />
public TValue this[TKey key]
{
get => _dictGeneric[key];
set => _dictGeneric[key] = value;
}

/// <inheritdoc />
public ICollection<TKey> Keys => _dictGeneric.Keys;

/// <inheritdoc />
public ICollection<TValue> Values => _dictGeneric.Values;
}
}
}
55 changes: 41 additions & 14 deletions src/Hyperion/SerializerFactories/DictionarySerializerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,31 @@ public override ValueSerializer BuildSerializer(Serializer serializer, Type type
var preserveObjectReferences = serializer.Options.PreserveObjectReferences;
var ser = new ObjectSerializer(type);
typeMapping.TryAdd(type, ser);
var elementSerializer = serializer.GetSerializerByType(typeof (DictionaryEntry));
var dictionaryTypes = GetKeyValuePairType(type);
var elementSerializer = serializer.GetSerializerByType(dictionaryTypes.KeyValuePairType);

ObjectReader reader = (stream, session) =>
{
throw new NotSupportedException("Generic IDictionary<TKey,TValue> are not yet supported");
#pragma warning disable CS0162 // Unreachable code detected
var instance = Activator.CreateInstance(type);
#pragma warning restore CS0162 // Unreachable code detected
var instance = Activator.CreateInstance(type); // IDictionary<TKey, TValue>
if (preserveObjectReferences)
{
session.TrackDeserializedObject(instance);
}
var count = stream.ReadInt32(session);
var entries = new DictionaryEntry[count];
for (var i = 0; i < count; i++)
{
var entry = (DictionaryEntry) stream.ReadObject(session);
entries[i] = entry;
var entry = stream.ReadObject(session); // KeyValuePair<TKey, TValue>

// Get entry.Key and entry.Value
var key = dictionaryTypes.KeyValuePairType.GetProperty(nameof(KeyValuePair<object, object>.Key)).GetValue(entry, null);
var value = dictionaryTypes.KeyValuePairType.GetProperty(nameof(KeyValuePair<object, object>.Value)).GetValue(entry, null);

// Same as: instance.Add(key, value)
dictionaryTypes.DictionaryInterfaceType
.GetMethod(nameof(IDictionary<object, object>.Add), new []{ dictionaryTypes.KeyType, dictionaryTypes.ValueType })
.Invoke(instance, new [] { key, value });
}
//TODO: populate dictionary

return instance;
};

Expand All @@ -68,19 +73,41 @@ public override ValueSerializer BuildSerializer(Serializer serializer, Type type
{
session.TrackSerializedObject(obj);
}
var dict = obj as IDictionary;

var dict = obj as IEnumerable; // IDictionary<T, V> is IEnumerable<KeyValuePair<T, V>>
var count = dict.Cast<object>().Count();
// ReSharper disable once PossibleNullReferenceException
Int32Serializer.WriteValueImpl(stream,dict.Count,session);
Int32Serializer.WriteValueImpl(stream, count, session);
foreach (var item in dict)
{
stream.WriteObject(item, typeof (DictionaryEntry), elementSerializer,
serializer.Options.PreserveObjectReferences, session);
// elementSerializer.WriteValue(stream,item,session);
stream.WriteObject(item, dictionaryTypes.KeyValuePairType, elementSerializer, serializer.Options.PreserveObjectReferences, session);
}
};
ser.Initialize(reader, writer);

return ser;
}

private GenericDictionaryTypes GetKeyValuePairType(Type dictImplementationType)
{
var dictInterface = dictImplementationType.GetInterfaces().First(i => i.GetGenericTypeDefinition() == typeof (IDictionary<,>));
var keyType = dictInterface.GetGenericArguments()[0];
var valueType = dictInterface.GetGenericArguments()[1];
return new GenericDictionaryTypes()
{
KeyType = keyType,
ValueType = valueType,
KeyValuePairType = typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType),
DictionaryInterfaceType = typeof(IDictionary<,>).MakeGenericType(keyType, valueType)
};
}

class GenericDictionaryTypes
{
public Type KeyType { get; set; }
public Type ValueType { get; set; }
public Type KeyValuePairType { get; set; }
public Type DictionaryInterfaceType { get; set; }
}
}
}
7 changes: 3 additions & 4 deletions src/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
<PropertyGroup>
<Copyright>Copyright © 2016-2017 Akka.NET Team</Copyright>
<Authors>Akka.NET Team</Authors>
<VersionPrefix>0.9.12</VersionPrefix>
<PackageReleaseNotes>Added version tolerance during deserialization.
Added `ArrayList` and non-generic `IEnumerable` support.</PackageReleaseNotes>
<VersionPrefix>0.9.13</VersionPrefix>
<PackageReleaseNotes>[Added support for serializing and deserializing `IDictionary&lt;TKey, TValue&gt;`](https://github.com/akkadotnet/Hyperion/pull/156)</PackageReleaseNotes>
<PackageIconUrl>http://getakka.net/images/akkalogo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/akkadotnet/Hyperion</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/akkadotnet/Hyperion/blob/master/LICENSE</PackageLicenseUrl>
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<XunitVersion>2.4.1</XunitVersion>
<TestSdkVersion>16.4.0</TestSdkVersion>
<TestSdkVersion>16.5.0</TestSdkVersion>
<NBenchVersion>1.2.2</NBenchVersion>
</PropertyGroup>
</Project>

0 comments on commit 457a5e7

Please sign in to comment.