From 087c5b983bbec413840e0b76ef295ff8e88e4a5c Mon Sep 17 00:00:00 2001 From: Mike-E <2931376+Mike-E-angelo@users.noreply.github.com> Date: Mon, 7 Dec 2020 16:08:16 -0500 Subject: [PATCH 1/5] Fixed list support in `WithUnknownContent` (#487) --- .../UnknownContentHandlingExtension.cs | 33 +++++++-- .../Issue473Tests.cs | 68 +++++++++++++++++++ 2 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue473Tests.cs diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs index 0793b14bd..95a254ba9 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs @@ -1,11 +1,12 @@ -using System; -using System.Reflection; -using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel; using ExtendedXmlSerializer.ContentModel.Collections; using ExtendedXmlSerializer.ContentModel.Content; using ExtendedXmlSerializer.ContentModel.Format; using ExtendedXmlSerializer.ContentModel.Members; +using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.Core; +using System; +using System.Reflection; namespace ExtendedXmlSerializer.ExtensionModel.Content { @@ -24,15 +25,33 @@ void ICommand.Execute(IServices parameter) {} sealed class Services : IInnerContentServices { readonly IInnerContentServices _services; + readonly IClassification _classification; readonly Action _missing; - public Services(IInnerContentServices services, Action missing) + public Services(IInnerContentServices services, IClassification classification, + Action missing) { - _services = services; - _missing = missing; + _services = services; + _classification = classification; + _missing = missing; } - public bool IsSatisfiedBy(IInnerContent parameter) => _services.IsSatisfiedBy(parameter); + public bool IsSatisfiedBy(IInnerContent parameter) + { + var previous = _services.IsSatisfiedBy(parameter); + if (previous) + { + var reader = parameter.Get(); + var type = _classification.Get(reader); + if (type == null) + { + _missing(reader); + return false; + } + } + + return previous; + } public void Handle(IInnerContent contents, IMemberSerializer member) { diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue473Tests.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue473Tests.cs new file mode 100644 index 000000000..f6ac6e81e --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue473Tests.cs @@ -0,0 +1,68 @@ +using ExtendedXmlSerializer.Configuration; +using FluentAssertions; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using Xunit; + +namespace ExtendedXmlSerializer.Tests.ReportedIssues +{ + public sealed class Issue473Tests + { + [Fact] + public void Verify() + { + // language=XML + const string input = + @""; + + var serializer = new ConfigurationContainer().Type() + .Name("Zoo") + .EnableImplicitTyping(typeof(Zoo), typeof(Animal)) + .WithUnknownContent() + .Continue() + .Create(); + + var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(input)); + var reader = XmlReader.Create(contentStream); + var deserialized = (Zoo)serializer.Deserialize(reader); + + deserialized.Animals.Count.Should().Be(2); + + var expected = new Zoo + { Animals = new List { new Animal { Name = "Hello" }, new Animal { Name = "World" } } }; + deserialized.Should().BeEquivalentTo(expected); + } + + [Fact] + public void VerifyThrow() + { + // language=XML + const string input = + @""; + + var serializer = new ConfigurationContainer().Type() + .Name("Zoo") + .EnableImplicitTyping(typeof(Zoo), typeof(Animal)) + .WithUnknownContent() + .Throw() + .Create(); + + serializer.Invoking(x => x.Deserialize(input)) + .Should() + .Throw() + .WithMessage("Unknown/invalid member encountered: 'Human'. Line 1, position 52."); + } + + public class Zoo + { + public List Animals { get; set; } + } + + public class Animal + { + public string Name { get; set; } + } + } +} \ No newline at end of file From 5e5c10c6df2e7abf1607b0e8467793e2b7ef9644 Mon Sep 17 00:00:00 2001 From: Mike-E <2931376+Mike-E-angelo@users.noreply.github.com> Date: Mon, 7 Dec 2020 16:08:39 -0500 Subject: [PATCH 2/5] Added non-generic equivalent for `AddMigration` (#484) --- .../ExtensionMethodsForXml.cs | 37 ++++++++ .../ExtensionModel/Xml/MigrationsExtension.cs | 2 - .../Issue483Tests.cs | 93 +++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue483Tests.cs diff --git a/src/ExtendedXmlSerializer/ExtensionMethodsForXml.cs b/src/ExtendedXmlSerializer/ExtensionMethodsForXml.cs index e302009d6..81447ff1f 100644 --- a/src/ExtendedXmlSerializer/ExtensionMethodsForXml.cs +++ b/src/ExtendedXmlSerializer/ExtensionMethodsForXml.cs @@ -273,6 +273,43 @@ public static ITypeConfiguration AddMigration(this ITypeConfiguration @ .Apply(@this.Get(), migrations.Fixed()) .Return(@this); + /// + /// Adds a migration command to the configured type. A migration allows older persisted XML to migrate to an object + /// model schema that has changed since the XML was persisted. The provided command specifies how to manipulate the + /// element that represents the type so that it can (hopefully 😇) be deserialized without error. + /// + /// The type configuration to configure. + /// The command that specifies how to migrate an Xml element that represents an older schema. + /// The configured type configuration. + public static ITypeConfiguration AddMigration(this ITypeConfiguration @this, ICommand migration) + => @this.AddMigration(migration.Execute); + + /// + /// Adds a migration delegate to the configured type. A migration allows older persisted XML to migrate to an object + /// model schema that has changed since the XML was persisted. The provided command specifies how to manipulate the + /// element that represents the type so that it can (hopefully 😇) be deserialized without error. + /// + /// The type configuration to configure. + /// The delegate that specifies how to migrate an Xml element that represents an older schema. + /// + /// The configured type configuration. + public static ITypeConfiguration AddMigration(this ITypeConfiguration @this, Action migration) + => @this.AddMigration(migration.Yield()); + + /// + /// Adds a set of migration delegates to the configured type. A migration allows older persisted XML to migrate to an + /// object model schema that has changed since the XML was persisted. The provided command specifies how to + /// manipulate the element that represents the type so that it can (hopefully 😇) be deserialized without error. + /// + /// The type configuration to configure. + /// The delegates that specify how to migrate an Xml element that represents an older schema. + /// + /// The configured type configuration. + public static ITypeConfiguration AddMigration(this ITypeConfiguration @this, IEnumerable> migrations) + => @this.Root.With() + .Apply(@this.Get(), migrations.Fixed()) + .Return(@this); + #endregion } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Xml/MigrationsExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Xml/MigrationsExtension.cs index 48bbdfc0e..829f8e46e 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Xml/MigrationsExtension.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Xml/MigrationsExtension.cs @@ -6,7 +6,6 @@ using ExtendedXmlSerializer.Core; using ExtendedXmlSerializer.Core.Sources; using ExtendedXmlSerializer.ReflectionModel; -using JetBrains.Annotations; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -21,7 +20,6 @@ namespace ExtendedXmlSerializer.ExtensionModel.Xml { sealed class MigrationsExtension : TypedTable>>, ISerializerExtension { - [UsedImplicitly] public MigrationsExtension() : this(new Dictionary>>()) {} public MigrationsExtension(IDictionary>> store) : base(store) {} diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue483Tests.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue483Tests.cs new file mode 100644 index 000000000..4ab55237e --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue483Tests.cs @@ -0,0 +1,93 @@ +using ExtendedXmlSerializer.Configuration; +using FluentAssertions; +using System.Linq; +using Xunit; + +namespace ExtendedXmlSerializer.Tests.ReportedIssues +{ + public sealed class Issue483Tests + { + [Fact] + public void Verify() + { + //// Write legacy XML + //var rootInitialVersion = new Root { Identifier = Guid.NewGuid() }; + //var someClass1 = new SomeClass { Id = 1, SomeString = "String1" }; + //var someClass2 = new SomeClass { Id = 2, SomeString = "String2" }; + //var children = new List(); + //for (var i = 1; i < 10; i++) + // children.Add(new Node + // { + // Id = i, + // Blubb = i % 2 == 0 ? someClass1 : someClass2 + // }); + //rootInitialVersion.Children = children; + + //var serializer = new ConfigurationContainer() + // .ConfigureType() + // .EnableReferences(s => s.Id) + // .Create(); + //var initialXml = serializer.Serialize(new XmlWriterSettings { Indent = true }, rootInitialVersion); + + var initialXml = @" + + 391047bb-21a7-46cb-b49c-6b9353305d09 + + 16 + + 1 + + String2 + + + + 2 + + String1 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + "; + + new ConfigurationContainer().Type() + .EnableReferences(s => s.Id) + .As() + .AddMigration(new SomeClassMigrations()) + .Create() + .Deserialize(initialXml) + .Children + .Select(x => x.Blubb.RenamedProperty) + .Take(4) + .Should() + .Equal("String2", "String1", "String2", "String1"); + } + } +} \ No newline at end of file From 90345c7e53fbe117ee4187ac8c840fe393e405f8 Mon Sep 17 00:00:00 2001 From: Mike-E <2931376+Mike-E-angelo@users.noreply.github.com> Date: Mon, 7 Dec 2020 16:08:59 -0500 Subject: [PATCH 3/5] Applied serializer type check using `WithUnknownContent` (#492) --- .../FixedInstanceMemberSerialization.cs | 3 + .../Members/IInstanceMemberSerialization.cs | 4 +- .../Members/InstanceMemberSerialization.cs | 4 ++ .../Members/MemberInnerContentHandler.cs | 20 +++--- .../UnknownContentHandlingExtension.cs | 45 ++++++++++++- .../Issue491Tests.cs | 64 +++++++++++++++++++ 6 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue491Tests.cs diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/FixedInstanceMemberSerialization.cs b/src/ExtendedXmlSerializer/ContentModel/Members/FixedInstanceMemberSerialization.cs index a83b2454e..3cb99435b 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Members/FixedInstanceMemberSerialization.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Members/FixedInstanceMemberSerialization.cs @@ -1,3 +1,4 @@ +using ExtendedXmlSerializer.ContentModel.Content; using ExtendedXmlSerializer.Core.Sources; namespace ExtendedXmlSerializer.ContentModel.Members @@ -6,5 +7,7 @@ sealed class FixedInstanceMemberSerialization : FixedInstanceSource, IInstanceMemberSerialization { public FixedInstanceMemberSerialization(IMemberSerialization instance) : base(instance) {} + + public IMemberSerialization Get(IInnerContent parameter) => Get(parameter.Current); } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/IInstanceMemberSerialization.cs b/src/ExtendedXmlSerializer/ContentModel/Members/IInstanceMemberSerialization.cs index 5a80a79cb..bfb041b25 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Members/IInstanceMemberSerialization.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Members/IInstanceMemberSerialization.cs @@ -1,6 +1,8 @@ +using ExtendedXmlSerializer.ContentModel.Content; using ExtendedXmlSerializer.Core.Sources; namespace ExtendedXmlSerializer.ContentModel.Members { - interface IInstanceMemberSerialization : IParameterizedSource {} + interface IInstanceMemberSerialization : IParameterizedSource, + IParameterizedSource {} } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs b/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs index 5e085791d..d5884d61e 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Members/InstanceMemberSerialization.cs @@ -1,3 +1,4 @@ +using ExtendedXmlSerializer.ContentModel.Content; using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.Core.Specifications; using ExtendedXmlSerializer.ExtensionModel.Types; @@ -22,11 +23,14 @@ public InstanceMemberSerialization(ISpecification specification, IMemb _serialization = serialization; } + public IMemberSerialization Get(IInnerContent parameter) => Get(parameter.Current); + public IMemberSerialization Get(object parameter) { var type = parameter is ITypeAware aware ? aware.Get() : parameter.GetType().GetTypeInfo(); var result = _specification.IsSatisfiedBy(type) ? _serializations.Get(type) : _serialization; return result; } + } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs b/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs index 038259237..293eac26a 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Members/MemberInnerContentHandler.cs @@ -19,17 +19,21 @@ public MemberInnerContentHandler(IInstanceMemberSerialization serialization, IMe public bool IsSatisfiedBy(IInnerContent parameter) { - var content = parameter.Get(); - var key = _formatter.Get(content); - var memberSerialization = _serialization.Get(parameter.Current); - var member = memberSerialization.Get(key); - var result = member != null; - if (result) + var content = parameter.Get(); + var key = _formatter.Get(content); + var serialization = _serialization.Get(parameter); + if (serialization != null) { - _handler.Handle(parameter, member); + var member = serialization.Get(key); + var result = member != null; + if (result) + { + _handler.Handle(parameter, member); + return true; + } } - return result; + return false; } } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs index 95a254ba9..9f120fe51 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/UnknownContentHandlingExtension.cs @@ -18,10 +18,53 @@ sealed class UnknownContentHandlingExtension : ISerializerExtension public IServiceRepository Get(IServiceRepository parameter) => parameter.RegisterInstance(_action) - .Decorate(); + .Decorate() + .Decorate(); void ICommand.Execute(IServices parameter) {} + sealed class InstanceMemberSerializations : IInstanceMemberSerializations + { + readonly IInstanceMemberSerializations _previous; + readonly IInnerContentServices _services; + + public InstanceMemberSerializations(IInstanceMemberSerializations previous, IInnerContentServices services) + { + _previous = previous; + _services = services; + } + + public IInstanceMemberSerialization Get(TypeInfo parameter) + => new InstanceMemberSerialization(_previous.Get(parameter), _services); + + sealed class InstanceMemberSerialization : IInstanceMemberSerialization + { + readonly IInstanceMemberSerialization _previous; + readonly IInnerContentServices _services; + + public InstanceMemberSerialization(IInstanceMemberSerialization previous, + IInnerContentServices services) + { + _previous = previous; + _services = services; + } + + public IMemberSerialization Get(IInnerContent parameter) + { + var content = parameter.Get(); + var key = _services.Get(content); + var serialization = _previous.Get(parameter); + var serializer = serialization.Get(key); + var result = serializer is PropertyMemberSerializer && !content.IsSatisfiedBy(serializer.Profile) + ? null + : serialization; + return result; + } + + public IMemberSerialization Get(object parameter) => _previous.Get(parameter); + } + } + sealed class Services : IInnerContentServices { readonly IInnerContentServices _services; diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue491Tests.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue491Tests.cs new file mode 100644 index 000000000..d76b8924e --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue491Tests.cs @@ -0,0 +1,64 @@ +using ExtendedXmlSerializer.Configuration; +using FluentAssertions; +using System.Xml.Serialization; +using Xunit; + +namespace ExtendedXmlSerializer.Tests.ReportedIssues +{ + public sealed class Issue491Tests + { + [Fact] + public void Test() + { + var serializer = new ConfigurationContainer().WithUnknownContent().Continue().Create(); + + // Create an object which have its Id as element + var obj2 = new RootObjectIdElement() {Id = 2, Name = "RootObjectId 2"}; + var text2 = serializer.Serialize(obj2); + //_output.WriteLine(text2); + // 2RootObjectId 2 + + // TEST 1: Change object types which allows deserialize type + var bugText1 = text2.Replace("RootObjectIdElement", "RootObjectIdAttribute"); + var bugObj1 = serializer.Deserialize(bugText1); + // RESULT 1: BUG encountered! Name is null although WithUnknownContent().Continue() is enabled + bugObj1.Name.Should().Be("RootObjectId 2"); + bugObj1.Id.Should().Be(0); + + // TEST 2: Set Id as Attribute and parallel as unknown element + var bugText2 = bugText1.Replace("-RootObjectIdAttribute ", @"-RootObjectIdAttribute Id=""1"" "); + var bugObj2 = serializer.Deserialize(bugText2); + // RESULT 2: BUG also exists in case the attribute is set too + bugObj2.Name.Should().Be("RootObjectId 2"); + bugObj2.Id.Should().Be(1); + + + + + // TEST 3: Rename element Id to Id2 - therefore it has not the same name as expected attribute + var bugText3 = bugText1.Replace("", "").Replace("", ""); + var bugObj3 = serializer.Deserialize(bugText3); + // RESULT 3: Works just fine + bugObj3.Name.Should().NotBeNull(); + bugObj3.Id.Should().Be(0); + + // => BUG happens only if an unknown content is determined which has same name as an expected attribute! + } + + public class RootObjectIdAttribute + { + [XmlAttribute] + public int Id { get; set; } + + public string Name { get; set; } + } + + public class RootObjectIdElement + { + public int Id { get; set; } + + public string Name { get; set; } + } + + } +} From f74f8c375c9ce4813cf5f1d6f089a5a38ce1e68c Mon Sep 17 00:00:00 2001 From: Mike-E <2931376+Mike-E-angelo@users.noreply.github.com> Date: Mon, 7 Dec 2020 16:09:19 -0500 Subject: [PATCH 4/5] Added support for `System.Collections.Immutable` Types (#486) --- .../Configuration/EmitBehaviors.cs | 6 +- .../Members/AllowedAssignedInstanceValues.cs | 8 +- .../Reflection/DefaultTypeDefaults.cs | 13 + .../ContentModel/Reflection/TypeDefaults.cs | 17 +- .../Reflection/TypeMemberDefaults.cs | 13 +- .../ExtensionMethodsForExtensionModel.cs | 15 +- .../ExtensionMethodsForSerialization.cs | 2 +- ...ImplicitlyDefinedDefaultValueAlteration.cs | 6 +- .../AllMembersParameterizedActivators.cs | 17 +- .../Members/DefaultValueTypeDefaults.cs | 20 + .../Members/ParameterizedActivators.cs | 16 +- .../Members/ParameterizedAwareTypeDefaults.cs | 31 ++ .../Markup/MarkupExtensionPartsEvaluator.cs | 19 +- .../ExtensionModel/Markup/MarkupExtensions.cs | 11 +- .../Types/ActivationContexts.cs | 27 +- .../ExtensionModel/Types/Activators.cs | 7 +- .../ExtensionModel/Types/IActivationAware.cs | 9 + .../Types/ImmutableDictionariesExtension.cs | 112 +++++ .../Types/ImmutableHashSetExtension.cs | 110 +++++ .../Types/ImmutableListExtension.cs | 110 +++++ .../ImmutableSortedDictionariesExtension.cs | 115 +++++ .../Types/ImmutableSortedSetExtension.cs | 112 +++++ .../Types/TypeModelExtension.cs | 3 +- .../ExtensionModel/Xml/InstanceFormatter.cs | 4 +- .../CollectionAwareConstructorLocator.cs | 21 + ...Activators.cs => ConstructedActivators.cs} | 136 +++--- .../DefaultConstructedActivators.cs | 12 + .../DictionaryConstructorLocator.cs | 42 ++ .../ReflectionModel/IsInterface.cs | 12 + .../ReflectionModel/ListConstructorLocator.cs | 35 ++ .../ReflectionModel/Support.cs | 4 +- .../Issue485Tests.cs | 417 ++++++++++++++++++ .../Issue485Tests_Extended.cs | 71 +++ 33 files changed, 1416 insertions(+), 137 deletions(-) create mode 100644 src/ExtendedXmlSerializer/ContentModel/Reflection/DefaultTypeDefaults.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Content/Members/DefaultValueTypeDefaults.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedAwareTypeDefaults.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationAware.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableDictionariesExtension.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableHashSetExtension.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableListExtension.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedDictionariesExtension.cs create mode 100644 src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedSetExtension.cs create mode 100644 src/ExtendedXmlSerializer/ReflectionModel/CollectionAwareConstructorLocator.cs rename src/ExtendedXmlSerializer/ReflectionModel/{DefaultActivators.cs => ConstructedActivators.cs} (54%) create mode 100644 src/ExtendedXmlSerializer/ReflectionModel/DefaultConstructedActivators.cs create mode 100644 src/ExtendedXmlSerializer/ReflectionModel/DictionaryConstructorLocator.cs create mode 100644 src/ExtendedXmlSerializer/ReflectionModel/IsInterface.cs create mode 100644 src/ExtendedXmlSerializer/ReflectionModel/ListConstructorLocator.cs create mode 100644 test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests.cs create mode 100644 test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests_Extended.cs diff --git a/src/ExtendedXmlSerializer/Configuration/EmitBehaviors.cs b/src/ExtendedXmlSerializer/Configuration/EmitBehaviors.cs index 584289d53..5b4e6779c 100644 --- a/src/ExtendedXmlSerializer/Configuration/EmitBehaviors.cs +++ b/src/ExtendedXmlSerializer/Configuration/EmitBehaviors.cs @@ -1,4 +1,5 @@ using ExtendedXmlSerializer.ContentModel.Members; +using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.ExtensionModel.Content.Members; using ExtendedXmlSerializer.ExtensionModel.Xml.Classic; using System; @@ -35,14 +36,13 @@ public static class EmitBehaviors /// MyProperty {get; set} = true` and `MyProperty` is `false` upon serialization, then the content is emitted. /// public static IEmitBehavior WhenModified { get; } = - new EmitBehavior(new AddAlteration(AllowedAssignedInstanceValues.Default)); + new EmitBehavior(new AddAlteration(new AllowedAssignedInstanceValues(new TypeMemberDefaults(DefaultTypeDefaults.Default)))); #region Obsolete /// [Obsolete("This is considered deprecated and will be removed in a future release. Use EmitBehaviors.WhenModified instead.")] - public static IEmitBehavior Assigned { get; } = - new EmitBehavior(new AddAlteration(AllowedAssignedInstanceValues.Default)); + public static IEmitBehavior Assigned { get; } = WhenModified; /// [Obsolete("This is considered deprecated and will be removed in a future release. Use EmitBehaviors.WhenAssigned instead.")] diff --git a/src/ExtendedXmlSerializer/ContentModel/Members/AllowedAssignedInstanceValues.cs b/src/ExtendedXmlSerializer/ContentModel/Members/AllowedAssignedInstanceValues.cs index 3efe2778c..c33dd7f76 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Members/AllowedAssignedInstanceValues.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Members/AllowedAssignedInstanceValues.cs @@ -7,16 +7,14 @@ namespace ExtendedXmlSerializer.ContentModel.Members { - class AllowedAssignedInstanceValues : IAllowedMemberValues + sealed class AllowedAssignedInstanceValues : IAllowedMemberValues { readonly ISpecification _specification; readonly ITypeMemberDefaults _defaults; readonly IGeneric> _generic; - public static AllowedAssignedInstanceValues Default { get; } = new AllowedAssignedInstanceValues(); - - AllowedAssignedInstanceValues() - : this(ActivatingTypeSpecification.Default, TypeMemberDefaults.Default, + public AllowedAssignedInstanceValues(ITypeMemberDefaults defaults) + : this(ActivatingTypeSpecification.Default, defaults, new Generic>(typeof(Specification<>))) {} public AllowedAssignedInstanceValues(ISpecification specification, ITypeMemberDefaults defaults, diff --git a/src/ExtendedXmlSerializer/ContentModel/Reflection/DefaultTypeDefaults.cs b/src/ExtendedXmlSerializer/ContentModel/Reflection/DefaultTypeDefaults.cs new file mode 100644 index 000000000..9dbc2ed33 --- /dev/null +++ b/src/ExtendedXmlSerializer/ContentModel/Reflection/DefaultTypeDefaults.cs @@ -0,0 +1,13 @@ +using ExtendedXmlSerializer.Core.Sources; +using ExtendedXmlSerializer.ReflectionModel; +using System.Reflection; + +namespace ExtendedXmlSerializer.ContentModel.Reflection +{ + sealed class DefaultTypeDefaults : DecoratedSource, ITypeDefaults + { + public static DefaultTypeDefaults Default { get; } = new DefaultTypeDefaults(); + + DefaultTypeDefaults() : base(new TypeDefaults(DefaultConstructedActivators.Default)) {} + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeDefaults.cs b/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeDefaults.cs index 8fb207998..ac719c27b 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeDefaults.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeDefaults.cs @@ -1,23 +1,22 @@ -using System.Reflection; using ExtendedXmlSerializer.Core.Sources; using ExtendedXmlSerializer.ReflectionModel; +using System.Reflection; namespace ExtendedXmlSerializer.ContentModel.Reflection { sealed class TypeDefaults : ReferenceCacheBase, ITypeDefaults { - public static TypeDefaults Default { get; } = new TypeDefaults(); + public static IParameterizedSource Defaults { get; } + = new ReferenceCache(key => new TypeDefaults(key)); + + /*public static TypeDefaults Default { get; } = new TypeDefaults(); - TypeDefaults() : this(DefaultActivators.Default) {} + TypeDefaults() : this(DefaultActivators.Default) {}*/ readonly IActivators _activators; - public TypeDefaults(IActivators activators) - { - _activators = activators; - } + public TypeDefaults(IActivators activators) => _activators = activators; - protected override object Create(TypeInfo parameter) => _activators.Get(parameter.AsType()) - .Get(); + protected override object Create(TypeInfo parameter) => _activators.Get(parameter.AsType()).Get(); } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeMemberDefaults.cs b/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeMemberDefaults.cs index 5ef98e8e7..245eeff84 100644 --- a/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeMemberDefaults.cs +++ b/src/ExtendedXmlSerializer/ContentModel/Reflection/TypeMemberDefaults.cs @@ -1,22 +1,19 @@ -using System; -using System.Reflection; using ExtendedXmlSerializer.ContentModel.Members; using ExtendedXmlSerializer.Core.Sources; +using System; +using System.Reflection; namespace ExtendedXmlSerializer.ContentModel.Reflection { sealed class TypeMemberDefaults : ReferenceCacheBase>, ITypeMemberDefaults { - public static TypeMemberDefaults Default { get; } = new TypeMemberDefaults(); + /*public static TypeMemberDefaults Default { get; } = new TypeMemberDefaults(); - TypeMemberDefaults() : this(TypeDefaults.Default) {} + TypeMemberDefaults() : this(TypeDefaults.Default) {}*/ readonly ITypeDefaults _defaults; - public TypeMemberDefaults(ITypeDefaults defaults) - { - _defaults = defaults; - } + public TypeMemberDefaults(ITypeDefaults defaults) => _defaults = defaults; protected override Func Create(TypeInfo parameter) => new MemberDefaults(_defaults.Get(parameter)).Get; diff --git a/src/ExtendedXmlSerializer/ExtensionMethodsForExtensionModel.cs b/src/ExtendedXmlSerializer/ExtensionMethodsForExtensionModel.cs index 6dbe09bc0..75b6a392e 100644 --- a/src/ExtendedXmlSerializer/ExtensionMethodsForExtensionModel.cs +++ b/src/ExtendedXmlSerializer/ExtensionMethodsForExtensionModel.cs @@ -127,6 +127,19 @@ public static IConfigurationContainer EnableMarkupExtensions(this IConfiguration public static IConfigurationContainer EnableAllConstructors(this IConfigurationContainer @this) => @this.Extend(AllConstructorsExtension.Default); + /// + /// Enables the use of types found in the `System.Collections.Immutable` namespace. + /// + /// The configuration container to configure. + /// The configured configuration container. + /// + public static IConfigurationContainer EnableImmutableTypes(this IConfigurationContainer @this) + => @this.Extend(ImmutableListExtension.Default) + .Extend(ImmutableHashSetExtension.Default) + .Extend(ImmutableSortedSetExtension.Default) + .Extend(ImmutableDictionariesExtension.Default) + .Extend(ImmutableSortedDictionariesExtension.Default); + #region Obsolete /// @@ -217,7 +230,7 @@ public static IConfigurationContainer AllowExistingInstances(this IConfiguration /// /// [Obsolete( - "This method is being deprecated. Please use ConfigurationContainer.WithUnknownContent.Call instead.")] + "This method is being deprecated. Please use ConfigurationContainer.WithUnknownContent.Call instead.")] public static IConfigurationContainer EnableUnknownContentHandling(this IConfigurationContainer @this, Action onMissing) => @this.WithUnknownContent().Call(onMissing); diff --git a/src/ExtendedXmlSerializer/ExtensionMethodsForSerialization.cs b/src/ExtendedXmlSerializer/ExtensionMethodsForSerialization.cs index 3b61eb283..97a745729 100644 --- a/src/ExtendedXmlSerializer/ExtensionMethodsForSerialization.cs +++ b/src/ExtendedXmlSerializer/ExtensionMethodsForSerialization.cs @@ -17,7 +17,7 @@ namespace ExtendedXmlSerializer /// public static class ExtensionMethodsForSerialization { - readonly static Func New = DefaultActivators.Default.New; + readonly static Func New = DefaultConstructedActivators.Default.New; readonly static IXmlWriterFactory WriterFactory = new XmlWriterFactory(CloseSettings.Default.Get(ExtensionModel.Xml.Defaults.WriterSettings)); diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/ImplicitlyDefinedDefaultValueAlteration.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/ImplicitlyDefinedDefaultValueAlteration.cs index a835a02bd..436ea6190 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Content/ImplicitlyDefinedDefaultValueAlteration.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/ImplicitlyDefinedDefaultValueAlteration.cs @@ -1,8 +1,8 @@ -using System; -using ExtendedXmlSerializer.ContentModel.Conversion; +using ExtendedXmlSerializer.ContentModel.Conversion; using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.Core.Parsing; using ExtendedXmlSerializer.Core.Sources; +using System; namespace ExtendedXmlSerializer.ExtensionModel.Content { @@ -15,7 +15,7 @@ sealed class ImplicitlyDefinedDefaultValueAlteration : IAlteration public IConverter Get(IConverter parameter) { - var @default = TypeDefaults.Default.Get(parameter.Get()); + var @default = DefaultTypeDefaults.Default.Get(parameter.Get()); var parser = new Parser(parameter.Parse, @default); var result = new Converter(parameter, parser.Get, parameter.Format); return result; diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs index 5ba133aa3..af66b9ea0 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/AllMembersParameterizedActivators.cs @@ -1,4 +1,5 @@ using ExtendedXmlSerializer.ContentModel.Members; +using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.Core; using ExtendedXmlSerializer.Core.Sources; using ExtendedXmlSerializer.ExtensionModel.Types; @@ -16,18 +17,27 @@ sealed class AllMembersParameterizedActivators : IActivators readonly IQueriedConstructors _constructors; readonly IMemberAccessors _accessors; readonly ITypeMembers _typeMembers; + readonly ITypeDefaults _defaults; readonly IConstructorMembers _members; // ReSharper disable once TooManyDependencies public AllMembersParameterizedActivators(IActivators activators, IQueriedConstructors constructors, IConstructorMembers members, IMemberAccessors accessors, ITypeMembers typeMembers) + : this(activators, constructors, members, accessors, typeMembers, + new ParameterizedAwareTypeDefaults(TypeDefaults.Defaults.Get(activators), constructors)) {} + + // ReSharper disable once TooManyDependencies + public AllMembersParameterizedActivators(IActivators activators, IQueriedConstructors constructors, + IConstructorMembers members, IMemberAccessors accessors, + ITypeMembers typeMembers, ITypeDefaults defaults) { _activators = activators; _constructors = constructors; _members = members; _accessors = accessors; _typeMembers = typeMembers; + _defaults = defaults; } public IActivator Get(Type parameter) @@ -46,7 +56,7 @@ ActivationContextActivator Activator(ConstructorInfo constructor, ImmutableArray { var activator = new Source(constructor).ToSelectionDelegate(); var context = new MemberContext(constructor.ReflectedType.GetTypeInfo(), members); - var contexts = new ActivationContexts(_accessors, context, activator); + var contexts = new ActivationContexts(_accessors, context, activator, _defaults); var defaults = constructor.GetParameters() .Where(x => x.IsOptional) .Select(x => Pairs.Create(x.Name, x.DefaultValue)) @@ -65,7 +75,10 @@ public IActivator Get(Func parameter) { var arguments = new Enumerable(_constructor.GetParameters() .Select(x => x.Name) - .Select(parameter)); + .Select(parameter) + .Select(x => x is IActivationAware aware + ? aware.Get() + : x)); var result = new ConstructedActivator(_constructor, arguments); return result; } diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/DefaultValueTypeDefaults.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/DefaultValueTypeDefaults.cs new file mode 100644 index 000000000..edcd01161 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/DefaultValueTypeDefaults.cs @@ -0,0 +1,20 @@ +using ExtendedXmlSerializer.ContentModel.Reflection; +using ExtendedXmlSerializer.Core.Sources; +using ExtendedXmlSerializer.ReflectionModel; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Content.Members +{ + sealed class DefaultValueTypeDefaults : ITypeDefaults + { + public static DefaultValueTypeDefaults Default { get; } = new DefaultValueTypeDefaults(); + + DefaultValueTypeDefaults() : this(new Generic>(typeof(DefaultValues<>))) {} + + readonly IGeneric> _generic; + + public DefaultValueTypeDefaults(IGeneric> generic) => _generic = generic; + + public object Get(TypeInfo parameter) => _generic.Get(parameter)().Get(); + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs index 553967bde..e84476960 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedActivators.cs @@ -1,4 +1,5 @@ using ExtendedXmlSerializer.ContentModel.Members; +using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.Core; using ExtendedXmlSerializer.Core.Sources; using ExtendedXmlSerializer.ExtensionModel.Types; @@ -15,16 +16,24 @@ sealed class ParameterizedActivators : IActivators readonly IActivators _activators; readonly IQueriedConstructors _constructors; readonly IMemberAccessors _accessors; + readonly ITypeDefaults _defaults; readonly IConstructorMembers _members; // ReSharper disable once TooManyDependencies public ParameterizedActivators(IActivators activators, IQueriedConstructors constructors, IConstructorMembers members, IMemberAccessors accessors) + : this(activators, constructors, members, accessors, + new ParameterizedAwareTypeDefaults(TypeDefaults.Defaults.Get(activators), constructors)) {} + + // ReSharper disable once TooManyDependencies + public ParameterizedActivators(IActivators activators, IQueriedConstructors constructors, + IConstructorMembers members, IMemberAccessors accessors, ITypeDefaults defaults) { _activators = activators; _constructors = constructors; _members = members; _accessors = accessors; + _defaults = defaults; } public IActivator Get(Type parameter) @@ -42,7 +51,7 @@ ActivationContextActivator Activator(ConstructorInfo constructor, ImmutableArray { var activator = new Source(constructor).ToSelectionDelegate(); var context = new MemberContext(constructor.ReflectedType.GetTypeInfo(), members); - var contexts = new ActivationContexts(_accessors, context, activator); + var contexts = new ActivationContexts(_accessors, context, activator, _defaults); var defaults = constructor.GetParameters() .Where(x => x.IsOptional) .Select(x => Pairs.Create(x.Name, x.DefaultValue)) @@ -61,7 +70,10 @@ public IActivator Get(Func parameter) { var arguments = new Enumerable(_constructor.GetParameters() .Select(x => x.Name) - .Select(parameter)); + .Select(parameter) + .Select(x => x is IActivationAware aware + ? aware.Get() + : x)); var result = new ConstructedActivator(_constructor, arguments); return result; } diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedAwareTypeDefaults.cs b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedAwareTypeDefaults.cs new file mode 100644 index 000000000..1142a0195 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Content/Members/ParameterizedAwareTypeDefaults.cs @@ -0,0 +1,31 @@ +using ExtendedXmlSerializer.ContentModel.Reflection; +using ExtendedXmlSerializer.ExtensionModel.Types; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Content.Members +{ + sealed class ParameterizedAwareTypeDefaults : ITypeDefaults + { + readonly ITypeDefaults _previous; + readonly IQueriedConstructors _constructors; + readonly ITypeDefaults _defaults; + + public ParameterizedAwareTypeDefaults(ITypeDefaults previous, IQueriedConstructors constructors) + : this(previous, constructors, DefaultValueTypeDefaults.Default) {} + + public ParameterizedAwareTypeDefaults(ITypeDefaults previous, IQueriedConstructors constructors, + ITypeDefaults defaults) + { + _previous = previous; + _constructors = constructors; + _defaults = defaults; + } + + public object Get(TypeInfo parameter) + { + var defaults = _constructors.Get(parameter) != null ? _defaults : _previous; + var result = defaults.Get(parameter); + return result; + } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs b/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs index 31c0f494b..cdb0a2944 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensionPartsEvaluator.cs @@ -2,6 +2,7 @@ using ExtendedXmlSerializer.ContentModel.Identification; using ExtendedXmlSerializer.ContentModel.Members; using ExtendedXmlSerializer.ContentModel.Properties; +using ExtendedXmlSerializer.ContentModel.Reflection; using ExtendedXmlSerializer.Core; using ExtendedXmlSerializer.Core.Parsing; using ExtendedXmlSerializer.Core.Sources; @@ -33,17 +34,21 @@ sealed class MarkupExtensionPartsEvaluator readonly IConstructors _constructors; readonly System.IServiceProvider _provider; readonly IFormatter _formatter; + readonly ITypeDefaults _defaults; readonly object[] _services; - public MarkupExtensionPartsEvaluator(IParser parser, IEvaluator evaluator, ITypeMembers members, + public MarkupExtensionPartsEvaluator(IActivators activators, + IParser parser, IEvaluator evaluator, ITypeMembers members, IMemberAccessors accessors, IConstructors constructors, - System.IServiceProvider provider, params object[] services) + System.IServiceProvider provider, + params object[] services) : this(parser, evaluator, members, accessors, constructors, provider, TypePartsFormatter.Default, - services) {} + TypeDefaults.Defaults.Get(activators), services) {} public MarkupExtensionPartsEvaluator(IParser parser, IEvaluator evaluator, ITypeMembers members, IMemberAccessors accessors, IConstructors constructors, System.IServiceProvider provider, IFormatter formatter, + ITypeDefaults defaults, params object[] services) { _parser = parser; @@ -53,6 +58,7 @@ public MarkupExtensionPartsEvaluator(IParser parser, IEvaluator eval _constructors = constructors; _provider = provider; _formatter = formatter; + _defaults = defaults; _services = services; } @@ -81,9 +87,10 @@ protected override object Create(MarkupExtensionParts parameter) .ToArray(); var activator = new ConstructedActivator(constructor, arguments); var context = new MemberContext(constructor.ReflectedType.GetTypeInfo(), members); - var extension = new ActivationContexts(_accessors, context, activator).Get(dictionary) - .Get() - .AsValid(); + var extension = new ActivationContexts(_accessors, context, activator, _defaults) + .Get(dictionary) + .Get() + .AsValid(); var result = extension.ProvideValue(new Provider(_provider, _services.Appending(parameter) .ToArray())); return result; diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensions.cs b/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensions.cs index a29f0fd5e..6538bdd33 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensions.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Markup/MarkupExtensions.cs @@ -10,6 +10,7 @@ sealed class MarkupExtensions : ReferenceCacheBase, IMarkupExtensions { + readonly IActivators _activators; readonly IEvaluator _evaluator; readonly ITypeMembers _members; readonly IMemberAccessors _accessors; @@ -17,9 +18,11 @@ sealed class MarkupExtensions readonly System.IServiceProvider _provider; // ReSharper disable once TooManyDependencies - public MarkupExtensions(IEvaluator evaluator, ITypeMembers members, IMemberAccessors accessors, - IConstructors constructors, System.IServiceProvider provider) + public MarkupExtensions(IActivators activators, IEvaluator evaluator, ITypeMembers members, + IMemberAccessors accessors, IConstructors constructors, + System.IServiceProvider provider) { + _activators = activators; _evaluator = evaluator; _members = members; _accessors = accessors; @@ -28,7 +31,7 @@ public MarkupExtensions(IEvaluator evaluator, ITypeMembers members, IMemberAcces } protected override IMarkupExtensionPartsEvaluator Create(IFormatReader parameter) - => new MarkupExtensionPartsEvaluator(parameter, _evaluator, _members, _accessors, _constructors, _provider, - parameter); + => new MarkupExtensionPartsEvaluator(_activators, parameter, _evaluator, _members, _accessors, + _constructors, _provider, parameter); } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs index 522998604..3a094c714 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ActivationContexts.cs @@ -15,27 +15,39 @@ sealed class ActivationContexts : IActivationContexts readonly MemberContext _members; readonly ITableSource _table; readonly Func, IActivator> _activator; + readonly ITypeDefaults _defaults; - public ActivationContexts(IMemberAccessors accessors, MemberContext members, IActivator activator) - : this(accessors, members, activator.Accept) {} + // ReSharper disable once TooManyDependencies + public ActivationContexts(IActivators activators, IMemberAccessors accessors, MemberContext members, + IActivator activator) + : this(accessors, members, activator, TypeDefaults.Defaults.Get(activators)) {} + + // ReSharper disable once TooManyDependencies + public ActivationContexts(IMemberAccessors accessors, MemberContext members, IActivator activator, + ITypeDefaults defaults) + : this(accessors, members, activator.Accept, defaults) {} + // ReSharper disable once TooManyDependencies public ActivationContexts(IMemberAccessors accessors, MemberContext members, - Func, IActivator> activator) + Func, IActivator> activator, ITypeDefaults defaults) : this(accessors, members, new TableSource(members.Members .ToDictionary(x => x.Name, StringComparer.InvariantCultureIgnoreCase)), - activator) {} + activator, defaults) {} // ReSharper disable once TooManyDependencies public ActivationContexts(IMemberAccessors accessors, MemberContext members, ITableSource table, - Func, IActivator> activator) + Func, IActivator> activator, + ITypeDefaults defaults + ) { _accessors = accessors; _members = members; _table = table; _activator = activator; + _defaults = defaults; } public IActivationContext Get(IDictionary parameter) @@ -46,7 +58,7 @@ public IActivationContext Get(IDictionary parameter) source), new AddItemsCommand(list)); var alteration = new ConfiguringAlteration(command); - var activator = new AlteringActivator(alteration, _activator(new Store(source, _table).Get)); + var activator = new AlteringActivator(alteration, _activator(new Store(source, _table, _defaults).Get)); var result = new ActivationContext(_members.ReflectedType, source, activator.Singleton().Get, list); return result; } @@ -57,9 +69,6 @@ sealed class Store : IParameterizedSource readonly IParameterizedSource _members; readonly ITypeDefaults _defaults; - public Store(ITableSource store, IParameterizedSource members) - : this(store, members, TypeDefaults.Default) {} - public Store(ITableSource store, IParameterizedSource members, ITypeDefaults defaults) { diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/Activators.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/Activators.cs index c061da8f1..31a174722 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Types/Activators.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/Activators.cs @@ -1,15 +1,14 @@ -using System; using ExtendedXmlSerializer.Core; using ExtendedXmlSerializer.Core.Sources; using ExtendedXmlSerializer.ReflectionModel; +using System; namespace ExtendedXmlSerializer.ExtensionModel.Types { sealed class Activators : ReferenceCacheBase, IActivators { - public static Activators Default { get; } = new Activators(); - - Activators() : this(ActivatingTypeSpecification.Default, DefaultActivators.Default, SingletonLocator.Default) {} + public Activators(IActivators activators) + : this(ActivatingTypeSpecification.Default, activators, SingletonLocator.Default) {} readonly IActivatingTypeSpecification _specification; readonly IActivators _activators; diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationAware.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationAware.cs new file mode 100644 index 000000000..0cabf7c00 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/IActivationAware.cs @@ -0,0 +1,9 @@ +using ExtendedXmlSerializer.Core.Sources; + +namespace ExtendedXmlSerializer.ExtensionModel.Types +{ + /// + /// Convenience interface for activating components. + /// + public interface IActivationAware : ISource {} +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableDictionariesExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableDictionariesExtension.cs new file mode 100644 index 000000000..8ad070d42 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableDictionariesExtension.cs @@ -0,0 +1,112 @@ +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Content; +using ExtendedXmlSerializer.ContentModel.Format; +using ExtendedXmlSerializer.ContentModel.Identification; +using ExtendedXmlSerializer.ContentModel.Reflection; +using ExtendedXmlSerializer.Core; +using ExtendedXmlSerializer.Core.Specifications; +using ExtendedXmlSerializer.ReflectionModel; +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Types +{ + sealed class ImmutableDictionariesExtension : ISerializerExtension + { + public static ImmutableDictionariesExtension Default { get; } = new ImmutableDictionariesExtension(); + + ImmutableDictionariesExtension() : this(new IsAssignableGenericSpecification(typeof(ImmutableDictionary<,>))) {} + + readonly ISpecification _specification; + + public ImmutableDictionariesExtension(ISpecification specification) => _specification = specification; + + public IServiceRepository Get(IServiceRepository parameter) + => parameter.DecorateContentsWith() + .When(_specification) + .Decorate() + .Decorate(Register); + + IConstructorLocator Register(IServiceProvider arg1, IConstructorLocator previous) + => new ConstructorLocator(_specification, previous); + + void ICommand.Execute(IServices parameter) {} + + sealed class ConstructorLocator : DictionaryConstructorLocator, IConstructorLocator + { + public ConstructorLocator(ISpecification specification, IConstructorLocator previous) + : base(specification, previous, typeof(Adapter<,>)) {} + } + + sealed class Adapter : Dictionary, IActivationAware + { + public object Get() => this.ToImmutableDictionary(); + } + + sealed class GenericTypes : IGenericTypes + { + readonly static TypeInfo Check = typeof(ImmutableDictionary).GetTypeInfo(); + readonly static ImmutableArray Type = typeof(ImmutableDictionary<,>).GetTypeInfo() + .Yield() + .ToImmutableArray(); + + readonly IGenericTypes _types; + + public GenericTypes(IGenericTypes types) => _types = types; + + public ImmutableArray Get(IIdentity parameter) + { + var type = _types.Get(parameter); + var result = type.Only()?.Equals(Check) ?? false ? Type : type; + return result; + } + } + + sealed class Contents : IContents + { + readonly IContents _contents; + readonly IGeneric _readers; + readonly Type _type; + + [UsedImplicitly] + public Contents(IContents contents) : this(contents, Readers.Instance, typeof(Dictionary<,>)) {} + + public Contents(IContents contents, IGeneric readers, Type type) + { + _contents = contents; + _readers = readers; + _type = type; + } + + public ISerializer Get(TypeInfo parameter) + { + var types = DictionaryPairTypesLocator.Default.Get(parameter).GetValueOrDefault(); + var type = _type.MakeGenericType(types.KeyType, types.ValueType); + var serializer = _contents.Get(type); + var result = new Serializer(_readers.Get(types.KeyType, types.ValueType)(serializer), serializer); + return result; + } + + sealed class Readers : Generic + { + public static Readers Instance { get; } = new Readers(); + + Readers() : base(typeof(Reader<,>)) {} + } + + sealed class Reader : IReader + { + readonly IReader _reader; + + [UsedImplicitly] + public Reader(IReader reader) => _reader = reader; + + public object Get(IFormatReader parameter) + => _reader.Get(parameter).AsValid>().ToImmutableDictionary(); + } + } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableHashSetExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableHashSetExtension.cs new file mode 100644 index 000000000..15d322881 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableHashSetExtension.cs @@ -0,0 +1,110 @@ +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Collections; +using ExtendedXmlSerializer.ContentModel.Content; +using ExtendedXmlSerializer.ContentModel.Format; +using ExtendedXmlSerializer.ContentModel.Identification; +using ExtendedXmlSerializer.ContentModel.Reflection; +using ExtendedXmlSerializer.Core; +using ExtendedXmlSerializer.Core.Specifications; +using ExtendedXmlSerializer.ReflectionModel; +using JetBrains.Annotations; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Types +{ + sealed class ImmutableHashSetExtension : ISerializerExtension + { + public static ImmutableHashSetExtension Default { get; } = new ImmutableHashSetExtension(); + + ImmutableHashSetExtension() : this(new IsAssignableGenericSpecification(typeof(ImmutableHashSet<>))) {} + + readonly ISpecification _specification; + + public ImmutableHashSetExtension(ISpecification specification) => _specification = specification; + + public IServiceRepository Get(IServiceRepository parameter) + => parameter.DecorateContentsWith() + .When(_specification) + .Decorate() + .Decorate(Register); + + IConstructorLocator Register(IServiceProvider arg1, IConstructorLocator previous) + => new ConstructorLocator(_specification, previous); + + void ICommand.Execute(IServices parameter) {} + + sealed class ConstructorLocator : ListConstructorLocator, IConstructorLocator + { + public ConstructorLocator(ISpecification specification, IConstructorLocator previous) + : base(specification, previous, typeof(Adapter<>)) {} + } + + sealed class Adapter : List, IActivationAware + { + public object Get() => this.ToImmutableHashSet(); + } + + sealed class GenericTypes : IGenericTypes + { + readonly static TypeInfo Check = typeof(ImmutableHashSet).GetTypeInfo(); + readonly static ImmutableArray Type = typeof(ImmutableHashSet<>).GetTypeInfo() + .Yield() + .ToImmutableArray(); + + readonly IGenericTypes _types; + + public GenericTypes(IGenericTypes types) => _types = types; + + public ImmutableArray Get(IIdentity parameter) + { + var type = _types.Get(parameter); + var result = type.Only()?.Equals(Check) ?? false ? Type : type; + return result; + } + } + + sealed class ImmutableHashSets : Collections + { + public ImmutableHashSets(RuntimeSerializers serializers, Contents contents) : base(serializers, contents) {} + } + + sealed class Contents : ICollectionContents + { + readonly IInnerContentServices _contents; + readonly IEnumerators _enumerators; + + public Contents(IInnerContentServices contents, IEnumerators enumerators) + { + _contents = contents; + _enumerators = enumerators; + } + + public ISerializer Get(CollectionContentInput parameter) + => new Serializer(Readers.Instance.Get(parameter.ItemType)(_contents, parameter.Item), + new EnumerableWriter(_enumerators, parameter.Item).Adapt()); + + sealed class Readers : Generic + { + public static Readers Instance { get; } = new Readers(); + + Readers() : base(typeof(Reader<>)) {} + } + + sealed class Reader : IReader + { + readonly IReader> _reader; + + [UsedImplicitly] + public Reader(IInnerContentServices services, IReader item) + : this(services.CreateContents>(new CollectionInnerContentHandler(item, services))) {} + + Reader(IReader> reader) => _reader = reader; + + public object Get(IFormatReader parameter) => _reader.Get(parameter).ToImmutableHashSet(); + } + } + } +} diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableListExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableListExtension.cs new file mode 100644 index 000000000..8c5252272 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableListExtension.cs @@ -0,0 +1,110 @@ +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Collections; +using ExtendedXmlSerializer.ContentModel.Content; +using ExtendedXmlSerializer.ContentModel.Format; +using ExtendedXmlSerializer.ContentModel.Identification; +using ExtendedXmlSerializer.ContentModel.Reflection; +using ExtendedXmlSerializer.Core; +using ExtendedXmlSerializer.Core.Specifications; +using ExtendedXmlSerializer.ReflectionModel; +using JetBrains.Annotations; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Types +{ + sealed class ImmutableListExtension : ISerializerExtension + { + public static ImmutableListExtension Default { get; } = new ImmutableListExtension(); + + ImmutableListExtension() : this(new IsAssignableGenericSpecification(typeof(ImmutableList<>))) {} + + readonly ISpecification _specification; + + public ImmutableListExtension(ISpecification specification) => _specification = specification; + + public IServiceRepository Get(IServiceRepository parameter) + => parameter.DecorateContentsWith() + .When(_specification) + .Decorate() + .Decorate(Register); + + IConstructorLocator Register(IServiceProvider arg1, IConstructorLocator previous) + => new ConstructorLocator(_specification, previous); + + void ICommand.Execute(IServices parameter) {} + + sealed class ConstructorLocator : ListConstructorLocator, IConstructorLocator + { + public ConstructorLocator(ISpecification specification, IConstructorLocator previous) + : base(specification, previous, typeof(Adapter<>)) {} + } + + sealed class Adapter : List, IActivationAware + { + public object Get() => this.ToImmutableList(); + } + + sealed class GenericTypes : IGenericTypes + { + readonly static TypeInfo Check = typeof(ImmutableList).GetTypeInfo(); + readonly static ImmutableArray Type = typeof(ImmutableList<>).GetTypeInfo() + .Yield() + .ToImmutableArray(); + + readonly IGenericTypes _types; + + public GenericTypes(IGenericTypes types) => _types = types; + + public ImmutableArray Get(IIdentity parameter) + { + var type = _types.Get(parameter); + var result = type.Only()?.Equals(Check) ?? false ? Type : type; + return result; + } + } + + sealed class ImmutableLists : Collections + { + public ImmutableLists(RuntimeSerializers serializers, Contents contents) : base(serializers, contents) {} + } + + sealed class Contents : ICollectionContents + { + readonly IInnerContentServices _contents; + readonly IEnumerators _enumerators; + + public Contents(IInnerContentServices contents, IEnumerators enumerators) + { + _contents = contents; + _enumerators = enumerators; + } + + public ISerializer Get(CollectionContentInput parameter) + => new Serializer(Readers.Instance.Get(parameter.ItemType)(_contents, parameter.Item), + new EnumerableWriter(_enumerators, parameter.Item).Adapt()); + + sealed class Readers : Generic + { + public static Readers Instance { get; } = new Readers(); + + Readers() : base(typeof(Reader<>)) {} + } + + sealed class Reader : IReader + { + readonly IReader> _reader; + + [UsedImplicitly] + public Reader(IInnerContentServices services, IReader item) + : this(services.CreateContents>(new CollectionInnerContentHandler(item, services))) {} + + Reader(IReader> reader) => _reader = reader; + + public object Get(IFormatReader parameter) => _reader.Get(parameter).ToImmutableList(); + } + } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedDictionariesExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedDictionariesExtension.cs new file mode 100644 index 000000000..b91d8c5f1 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedDictionariesExtension.cs @@ -0,0 +1,115 @@ +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Content; +using ExtendedXmlSerializer.ContentModel.Format; +using ExtendedXmlSerializer.ContentModel.Identification; +using ExtendedXmlSerializer.ContentModel.Reflection; +using ExtendedXmlSerializer.Core; +using ExtendedXmlSerializer.Core.Specifications; +using ExtendedXmlSerializer.ReflectionModel; +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Types +{ + sealed class ImmutableSortedDictionariesExtension : ISerializerExtension + { + public static ImmutableSortedDictionariesExtension Default { get; } + = new ImmutableSortedDictionariesExtension(); + + ImmutableSortedDictionariesExtension() + : this(new IsAssignableGenericSpecification(typeof(ImmutableSortedDictionary<,>))) {} + + readonly ISpecification _specification; + + public ImmutableSortedDictionariesExtension(ISpecification specification) + => _specification = specification; + + public IServiceRepository Get(IServiceRepository parameter) + => parameter.DecorateContentsWith() + .When(_specification) + .Decorate() + .Decorate(Register); + + IConstructorLocator Register(IServiceProvider arg1, IConstructorLocator previous) + => new ConstructorLocator(_specification, previous); + + void ICommand.Execute(IServices parameter) {} + + sealed class ConstructorLocator : DictionaryConstructorLocator, IConstructorLocator + { + public ConstructorLocator(ISpecification specification, IConstructorLocator previous) + : base(specification, previous, typeof(Adapter<,>)) {} + } + + sealed class Adapter : Dictionary, IActivationAware + { + public object Get() => this.ToImmutableSortedDictionary(); + } + + sealed class GenericTypes : IGenericTypes + { + readonly static TypeInfo Check = typeof(ImmutableSortedDictionary).GetTypeInfo(); + readonly static ImmutableArray Type = typeof(ImmutableSortedDictionary<,>).GetTypeInfo() + .Yield() + .ToImmutableArray(); + + readonly IGenericTypes _types; + + public GenericTypes(IGenericTypes types) => _types = types; + + public ImmutableArray Get(IIdentity parameter) + { + var type = _types.Get(parameter); + var result = type.Only()?.Equals(Check) ?? false ? Type : type; + return result; + } + } + + sealed class Contents : IContents + { + readonly IContents _contents; + readonly IGeneric _readers; + readonly Type _type; + + [UsedImplicitly] + public Contents(IContents contents) : this(contents, Readers.Instance, typeof(Dictionary<,>)) {} + + public Contents(IContents contents, IGeneric readers, Type type) + { + _contents = contents; + _readers = readers; + _type = type; + } + + public ISerializer Get(TypeInfo parameter) + { + var types = DictionaryPairTypesLocator.Default.Get(parameter).GetValueOrDefault(); + var type = _type.MakeGenericType(types.KeyType, types.ValueType); + var serializer = _contents.Get(type); + var result = new Serializer(_readers.Get(types.KeyType, types.ValueType)(serializer), serializer); + return result; + } + + sealed class Readers : Generic + { + public static Readers Instance { get; } = new Readers(); + + Readers() : base(typeof(Reader<,>)) {} + } + + sealed class Reader : IReader + { + readonly IReader _reader; + + [UsedImplicitly] + public Reader(IReader reader) => _reader = reader; + + public object Get(IFormatReader parameter) + => _reader.Get(parameter).AsValid>().ToImmutableSortedDictionary(); + } + } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedSetExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedSetExtension.cs new file mode 100644 index 000000000..84a490e79 --- /dev/null +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/ImmutableSortedSetExtension.cs @@ -0,0 +1,112 @@ +using ExtendedXmlSerializer.ContentModel; +using ExtendedXmlSerializer.ContentModel.Collections; +using ExtendedXmlSerializer.ContentModel.Content; +using ExtendedXmlSerializer.ContentModel.Format; +using ExtendedXmlSerializer.ContentModel.Identification; +using ExtendedXmlSerializer.ContentModel.Reflection; +using ExtendedXmlSerializer.Core; +using ExtendedXmlSerializer.Core.Specifications; +using ExtendedXmlSerializer.ReflectionModel; +using JetBrains.Annotations; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Reflection; + +namespace ExtendedXmlSerializer.ExtensionModel.Types +{ + sealed class ImmutableSortedSetExtension : ISerializerExtension + { + public static ImmutableSortedSetExtension Default { get; } = new ImmutableSortedSetExtension(); + + ImmutableSortedSetExtension() : this(new IsAssignableGenericSpecification(typeof(ImmutableSortedSet<>))) {} + + readonly ISpecification _specification; + + public ImmutableSortedSetExtension(ISpecification specification) => _specification = specification; + + public IServiceRepository Get(IServiceRepository parameter) + => parameter.DecorateContentsWith() + .When(_specification) + .Decorate() + .Decorate(Register); + + IConstructorLocator Register(IServiceProvider arg1, IConstructorLocator previous) + => new ConstructorLocator(_specification, previous); + + void ICommand.Execute(IServices parameter) {} + + sealed class ConstructorLocator : ListConstructorLocator, IConstructorLocator + { + public ConstructorLocator(ISpecification specification, IConstructorLocator previous) + : base(specification, previous, typeof(Adapter<>)) {} + } + + sealed class Adapter : List, IActivationAware + { + public object Get() => this.ToImmutableSortedSet(); + } + + sealed class GenericTypes : IGenericTypes + { + readonly static TypeInfo Check = typeof(ImmutableSortedSet).GetTypeInfo(); + readonly static ImmutableArray Type = typeof(ImmutableSortedSet<>).GetTypeInfo() + .Yield() + .ToImmutableArray(); + + readonly IGenericTypes _types; + + public GenericTypes(IGenericTypes types) => _types = types; + + public ImmutableArray Get(IIdentity parameter) + { + var type = _types.Get(parameter); + var result = type.Only()?.Equals(Check) ?? false ? Type : type; + return result; + } + } + + sealed class ImmutableSortedSets : Collections + { + public ImmutableSortedSets(RuntimeSerializers serializers, Contents contents) + : base(serializers, contents) {} + } + + sealed class Contents : ICollectionContents + { + readonly IInnerContentServices _contents; + readonly IEnumerators _enumerators; + + public Contents(IInnerContentServices contents, IEnumerators enumerators) + { + _contents = contents; + _enumerators = enumerators; + } + + public ISerializer Get(CollectionContentInput parameter) + => new Serializer(Readers.Instance.Get(parameter.ItemType)(_contents, parameter.Item), + new EnumerableWriter(_enumerators, parameter.Item).Adapt()); + + sealed class Readers : Generic + { + public static Readers Instance { get; } = new Readers(); + + Readers() : base(typeof(Reader<>)) {} + } + + sealed class Reader : IReader + { + readonly IReader> _reader; + + [UsedImplicitly] + public Reader(IInnerContentServices services, IReader item) + : this(services.CreateContents>(new CollectionInnerContentHandler(item, services))) {} + + Reader(IReader> reader) => _reader = reader; + + public object Get(IFormatReader parameter) => _reader.Get(parameter).ToImmutableSortedSet(); + } + } + } + +} diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Types/TypeModelExtension.cs b/src/ExtendedXmlSerializer/ExtensionModel/Types/TypeModelExtension.cs index 590c9a6f3..c0c8368b6 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Types/TypeModelExtension.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Types/TypeModelExtension.cs @@ -20,9 +20,10 @@ public sealed class TypeModelExtension : ISerializerExtension public IServiceRepository Get(IServiceRepository parameter) => parameter.Register() .Register() - .Register() + .Register() .Register() .Register() + .Decorate() .Register() .Register() .RegisterInstance(DictionaryEnumerators.Default) diff --git a/src/ExtendedXmlSerializer/ExtensionModel/Xml/InstanceFormatter.cs b/src/ExtendedXmlSerializer/ExtensionModel/Xml/InstanceFormatter.cs index fd092fcbd..b237d44eb 100644 --- a/src/ExtendedXmlSerializer/ExtensionModel/Xml/InstanceFormatter.cs +++ b/src/ExtendedXmlSerializer/ExtensionModel/Xml/InstanceFormatter.cs @@ -1,12 +1,12 @@ +using ExtendedXmlSerializer.ReflectionModel; using System; using System.IO; -using ExtendedXmlSerializer.ReflectionModel; namespace ExtendedXmlSerializer.ExtensionModel.Xml { class InstanceFormatter : IInstanceFormatter { - readonly static Func Stream = DefaultActivators.Default.New; + readonly static Func Stream = DefaultConstructedActivators.Default.New; readonly IExtendedXmlSerializer _serializer; readonly IXmlWriterFactory _factory; diff --git a/src/ExtendedXmlSerializer/ReflectionModel/CollectionAwareConstructorLocator.cs b/src/ExtendedXmlSerializer/ReflectionModel/CollectionAwareConstructorLocator.cs new file mode 100644 index 000000000..8b4515700 --- /dev/null +++ b/src/ExtendedXmlSerializer/ReflectionModel/CollectionAwareConstructorLocator.cs @@ -0,0 +1,21 @@ +using ExtendedXmlSerializer.Core.Specifications; +using System.Collections.Generic; +using System.Reflection; + +namespace ExtendedXmlSerializer.ReflectionModel +{ + sealed class CollectionAwareConstructorLocator : ListConstructorLocator, IConstructorLocator + { + readonly static ISpecification Specification = IsInterface.Default.And(IsCollectionType.Instance); + + public CollectionAwareConstructorLocator(IConstructorLocator previous) : base(Specification, previous) {} + + sealed class IsCollectionType : AnySpecification + { + public static IsCollectionType Instance { get; } = new IsCollectionType(); + + IsCollectionType() : base(IsCollectionTypeSpecification.Default, + new IsAssignableGenericSpecification(typeof(IReadOnlyCollection<>))) {} + } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ReflectionModel/DefaultActivators.cs b/src/ExtendedXmlSerializer/ReflectionModel/ConstructedActivators.cs similarity index 54% rename from src/ExtendedXmlSerializer/ReflectionModel/DefaultActivators.cs rename to src/ExtendedXmlSerializer/ReflectionModel/ConstructedActivators.cs index 8a8447bba..b1970a353 100644 --- a/src/ExtendedXmlSerializer/ReflectionModel/DefaultActivators.cs +++ b/src/ExtendedXmlSerializer/ReflectionModel/ConstructedActivators.cs @@ -1,76 +1,62 @@ -using ExtendedXmlSerializer.Core.Sources; -using ExtendedXmlSerializer.Core.Specifications; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; - -namespace ExtendedXmlSerializer.ReflectionModel -{ - sealed class DefaultActivators : ReferenceCacheBase, IActivators - { - readonly static Func Selector = DefaultParameters.Instance.Get; - - public static DefaultActivators Default { get; } = new DefaultActivators(); - - DefaultActivators() : this(ConstructorLocator.Default) {} - - readonly IConstructorLocator _locator; - - public DefaultActivators(IConstructorLocator locator) => _locator = locator; - - protected override IActivator Create(Type parameter) - { - var typeInfo = parameter.GetTypeInfo(); - var expression = parameter == typeof(string) - ? (Expression)Expression.Default(parameter) - : typeInfo.IsValueType - ? Expression.New(parameter) - : Reference(parameter, typeInfo); - var convert = Expression.Convert(expression, typeof(object)); - var lambda = Expression.Lambda>(convert); - var result = new Activator(lambda.Compile()); - return result; - } - - NewExpression Reference(Type parameter, TypeInfo typeInfo) - { - var accounted = typeInfo.IsInterface && IsCollectionType.Instance.IsSatisfiedBy(parameter) - ? typeof(List<>).MakeGenericType(CollectionItemTypeLocator.Default.Get(typeInfo)) - : typeInfo; - var constructor = _locator.Get(accounted) ?? _locator.Get(typeInfo); - var parameters = constructor.GetParameters(); - var result = parameters.Length > 0 - ? Expression.New(constructor, parameters.Select(Selector)) - : Expression.New(accounted); - return result; - } - - sealed class DefaultParameters : IParameterizedSource - { - readonly static IEnumerable Initializers = Enumerable.Empty(); - - public static DefaultParameters Instance { get; } = new DefaultParameters(); - - DefaultParameters() {} - - public Expression Get(ParameterInfo parameter) - => parameter.IsDefined(typeof(ParamArrayAttribute)) - ? (Expression)Expression.NewArrayInit( - parameter.ParameterType.GetElementType() ?? - throw new - InvalidOperationException("Element Type not found."), - Initializers) - : Expression.Default(parameter.ParameterType); - } - - sealed class IsCollectionType : AnySpecification - { - public static IsCollectionType Instance { get; } = new IsCollectionType(); - - IsCollectionType() : base(IsCollectionTypeSpecification.Default, - new IsAssignableGenericSpecification(typeof(IReadOnlyCollection<>))) {} - } - } +using ExtendedXmlSerializer.Core.Sources; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace ExtendedXmlSerializer.ReflectionModel +{ + sealed class ConstructedActivators : ReferenceCacheBase, IActivators + { + readonly static Func Selector = DefaultParameters.Instance.Get; + + /*public static DefaultActivators Default { get; } = new DefaultActivators(); + + DefaultActivators() : this(ConstructorLocator.Default) {}*/ + + readonly IConstructorLocator _locator; + + public ConstructedActivators(IConstructorLocator locator) => _locator = locator; + + protected override IActivator Create(Type parameter) + { + var expression = parameter == typeof(string) + ? (Expression)Expression.Default(parameter) + : parameter.IsValueType + ? Expression.New(parameter) + : Reference(parameter); + var convert = Expression.Convert(expression, typeof(object)); + var lambda = Expression.Lambda>(convert); + var result = new Activator(lambda.Compile()); + return result; + } + + NewExpression Reference(Type parameter) + { + var constructor = _locator.Get(parameter); + var parameters = constructor.GetParameters(); + var result = parameters.Length > 0 + ? Expression.New(constructor, parameters.Select(Selector)) + : Expression.New(constructor); + return result; + } + + sealed class DefaultParameters : IParameterizedSource + { + readonly static IEnumerable Initializers = Enumerable.Empty(); + + public static DefaultParameters Instance { get; } = new DefaultParameters(); + + DefaultParameters() {} + + public Expression Get(ParameterInfo parameter) + => parameter.IsDefined(typeof(ParamArrayAttribute)) + ? (Expression)Expression.NewArrayInit(parameter.ParameterType.GetElementType() ?? + throw new + InvalidOperationException("Element Type not found."), + Initializers) + : Expression.Default(parameter.ParameterType); + } + } } \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ReflectionModel/DefaultConstructedActivators.cs b/src/ExtendedXmlSerializer/ReflectionModel/DefaultConstructedActivators.cs new file mode 100644 index 000000000..4f6498463 --- /dev/null +++ b/src/ExtendedXmlSerializer/ReflectionModel/DefaultConstructedActivators.cs @@ -0,0 +1,12 @@ +using ExtendedXmlSerializer.Core.Sources; +using System; + +namespace ExtendedXmlSerializer.ReflectionModel +{ + sealed class DefaultConstructedActivators : DecoratedSource, IActivators + { + public static DefaultConstructedActivators Default { get; } = new DefaultConstructedActivators(); + + DefaultConstructedActivators() : base(new ConstructedActivators(ConstructorLocator.Default)) {} + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ReflectionModel/DictionaryConstructorLocator.cs b/src/ExtendedXmlSerializer/ReflectionModel/DictionaryConstructorLocator.cs new file mode 100644 index 000000000..153a712fd --- /dev/null +++ b/src/ExtendedXmlSerializer/ReflectionModel/DictionaryConstructorLocator.cs @@ -0,0 +1,42 @@ +using ExtendedXmlSerializer.Core.Sources; +using ExtendedXmlSerializer.Core.Specifications; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace ExtendedXmlSerializer.ReflectionModel +{ + class DictionaryConstructorLocator : IParameterizedSource + { + readonly ISpecification _specification; + readonly IConstructorLocator _previous; + readonly Type _baseType; + + public DictionaryConstructorLocator(ISpecification specification, IConstructorLocator previous) + : this(specification, previous, typeof(Dictionary<,>)) {} + + public DictionaryConstructorLocator(ISpecification specification, IConstructorLocator previous, + Type baseType) + { + _specification = specification; + _previous = previous; + _baseType = baseType; + } + + public ConstructorInfo Get(TypeInfo parameter) + { + var accounted = _specification.IsSatisfiedBy(parameter) + ? MakeGenericType(parameter) + : parameter; + var result = _previous.Get(accounted); + return result; + } + + Type MakeGenericType(TypeInfo parameter) + { + var types = DictionaryPairTypesLocator.Default.Get(parameter); + var result = _baseType.MakeGenericType(types?.KeyType, types?.ValueType); + return result; + } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ReflectionModel/IsInterface.cs b/src/ExtendedXmlSerializer/ReflectionModel/IsInterface.cs new file mode 100644 index 000000000..26069d3c7 --- /dev/null +++ b/src/ExtendedXmlSerializer/ReflectionModel/IsInterface.cs @@ -0,0 +1,12 @@ +using ExtendedXmlSerializer.Core.Specifications; +using System.Reflection; + +namespace ExtendedXmlSerializer.ReflectionModel +{ + sealed class IsInterface : DelegatedSpecification + { + public static IsInterface Default { get; } = new IsInterface(); + + IsInterface() : base(x => x.IsInterface) {} + } +} diff --git a/src/ExtendedXmlSerializer/ReflectionModel/ListConstructorLocator.cs b/src/ExtendedXmlSerializer/ReflectionModel/ListConstructorLocator.cs new file mode 100644 index 000000000..dd0bcb7e2 --- /dev/null +++ b/src/ExtendedXmlSerializer/ReflectionModel/ListConstructorLocator.cs @@ -0,0 +1,35 @@ +using ExtendedXmlSerializer.Core.Sources; +using ExtendedXmlSerializer.Core.Specifications; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace ExtendedXmlSerializer.ReflectionModel +{ + class ListConstructorLocator : IParameterizedSource + { + readonly ISpecification _specification; + readonly IConstructorLocator _previous; + readonly Type _baseType; + + public ListConstructorLocator(ISpecification specification, IConstructorLocator previous) + : this(specification, previous, typeof(List<>)) {} + + public ListConstructorLocator(ISpecification specification, IConstructorLocator previous, + Type baseType) + { + _specification = specification; + _previous = previous; + _baseType = baseType; + } + + public ConstructorInfo Get(TypeInfo parameter) + { + var accounted = _specification.IsSatisfiedBy(parameter) + ? _baseType.MakeGenericType(CollectionItemTypeLocator.Default.Get(parameter)) + : parameter; + var result = _previous.Get(accounted); + return result; + } + } +} \ No newline at end of file diff --git a/src/ExtendedXmlSerializer/ReflectionModel/Support.cs b/src/ExtendedXmlSerializer/ReflectionModel/Support.cs index e364a0222..8ca6494a4 100644 --- a/src/ExtendedXmlSerializer/ReflectionModel/Support.cs +++ b/src/ExtendedXmlSerializer/ReflectionModel/Support.cs @@ -10,8 +10,8 @@ static class Support public static TypeInfo Metadata { get; } = typeof(T).GetTypeInfo(); - public static Func New { get; } = DefaultActivators.Default.New; + public static Func New { get; } = DefaultConstructedActivators.Default.New; - public static Func NewOrSingleton { get; } = Activators.Default.New; + public static Func NewOrSingleton { get; } = new Activators(DefaultConstructedActivators.Default).New; } } \ No newline at end of file diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests.cs new file mode 100644 index 000000000..cce2f09fc --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests.cs @@ -0,0 +1,417 @@ +using ExtendedXmlSerializer.Configuration; +using ExtendedXmlSerializer.Tests.ReportedIssues.Support; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Xunit; +// ReSharper disable All + +namespace ExtendedXmlSerializer.Tests.ReportedIssues +{ + public sealed class Issue485Tests + { + [Fact] + public void Verify() + { + var instance = new[] { 1, 2, 3, 4 }.ToImmutableList(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + serializer.Assert(instance, + @"1234"); + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyHashSet() + { + var instance = new[] { 1, 2, 3, 4 }.ToImmutableHashSet(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + serializer.Assert(instance, + @"1234"); + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifySortedSet() + { + var instance = new[] { 1, 2, 3, 4 }.ToImmutableSortedSet(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + serializer.Assert(instance, + @"1234"); + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyDictionary() + { + var instance = new Dictionary + { + ["Hello"] = "World" + }.ToImmutableDictionary(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + + serializer.Assert(instance, + @""); + + var dictionary = serializer.Cycle(instance); + dictionary.Should().BeEquivalentTo(instance); + + dictionary["Hello"].Should().Be(instance["Hello"]); + } + + [Fact] + public void VerifySortedDictionary() + { + var instance = new Dictionary + { + ["First"] = "Value1", + ["Hello"] = "World", + ["Second"] = "Value2", + ["Last"] = "Value2", + }.ToImmutableSortedDictionary(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + + serializer.Assert(instance, + @""); + + var dictionary = serializer.Cycle(instance); + dictionary.Should().BeEquivalentTo(instance); + + dictionary["Hello"].Should().Be(instance["Hello"]); + } + + [Fact] + public void VerifyWithPropertyAssignments() + { + var instance = new[] { 1, 2, 3, 4 }.ToImmutableList(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + serializer.Assert(instance, + @"1234"); + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyHashSetWithPropertyAssignments() + { + var instance = new[] { 1, 2, 3, 4 }.ToImmutableHashSet(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + serializer.Assert(instance, + @"1234"); + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifySortedSetWithPropertyAssignments() + { + var instance = new[] { 1, 2, 3, 4 }.ToImmutableSortedSet(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + serializer.Assert(instance, + @"1234"); + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyDictionaryWithPropertyAssignments() + { + var instance = new Dictionary + { + ["Hello"] = "World" + }.ToImmutableDictionary(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + + serializer.Assert(instance, + @""); + + var dictionary = serializer.Cycle(instance); + dictionary.Should().BeEquivalentTo(instance); + + dictionary["Hello"].Should().Be(instance["Hello"]); + } + + [Fact] + public void VerifySortedDictionaryWithPropertyAssignments() + { + var instance = new Dictionary + { + ["First"] = "Value1", + ["Hello"] = "World", + ["Second"] = "Value2", + ["Last"] = "Value2", + }.ToImmutableSortedDictionary(); + + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + + serializer.Assert(instance, + @""); + + var dictionary = serializer.Cycle(instance); + dictionary.Should().BeEquivalentTo(instance); + + dictionary["Hello"].Should().Be(instance["Hello"]); + } + + [Fact] + public void VerifyListEmpty() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + var instance = new SubjectList("Hello World!", ImmutableList.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyHashSetEmpty() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + var instance = new SubjectHashSet("Hello World!", ImmutableHashSet.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifySortedSetEmpty() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + var instance = new SubjectSortedSet("Hello World!", ImmutableSortedSet.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyDictionaryEmpty() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + var instance = new SubjectDictionary("Hello World!", ImmutableDictionary.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifySortedDictionaryEmpty() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create() + .ForTesting(); + var instance = new SubjectSortedDictionary("Hello World!", ImmutableSortedDictionary.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyListEmptyWithPropertyAssignments() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + var instance = new SubjectList("Hello World!", ImmutableList.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyHashSetEmptyWithPropertyAssignments() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + var instance = new SubjectHashSet("Hello World!", ImmutableHashSet.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifySortedSetEmptyWithPropertyAssignments() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + var instance = new SubjectSortedSet("Hello World!", ImmutableSortedSet.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifyDictionaryEmptyWithPropertyAssignments() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + var instance = new SubjectDictionary("Hello World!", ImmutableDictionary.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + [Fact] + public void VerifySortedDictionaryEmptyWithPropertyAssignments() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .UseOptimizedNamespaces() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create() + .ForTesting(); + var instance = new SubjectSortedDictionary("Hello World!", ImmutableSortedDictionary.Empty); + + serializer.Cycle(instance).Should().BeEquivalentTo(instance); + } + + class SubjectList + { + public SubjectList(string name, ImmutableList list) + { + Name = name; + List = list; + } + + public string Name { get; } + + public ImmutableList List { get; } + } + + class SubjectHashSet + { + public SubjectHashSet(string name, ImmutableHashSet list) + { + Name = name; + List = list; + } + + public string Name { get; } + + public ImmutableHashSet List { get; } + } + + class SubjectSortedSet + { + public SubjectSortedSet(string name, ImmutableSortedSet list) + { + Name = name; + List = list; + } + + public string Name { get; } + + public ImmutableSortedSet List { get; } + } + + class SubjectDictionary + { + public SubjectDictionary(string name, ImmutableDictionary list) + { + Name = name; + List = list; + } + + public string Name { get; } + + public ImmutableDictionary List { get; } + } + + class SubjectSortedDictionary + { + public SubjectSortedDictionary(string name, ImmutableSortedDictionary list) + { + Name = name; + List = list; + } + + public string Name { get; } + + public ImmutableSortedDictionary List { get; } + } + } +} \ No newline at end of file diff --git a/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests_Extended.cs b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests_Extended.cs new file mode 100644 index 000000000..8c1392c6d --- /dev/null +++ b/test/ExtendedXmlSerializer.Tests.ReportedIssues/Issue485Tests_Extended.cs @@ -0,0 +1,71 @@ +using ExtendedXmlSerializer.Configuration; +using FluentAssertions; +using LightInject; +using System.Xml; +using Xunit; +// ReSharper disable All + +namespace ExtendedXmlSerializer.Tests.ReportedIssues +{ +#nullable enable + public sealed class Issue485Tests_Extended + { + [Fact] + public void Verify() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .EnableImmutableTypes() + .EnableParameterizedContent() + .Create(); + var settings = new XmlWriterSettings { Indent = true }; + + var instance = new U("ciao", null); + var xml = serializer.Serialize(settings, instance); + + var deserialized = serializer.Deserialize(xml); + deserialized.Member.Should().BeNull(); + } + + [Fact] + public void VerifyAlternate() + { + var serializer = new ConfigurationContainer().UseAutoFormatting() + .EnableImmutableTypes() + .EnableParameterizedContentWithPropertyAssignments() + .Create(); + var settings = new XmlWriterSettings { Indent = true }; + + var instance = new U("ciao", null); + var xml = serializer.Serialize(settings, instance); + + var deserialized = serializer.Deserialize(xml); + deserialized.Member.Should().BeNull(); + } + + class U + { + public string Id { get; } + public T? Member { get; } + + public U(string id, T? member) + { + Id = id; + Member = member; + } + } + + class T + { + public string Name { get; } + public ImmutableList List { get; } + + public T(string name, ImmutableList list) + { + Name = name; + List = list; + } + } + + } + #nullable restore +} From a6263e4a580e6053231d30543d14af4cc07ed1f8 Mon Sep 17 00:00:00 2001 From: ExtendedXmlSerializer's GitHub Action Automation Agent Date: Tue, 8 Dec 2020 04:18:09 +0000 Subject: [PATCH 5/5] Generated CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d03fb7d5e..872cfaff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# [ExtendedXmlSerializer v3.5.0](https://github.com/ExtendedXmlSerializer/home/releases/tag/v3.5.0) +> 12/08/2020 04:16:45 UTC +##### ``v3.5.0`` +### ✨ New Features 🚀 +- Added non-generic equivalent for `AddMigration` #484 @Mike-E-angelo +- Added support for `System.Collections.Immutable` Types #486 @Mike-E-angelo +### 🐛 Bug Fixes 🔧 +- Fixed list support in `WithUnknownContent` #487 @Mike-E-angelo +- Applied serializer type check using `WithUnknownContent` #492 @Mike-E-angelo + # [ExtendedXmlSerializer v3.4.3](https://github.com/ExtendedXmlSerializer/home/releases/tag/v3.4.3) > 11/24/2020 06:11:48 UTC ##### ``v3.4.3``