Skip to content

Commit

Permalink
Merge f3e47da into 6fab847
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike-E-angelo committed Jul 21, 2020
2 parents 6fab847 + f3e47da commit 31d4f25
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using ExtendedXmlSerializer.ContentModel;
using ExtendedXmlSerializer.ContentModel.Content;
using ExtendedXmlSerializer.ContentModel.Format;
using ExtendedXmlSerializer.ContentModel.Properties;
using ExtendedXmlSerializer.ContentModel.Reflection;
using System.Reflection;
using System.Xml;
Expand Down Expand Up @@ -29,7 +30,8 @@ public ReferenceReader(IReader reader, IReferenceMaps maps, IEntities entities,

ReferenceIdentity? GetReference(IFormatReader parameter)
{
if (parameter.Get().To<XmlReader>().NodeType != XmlNodeType.Attribute || MemberProperty.Default.Get(parameter))
if (parameter.Get().To<XmlReader>().NodeType != XmlNodeType.Attribute ||
MemberProperty.Default.Get(parameter))
{
var identity = ReferenceIdentity.Get(parameter);
if (identity.HasValue)
Expand All @@ -50,17 +52,49 @@ public ReferenceReader(IReader reader, IReferenceMaps maps, IEntities entities,

public override object Get(IFormatReader parameter)
{
var identity = GetReference(parameter);
if (identity != null)
var reference = GetReference(parameter);
if (reference != null)
{
var result = _maps.Get(parameter).Get(identity.Value);
var result = _maps.Get(parameter).Get(reference.Value);
return result;
}

{
var result = base.Get(parameter);
var element = parameter.Get().To<XmlReader>().NodeType != XmlNodeType.Attribute ||
MemberProperty.Default.Get(parameter);
var declared = element ? Identity(parameter) : null;
var result = base.Get(parameter);
var identity = declared ?? (element && result != null ? Entity(parameter, result) : null);
if (identity != null)
{
var map = _maps.Get(parameter);
if (map.Get(identity.Value) != result)
{
map.Assign(identity.Value, result);
}
}

return result;
}
}

static ReferenceIdentity? Identity(IFormatReader reader)
{
var identity = IdentityProperty.Default.Get(reader);
var result = identity.HasValue ? new ReferenceIdentity(identity.Value) : (ReferenceIdentity?)null;
return result;
}

ReferenceIdentity? Entity(IFormatReader reader, object instance)
{
var typeInfo = instance.GetType()
.GetTypeInfo();
var entity = _entities.Get(typeInfo)
?.Get(reader);
var result = entity != null
? (ReferenceIdentity?)new ReferenceIdentity(typeInfo, entity)
: null;
return result;
}
}
}
24 changes: 19 additions & 5 deletions src/ExtendedXmlSerializer/ReflectionModel/DefaultActivators.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using ExtendedXmlSerializer.Core.Sources;
using ExtendedXmlSerializer.Core.Specifications;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -13,11 +14,16 @@ sealed class DefaultActivators : ReferenceCacheBase<Type, IActivator>, IActivato

public static DefaultActivators Default { get; } = new DefaultActivators();

DefaultActivators() : this(ConstructorLocator.Default) {}
DefaultActivators() : this(ConstructorLocator.Default, IsCollectionType.Instance) {}

readonly IConstructorLocator _locator;
readonly IConstructorLocator _locator;
readonly ISpecification<TypeInfo> _collection;

public DefaultActivators(IConstructorLocator locator) => _locator = locator;
public DefaultActivators(IConstructorLocator locator, ISpecification<TypeInfo> collection)
{
_locator = locator;
_collection = collection;
}

protected override IActivator Create(Type parameter)
{
Expand All @@ -35,10 +41,10 @@ protected override IActivator Create(Type parameter)

NewExpression Reference(Type parameter, TypeInfo typeInfo)
{
var accounted = typeInfo.IsInterface && IsCollectionTypeSpecification.Default.IsSatisfiedBy(parameter)
var accounted = typeInfo.IsInterface && _collection.IsSatisfiedBy(parameter)
? typeof(List<>).MakeGenericType(CollectionItemTypeLocator.Default.Get(typeInfo))
: typeInfo;
var constructor = _locator.Get(accounted);
var constructor = _locator.Get(accounted) ?? _locator.Get(typeInfo);
var parameters = constructor.GetParameters();
var result = parameters.Length > 0
? Expression.New(constructor, parameters.Select(Selector))
Expand All @@ -63,5 +69,13 @@ public Expression Get(ParameterInfo parameter)
Initializers)
: Expression.Default(parameter.ParameterType);
}

sealed class IsCollectionType : AnySpecification<TypeInfo>
{
public static IsCollectionType Instance { get; } = new IsCollectionType();

IsCollectionType() : base(IsCollectionTypeSpecification.Default,
new IsAssignableGenericSpecification(typeof(IReadOnlyCollection<>))) {}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ sealed class IsCollectionTypeSpecification : AnySpecification<TypeInfo>
public static IsCollectionTypeSpecification Default { get; } = new IsCollectionTypeSpecification();

IsCollectionTypeSpecification()
: base(IsAssignableSpecification<IList>.Default, new IsAssignableGenericSpecification(typeof(ICollection<>))
) {}
: base(IsAssignableSpecification<IList>.Default,
new IsAssignableGenericSpecification(typeof(ICollection<>))) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using ExtendedXmlSerializer.Configuration;
using ExtendedXmlSerializer.Tests.ReportedIssues.Support;
using FluentAssertions;
using JetBrains.Annotations;
using Xunit;

namespace ExtendedXmlSerializer.Tests.ReportedIssues
{
public sealed class Issue358Tests_Extended
{
[Fact]
public void Verify()
{
var serializer = new ConfigurationContainer().EnableParameterizedContentWithPropertyAssignments()
.EnableReferences()
.Create()
.ForTesting();

var length = new length(11);
var instance = new vector(length, length);

var cycled = serializer.Cycle(instance);
cycled.L1.Should().BeSameAs(cycled.L2);
}

class length
{
public length(int value)
{
Value = value;
}

public int Value { [UsedImplicitly] get; }
}

class vector
{
public vector(length l1, length l2)
{
L1 = l1;
L2 = l2;
}

public length L1 { get; }
public length L2 { get; }
}
}
}
73 changes: 73 additions & 0 deletions test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue396Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using ExtendedXmlSerializer.Configuration;
using ExtendedXmlSerializer.Tests.ReportedIssues.Support;
using FluentAssertions;
using System;
using System.Collections.Generic;
using Xunit;

namespace ExtendedXmlSerializer.Tests.ReportedIssues
{
public sealed class Issue396Tests
{
[Fact]
public void NodesListIsMissingNodes()
{
var serializer = new ConfigurationContainer().UseOptimizedNamespaces()
.EnableParameterizedContentWithPropertyAssignments()
.UseAutoFormatting()
.Type<Node>()
.EnableReferences()
.Create()
.ForTesting();
var node1 = new Node(1);
var node2 = new Node(2).AddNode(node1, isBidirectional: true);
var node3 = new Node(3).AddNode(node2, isBidirectional: false);
node1.AddNode(node3, isBidirectional: false);
var nodesList = new List<Node> { node1, node2, node3 };



var cycled = serializer.Cycle(nodesList);
cycled.Should().BeEquivalentTo(nodesList, config => config.IgnoringCyclicReferences());
}

public sealed class Node : IEquatable<Node>
{
private readonly List<Node> _linkedNodes;

public Node(int id) : this(id, new List<Node>()) {}

public Node(int id, List<Node> linkedNodes)
{
Id = id;
_linkedNodes = linkedNodes ?? new List<Node>();
}

public int Id { get; }

public IReadOnlyList<Node> LinkedNodes => _linkedNodes;

// ReSharper disable once FlagArgument
public Node AddNode(Node otherNode, bool isBidirectional = true)
{
if (otherNode == null)
throw new ArgumentNullException(nameof(otherNode));
if (ReferenceEquals(this, otherNode))
throw new ArgumentException($"You cannot link a node {Id} to itself.");

_linkedNodes.Add(otherNode);
if (isBidirectional)
otherNode.AddNode(this, false);
return this;
}

public bool Equals(Node other) => !ReferenceEquals(null, other) && Id == other.Id;

public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is Node other && Equals(other);

public override int GetHashCode() => Id;

public override string ToString() => "Node " + Id;
}
}
}
60 changes: 60 additions & 0 deletions test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue418Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using ExtendedXmlSerializer.Configuration;
using ExtendedXmlSerializer.Tests.ReportedIssues.Support;
using FluentAssertions;
using System.Collections.Generic;
using System.Linq;
using Xunit;

namespace ExtendedXmlSerializer.Tests.ReportedIssues
{
public sealed class Issue418Tests
{
[Fact]
public void Verify()
{
var b1 = new Book();
var b2 = new Book();

var allBooks = new[] {b1, b2,};

var fs = new BookStore()
{
AllBooks = allBooks,
Genres = new[]
{
new Genre
{
Books = allBooks,
},
new Genre
{
Books = allBooks,
},
}
};

var serializer = new ConfigurationContainer().Type<Book[]>()
.EnableReferences()
.Create()
.ForTesting();

var cycled = serializer.Cycle(fs);

cycled.AllBooks.Should().BeSameAs(cycled.Genres.ElementAt(0).Books);
cycled.AllBooks.Should().BeSameAs(cycled.Genres.ElementAt(1).Books);
}

class BookStore
{
public IEnumerable<Book> AllBooks { get; set; }
public IEnumerable<Genre> Genres { get; set; }
}

class Book {}

class Genre
{
public IEnumerable<Book> Books { get; set; }
}
}
}

0 comments on commit 31d4f25

Please sign in to comment.